Ruby 4.1.0dev (2026-10-03 revision 9b8b0ae443b38b19bcabebec450fa1ae1658cfbc)
io.c (9b8b0ae443b38b19bcabebec450fa1ae1658cfbc)
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 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
12061 }
12062 else {
12063 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12064 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12065 ecopts = Qnil;
12066 }
12067 }
12068 }
12069 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
12070 fptr->encs.enc = enc;
12071 fptr->encs.enc2 = enc2;
12072 fptr->encs.ecflags = ecflags;
12073 fptr->encs.ecopts = ecopts;
12074 clear_codeconv(fptr);
12075
12076}
12077
12079 rb_io_t *fptr;
12080 VALUE v1;
12081 VALUE v2;
12082 VALUE opt;
12083};
12084
12085static VALUE
12086io_encoding_set_v(VALUE v)
12087{
12088 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
12089 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12090 return Qnil;
12091}
12092
12093static VALUE
12094pipe_pair_close(VALUE rw)
12095{
12096 VALUE *rwp = (VALUE *)rw;
12097 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12098}
12099
12100/*
12101 * call-seq:
12102 * IO.pipe(**opts) -> [read_io, write_io]
12103 * IO.pipe(enc, **opts) -> [read_io, write_io]
12104 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
12105 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
12106 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
12107 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
12108 *
12109 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
12110 * connected to each other.
12111 *
12112 * If argument +enc_string+ is given, it must be a string containing one of:
12113 *
12114 * - The name of the encoding to be used as the external encoding.
12115 * - The colon-separated names of two encodings to be used as the external
12116 * and internal encodings.
12117 *
12118 * If argument +int_enc+ is given, it must be an Encoding object
12119 * or encoding name string that specifies the internal encoding to be used;
12120 * if argument +ext_enc+ is also given, it must be an Encoding object
12121 * or encoding name string that specifies the external encoding to be used.
12122 *
12123 * The string read from +read_io+ is tagged with the external encoding;
12124 * if an internal encoding is also specified, the string is converted
12125 * to, and tagged with, that encoding.
12126 *
12127 * If any encoding is specified,
12128 * optional hash arguments specify the conversion option.
12129 *
12130 * Optional keyword arguments +opts+ specify:
12131 *
12132 * - {Open Options}[rdoc-ref:IO@Open+Options].
12133 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12134 *
12135 * With no block given, returns the two endpoints in an array:
12136 *
12137 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
12138 *
12139 * With a block given, calls the block with the two endpoints;
12140 * closes both endpoints and returns the value of the block:
12141 *
12142 * IO.pipe {|read_io, write_io| p read_io; p write_io }
12143 *
12144 * Output:
12145 *
12146 * #<IO:fd 6>
12147 * #<IO:fd 7>
12148 *
12149 * Not available on all platforms.
12150 *
12151 * In the example below, the two processes close the ends of the pipe
12152 * that they are not using. This is not just a cosmetic nicety. The
12153 * read end of a pipe will not generate an end of file condition if
12154 * there are any writers with the pipe still open. In the case of the
12155 * parent process, the <tt>rd.read</tt> will never return if it
12156 * does not first issue a <tt>wr.close</tt>:
12157 *
12158 * rd, wr = IO.pipe
12159 *
12160 * if fork
12161 * wr.close
12162 * puts "Parent got: <#{rd.read}>"
12163 * rd.close
12164 * Process.wait
12165 * else
12166 * rd.close
12167 * puts 'Sending message to parent'
12168 * wr.write "Hi Dad"
12169 * wr.close
12170 * end
12171 *
12172 * <em>produces:</em>
12173 *
12174 * Sending message to parent
12175 * Parent got: <Hi Dad>
12176 *
12177 */
12178
12179static VALUE
12180rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
12181{
12182 int pipes[2], state;
12183 VALUE r, w, args[3], v1, v2;
12184 VALUE opt;
12185 rb_io_t *fptr, *fptr2;
12186 struct io_encoding_set_args ies_args;
12187 enum rb_io_mode fmode = 0;
12188 VALUE ret;
12189
12190 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
12191 if (rb_pipe(pipes) < 0)
12192 rb_sys_fail(0);
12193
12194 args[0] = klass;
12195 args[1] = INT2NUM(pipes[0]);
12196 args[2] = INT2FIX(O_RDONLY);
12197 r = rb_protect(io_new_instance, (VALUE)args, &state);
12198 if (state) {
12199 close(pipes[0]);
12200 close(pipes[1]);
12201 rb_jump_tag(state);
12202 }
12203 GetOpenFile(r, fptr);
12204
12205 ies_args.fptr = fptr;
12206 ies_args.v1 = v1;
12207 ies_args.v2 = v2;
12208 ies_args.opt = opt;
12209 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
12210 if (state) {
12211 close(pipes[1]);
12212 io_close(r);
12213 rb_jump_tag(state);
12214 }
12215
12216 args[1] = INT2NUM(pipes[1]);
12217 args[2] = INT2FIX(O_WRONLY);
12218 w = rb_protect(io_new_instance, (VALUE)args, &state);
12219 if (state) {
12220 close(pipes[1]);
12221 if (!NIL_P(r)) rb_io_close(r);
12222 rb_jump_tag(state);
12223 }
12224 GetOpenFile(w, fptr2);
12225 rb_io_synchronized(fptr2);
12226
12227 extract_binmode(opt, &fmode);
12228
12229 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
12232 }
12233
12234#if DEFAULT_TEXTMODE
12235 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12236 fptr->mode &= ~FMODE_TEXTMODE;
12237 setmode(fptr->fd, O_BINARY);
12238 }
12239#if RUBY_CRLF_ENVIRONMENT
12242 }
12243#endif
12244#endif
12245 fptr->mode |= fmode;
12246#if DEFAULT_TEXTMODE
12247 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12248 fptr2->mode &= ~FMODE_TEXTMODE;
12249 setmode(fptr2->fd, O_BINARY);
12250 }
12251#endif
12252 fptr2->mode |= fmode;
12253
12254 ret = rb_assoc_new(r, w);
12255 if (rb_block_given_p()) {
12256 VALUE rw[2];
12257 rw[0] = r;
12258 rw[1] = w;
12259 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12260 }
12261 return ret;
12262}
12263
12265 int argc;
12266 VALUE *argv;
12267 VALUE io;
12268};
12269
12270static void
12271open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12272{
12273 VALUE path, v;
12274 VALUE vmode = Qnil, vperm = Qnil;
12275
12276 path = *argv++;
12277 argc--;
12278 FilePathValue(path);
12279 arg->io = 0;
12280 arg->argc = argc;
12281 arg->argv = argv;
12282 if (NIL_P(opt)) {
12283 vmode = INT2NUM(O_RDONLY);
12284 vperm = INT2FIX(0666);
12285 }
12286 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12287 int n;
12288
12289 v = rb_to_array_type(v);
12290 n = RARRAY_LENINT(v);
12291 rb_check_arity(n, 0, 3); /* rb_io_open */
12292 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12293 }
12294 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12295}
12296
12297static VALUE
12298io_s_foreach(VALUE v)
12299{
12300 struct getline_arg *arg = (void *)v;
12301 VALUE str;
12302
12303 if (arg->limit == 0)
12304 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12305 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12306 rb_lastline_set(str);
12307 rb_yield(str);
12308 }
12310 return Qnil;
12311}
12312
12313/*
12314 * call-seq:
12315 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12316 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12317 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12318 * IO.foreach(...) -> an_enumerator
12319 *
12320 * Calls the block with each successive line read from the stream.
12321 *
12322 * The first argument must be a string that is the path to a file.
12323 *
12324 * With only argument +path+ given, parses lines from the file at the given +path+,
12325 * as determined by the default line separator,
12326 * and calls the block with each successive line:
12327 *
12328 * File.foreach('t.txt') {|line| p line }
12329 *
12330 * Output: the same as above.
12331 *
12332 * For both forms, command and path, the remaining arguments are the same.
12333 *
12334 * With argument +sep+ given, parses lines as determined by that line separator
12335 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12336 *
12337 * File.foreach('t.txt', 'li') {|line| p line }
12338 *
12339 * Output:
12340 *
12341 * "First li"
12342 * "ne\nSecond li"
12343 * "ne\n\nThird li"
12344 * "ne\nFourth li"
12345 * "ne\n"
12346 *
12347 * Each paragraph:
12348 *
12349 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12350 *
12351 * Output:
12352 *
12353 * "First line\nSecond line\n\n"
12354 * "Third line\nFourth line\n"
12355 *
12356 * With argument +limit+ given, parses lines as determined by the default
12357 * line separator and the given line-length limit
12358 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12359 *
12360 * File.foreach('t.txt', 7) {|line| p line }
12361 *
12362 * Output:
12363 *
12364 * "First l"
12365 * "ine\n"
12366 * "Second "
12367 * "line\n"
12368 * "\n"
12369 * "Third l"
12370 * "ine\n"
12371 * "Fourth l"
12372 * "line\n"
12373 *
12374 * With arguments +sep+ and +limit+ given,
12375 * combines the two behaviors
12376 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12377 *
12378 * Optional keyword arguments +opts+ specify:
12379 *
12380 * - {Open Options}[rdoc-ref:IO@Open+Options].
12381 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12382 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12383 *
12384 * Returns an Enumerator if no block is given.
12385 *
12386 */
12387
12388static VALUE
12389rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12390{
12391 VALUE opt;
12392 int orig_argc = argc;
12393 struct foreach_arg arg;
12394 struct getline_arg garg;
12395
12396 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12397 RETURN_ENUMERATOR(self, orig_argc, argv);
12398 extract_getline_args(argc-1, argv+1, &garg);
12399 open_key_args(self, argc, argv, opt, &arg);
12400 if (NIL_P(arg.io)) return Qnil;
12401 extract_getline_opts(opt, &garg);
12402 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12403 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12404}
12405
12406static VALUE
12407io_s_readlines(VALUE v)
12408{
12409 struct getline_arg *arg = (void *)v;
12410 return io_readlines(arg, arg->io);
12411}
12412
12413/*
12414 * call-seq:
12415 * IO.readlines(path, sep = $/, **opts) -> array
12416 * IO.readlines(path, limit, **opts) -> array
12417 * IO.readlines(path, sep, limit, **opts) -> array
12418 *
12419 * Returns an array of all lines read from the stream.
12420 *
12421 * The first argument must be a string that is the path to a file.
12422 *
12423 * With only argument +path+ given, parses lines from the file at the given +path+,
12424 * as determined by the default line separator,
12425 * and returns those lines in an array:
12426 *
12427 * IO.readlines('t.txt')
12428 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12429 *
12430 * With argument +sep+ given, parses lines as determined by that line separator
12431 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12432 *
12433 * # Ordinary separator.
12434 * IO.readlines('t.txt', 'li')
12435 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12436 * # Get-paragraphs separator.
12437 * IO.readlines('t.txt', '')
12438 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12439 * # Get-all separator.
12440 * IO.readlines('t.txt', nil)
12441 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12442 *
12443 * With argument +limit+ given, parses lines as determined by the default
12444 * line separator and the given line-length limit
12445 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12446 *
12447 * IO.readlines('t.txt', 7)
12448 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12449 *
12450 * With arguments +sep+ and +limit+ given,
12451 * combines the two behaviors
12452 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12453 *
12454 * Optional keyword arguments +opts+ specify:
12455 *
12456 * - {Open Options}[rdoc-ref:IO@Open+Options].
12457 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12458 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12459 *
12460 */
12461
12462static VALUE
12463rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12464{
12465 VALUE opt;
12466 struct foreach_arg arg;
12467 struct getline_arg garg;
12468
12469 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12470 extract_getline_args(argc-1, argv+1, &garg);
12471 open_key_args(io, argc, argv, opt, &arg);
12472 if (NIL_P(arg.io)) return Qnil;
12473 extract_getline_opts(opt, &garg);
12474 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12475 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12476}
12477
12478static VALUE
12479io_s_read(VALUE v)
12480{
12481 struct foreach_arg *arg = (void *)v;
12482 return io_read(arg->argc, arg->argv, arg->io);
12483}
12484
12485struct seek_arg {
12486 VALUE io;
12487 VALUE offset;
12488 int mode;
12489};
12490
12491static VALUE
12492seek_before_access(VALUE argp)
12493{
12494 struct seek_arg *arg = (struct seek_arg *)argp;
12495 rb_io_binmode(arg->io);
12496 return rb_io_seek(arg->io, arg->offset, arg->mode);
12497}
12498
12499/*
12500 * call-seq:
12501 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12502 *
12503 * Opens the stream, reads and returns some or all of its content,
12504 * and closes the stream; returns +nil+ if no bytes were read.
12505 *
12506 * The first argument must be a string that is the path to a file.
12507 *
12508 * With only argument +path+ given, reads in text mode and returns the entire content
12509 * of the file at the given path:
12510 *
12511 * File.read('t.txt')
12512 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
12513 * File.read('t.ja')
12514 * # => "こんにちは"
12515 * File.read('t.dat')
12516 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12517 *
12518 * On Windows, text mode can terminate reading and leave bytes in the file
12519 * unread when encountering certain special bytes. Consider using
12520 * IO.binread if all bytes in the file should be read.
12521 *
12522 * With argument +length+, returns +length+ bytes if available:
12523 *
12524 * File.read('t.txt', 7)
12525 * # => "First l"
12526 * File.read('t.ja', 7)
12527 * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
12528 * File.read('t.dat', 7)
12529 * # => "\xFE\xFF\x99\x90\x99\x91\x99"
12530 *
12531 * Returns all bytes if +length+ is larger than the files size:
12532 *
12533 * File.read('t.txt', 700)
12534 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12535 * File.read('t.ja', 700)
12536 * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
12537 * File.read('t.dat', 700)
12538 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12539 *
12540 * With arguments +length+ and +offset+, returns +length+ bytes
12541 * if available, beginning at the given +offset+:
12542 *
12543 * File.read('t.txt', 10, 2)
12544 * # => "rst line\r\n"
12545 * File.read('t.ja', 10, 2)
12546 * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
12547 * File.read('t.dat', 10, 2)
12548 * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12549 *
12550 * Returns +nil+ if +offset+ is past the end of the stream:
12551 *
12552 * File.read('t.txt', 10, 200)
12553 * # => nil
12554 *
12555 * Optional keyword arguments +opts+ specify:
12556 *
12557 * - {Open Options}[rdoc-ref:IO@Open+Options].
12558 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12559 *
12560 */
12561
12562static VALUE
12563rb_io_s_read(int argc, VALUE *argv, VALUE io)
12564{
12565 VALUE opt, offset;
12566 long off;
12567 struct foreach_arg arg;
12568
12569 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12570 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12571 rb_raise(rb_eArgError, "negative offset %ld given", off);
12572 }
12573 open_key_args(io, argc, argv, opt, &arg);
12574 if (NIL_P(arg.io)) return Qnil;
12575 if (!NIL_P(offset)) {
12576 struct seek_arg sarg;
12577 int state = 0;
12578 sarg.io = arg.io;
12579 sarg.offset = offset;
12580 sarg.mode = SEEK_SET;
12581 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12582 if (state) {
12583 rb_io_close(arg.io);
12584 rb_jump_tag(state);
12585 }
12586 if (arg.argc == 2) arg.argc = 1;
12587 }
12588 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12589}
12590
12591/*
12592 * call-seq:
12593 * IO.binread(path, length = nil, offset = 0) -> string or nil
12594 *
12595 * Behaves like IO.read, except that the stream is opened in binary mode
12596 * with ASCII-8BIT encoding.
12597 *
12598 */
12599
12600static VALUE
12601rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12602{
12603 VALUE offset;
12604 struct foreach_arg arg;
12605 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12606 enum {
12607 oflags = O_RDONLY
12608#ifdef O_BINARY
12609 |O_BINARY
12610#endif
12611 };
12612 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12613
12614 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12615 FilePathValue(argv[0]);
12616 convconfig.enc = rb_ascii8bit_encoding();
12617 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12618 if (NIL_P(arg.io)) return Qnil;
12619 arg.argv = argv+1;
12620 arg.argc = (argc > 1) ? 1 : 0;
12621 if (!NIL_P(offset)) {
12622 struct seek_arg sarg;
12623 int state = 0;
12624 sarg.io = arg.io;
12625 sarg.offset = offset;
12626 sarg.mode = SEEK_SET;
12627 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12628 if (state) {
12629 rb_io_close(arg.io);
12630 rb_jump_tag(state);
12631 }
12632 }
12633 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12634}
12635
12636static VALUE
12637io_s_write0(VALUE v)
12638{
12639 struct write_arg *arg = (void *)v;
12640 return io_write(arg->io,arg->str,arg->nosync);
12641}
12642
12643static VALUE
12644io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12645{
12646 VALUE string, offset, opt;
12647 struct foreach_arg arg;
12648 struct write_arg warg;
12649
12650 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12651
12652 if (NIL_P(opt)) opt = rb_hash_new();
12653 else opt = rb_hash_dup(opt);
12654
12655
12656 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12657 int mode = O_WRONLY|O_CREAT;
12658#ifdef O_BINARY
12659 if (binary) mode |= O_BINARY;
12660#endif
12661 if (NIL_P(offset)) mode |= O_TRUNC;
12662 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12663 }
12664 open_key_args(klass, argc, argv, opt, &arg);
12665
12666#ifndef O_BINARY
12667 if (binary) rb_io_binmode_m(arg.io);
12668#endif
12669
12670 if (NIL_P(arg.io)) return Qnil;
12671 if (!NIL_P(offset)) {
12672 struct seek_arg sarg;
12673 int state = 0;
12674 sarg.io = arg.io;
12675 sarg.offset = offset;
12676 sarg.mode = SEEK_SET;
12677 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12678 if (state) {
12679 rb_io_close(arg.io);
12680 rb_jump_tag(state);
12681 }
12682 }
12683
12684 warg.io = arg.io;
12685 warg.str = string;
12686 warg.nosync = 0;
12687
12688 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12689}
12690
12691/*
12692 * call-seq:
12693 * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
12694 *
12695 * Opens the stream, writes the given +data+ to it,
12696 * and closes the stream; returns the number of bytes written.
12697 *
12698 * The first argument must be a string that is the path to a file.
12699 *
12700 * With only arguments +path+ and +data+ given,
12701 * writes the given data to the file at that path:
12702 *
12703 * path = 't.tmp'
12704 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
12705 * File.write(path, 'こんにちは') # => 15
12706 * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
12707 *
12708 * When +offset+ is zero (the default), the entire file content is overwritten:
12709 *
12710 * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12711 * File.write(path, 'foo')
12712 * File.read(path) # => "foo"
12713 *
12714 * When +offset+ in within the file content, the file content is partly overwritten,
12715 * beginning at byte +offset+:
12716 *
12717 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12718 * File.write(path, 'LINE', 6)
12719 * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
12720 *
12721 * When the file contains multi-byte characters,
12722 * the effect of writing may disturb some characters:
12723 *
12724 * File.write(path, "こんにちは")
12725 * File.write(path, 'FOO', 3) # Replace one 3-byte character.
12726 * File.read(path) # => "こFOOにちは"
12727 * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
12728 * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
12729 *
12730 * If +offset+ is outside the file content,
12731 * the file is padded with null characters <tt>"\u0000"</tt>:
12732 *
12733 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12734 * File.write(path, 'FOO', 55)
12735 * File.read(path)
12736 * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
12737 *
12738 * Optional keyword arguments +opts+ specify:
12739 *
12740 * - {Open Options}[rdoc-ref:IO@Open+Options].
12741 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12742 *
12743 */
12744
12745static VALUE
12746rb_io_s_write(int argc, VALUE *argv, VALUE io)
12747{
12748 return io_s_write(argc, argv, io, 0);
12749}
12750
12751/*
12752 * call-seq:
12753 * IO.binwrite(path, string, offset = 0, **opts) -> integer
12754 *
12755 * Behaves like IO.write, except that the stream is opened in binary mode
12756 * with ASCII-8BIT encoding.
12757 *
12758 */
12759
12760static VALUE
12761rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12762{
12763 return io_s_write(argc, argv, io, 1);
12764}
12765
12767 VALUE src;
12768 VALUE dst;
12769 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12770 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12771
12772 rb_io_t *src_fptr;
12773 rb_io_t *dst_fptr;
12774 unsigned close_src : 1;
12775 unsigned close_dst : 1;
12776 int error_no;
12777 rb_off_t total;
12778 const char *syserr;
12779 const char *notimp;
12780 VALUE th;
12781 struct stat src_stat;
12782 struct stat dst_stat;
12783#ifdef HAVE_FCOPYFILE
12784 copyfile_state_t copyfile_state;
12785#endif
12786};
12787
12788static void *
12789exec_interrupts(void *arg)
12790{
12791 VALUE th = (VALUE)arg;
12792 rb_thread_execute_interrupts(th);
12793 return NULL;
12794}
12795
12796/*
12797 * returns TRUE if the preceding system call was interrupted
12798 * so we can continue. If the thread was interrupted, we
12799 * reacquire the GVL to execute interrupts before continuing.
12800 */
12801static int
12802maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12803{
12804 switch (errno) {
12805 case EINTR:
12806#if defined(ERESTART)
12807 case ERESTART:
12808#endif
12809 if (rb_thread_interrupted(stp->th)) {
12810 if (has_gvl)
12811 rb_thread_execute_interrupts(stp->th);
12812 else
12813 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12814 }
12815 return TRUE;
12816 }
12817 return FALSE;
12818}
12819
12821 VALUE scheduler;
12822
12823 rb_io_t *fptr;
12824 short events;
12825
12826 VALUE result;
12827};
12828
12829static void *
12830fiber_scheduler_wait_for(void * _arguments)
12831{
12832 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12833
12834 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12835
12836 return NULL;
12837}
12838
12839#if USE_POLL
12840# define IOWAIT_SYSCALL "poll"
12841STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12842STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12843static int
12844nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12845{
12847 if (scheduler != Qnil) {
12848 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12849 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12850 return RTEST(args.result);
12851 }
12852
12853 int fd = fptr->fd;
12854 if (fd == -1) return 0;
12855
12856 struct pollfd fds;
12857
12858 fds.fd = fd;
12859 fds.events = events;
12860
12861 int timeout_milliseconds = -1;
12862
12863 if (timeout) {
12864 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12865 }
12866
12867 return poll(&fds, 1, timeout_milliseconds);
12868}
12869#else /* !USE_POLL */
12870# define IOWAIT_SYSCALL "select"
12871static int
12872nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12873{
12875 if (scheduler != Qnil) {
12876 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12877 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12878 return RTEST(args.result);
12879 }
12880
12881 int fd = fptr->fd;
12882
12883 if (fd == -1) {
12884 errno = EBADF;
12885 return -1;
12886 }
12887
12888 rb_fdset_t fds;
12889 int ret;
12890
12891 rb_fd_init(&fds);
12892 rb_fd_set(fd, &fds);
12893
12894 switch (events) {
12895 case RB_WAITFD_IN:
12896 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12897 break;
12898 case RB_WAITFD_OUT:
12899 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12900 break;
12901 default:
12902 VM_UNREACHABLE(nogvl_wait_for);
12903 }
12904
12905 rb_fd_term(&fds);
12906
12907 // On timeout, this returns 0.
12908 return ret;
12909}
12910#endif /* !USE_POLL */
12911
12912static int
12913maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12914{
12915 int ret;
12916
12917 do {
12918 if (has_gvl) {
12920 }
12921 else {
12922 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12923 }
12924 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12925
12926 if (ret < 0) {
12927 stp->syserr = IOWAIT_SYSCALL;
12928 stp->error_no = errno;
12929 return ret;
12930 }
12931 return 0;
12932}
12933
12934static int
12935nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12936{
12937 int ret;
12938
12939 do {
12940 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12941 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12942
12943 if (ret < 0) {
12944 stp->syserr = IOWAIT_SYSCALL;
12945 stp->error_no = errno;
12946 return ret;
12947 }
12948 return 0;
12949}
12950
12951#ifdef USE_COPY_FILE_RANGE
12952
12953static ssize_t
12954simple_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)
12955{
12956#ifdef HAVE_COPY_FILE_RANGE
12957 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12958#else
12959 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12960#endif
12961}
12962
12963static int
12964nogvl_copy_file_range(struct copy_stream_struct *stp)
12965{
12966 ssize_t ss;
12967 rb_off_t src_size;
12968 rb_off_t copy_length, src_offset, *src_offset_ptr;
12969
12970 if (!S_ISREG(stp->src_stat.st_mode))
12971 return 0;
12972
12973 src_size = stp->src_stat.st_size;
12974 src_offset = stp->src_offset;
12975 if (src_offset >= (rb_off_t)0) {
12976 src_offset_ptr = &src_offset;
12977 }
12978 else {
12979 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12980 }
12981
12982 copy_length = stp->copy_length;
12983 if (copy_length < (rb_off_t)0) {
12984 if (src_offset < (rb_off_t)0) {
12985 rb_off_t current_offset;
12986 errno = 0;
12987 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12988 if (current_offset < (rb_off_t)0 && errno) {
12989 stp->syserr = "lseek";
12990 stp->error_no = errno;
12991 return (int)current_offset;
12992 }
12993 copy_length = src_size - current_offset;
12994 }
12995 else {
12996 copy_length = src_size - src_offset;
12997 }
12998 }
12999
13000 retry_copy_file_range:
13001# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13002 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13003 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13004# else
13005 ss = (ssize_t)copy_length;
13006# endif
13007 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
13008 if (0 < ss) {
13009 stp->total += ss;
13010 copy_length -= ss;
13011 if (0 < copy_length) {
13012 goto retry_copy_file_range;
13013 }
13014 }
13015 if (ss < 0) {
13016 if (maygvl_copy_stream_continue_p(0, stp)) {
13017 goto retry_copy_file_range;
13018 }
13019 switch (errno) {
13020 case EINVAL:
13021 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
13022 docker container) */
13023#ifdef ENOSYS
13024 case ENOSYS:
13025#endif
13026#ifdef EXDEV
13027 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
13028#endif
13029 return 0;
13030 case EAGAIN:
13031#if EWOULDBLOCK != EAGAIN
13032 case EWOULDBLOCK:
13033#endif
13034 {
13035 int ret = nogvl_copy_stream_wait_write(stp);
13036 if (ret < 0) return ret;
13037 }
13038 goto retry_copy_file_range;
13039 case EBADF:
13040 {
13041 int e = errno;
13042 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
13043
13044 if (flags != -1 && flags & O_APPEND) {
13045 return 0;
13046 }
13047 errno = e;
13048 }
13049 }
13050 stp->syserr = "copy_file_range";
13051 stp->error_no = errno;
13052 return (int)ss;
13053 }
13054 return 1;
13055}
13056#endif
13057
13058#ifdef HAVE_FCOPYFILE
13059static int
13060nogvl_fcopyfile(struct copy_stream_struct *stp)
13061{
13062 rb_off_t cur, ss = 0;
13063 const rb_off_t src_offset = stp->src_offset;
13064 int ret;
13065
13066 if (stp->copy_length >= (rb_off_t)0) {
13067 /* copy_length can't be specified in fcopyfile(3) */
13068 return 0;
13069 }
13070
13071 if (!S_ISREG(stp->src_stat.st_mode))
13072 return 0;
13073
13074 if (!S_ISREG(stp->dst_stat.st_mode))
13075 return 0;
13076 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
13077 return 0;
13078 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
13079 /* fcopyfile(3) appends src IO to dst IO and then truncates
13080 * dst IO to src IO's original size. */
13081 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
13082 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
13083 if (end > (rb_off_t)0) return 0;
13084 }
13085
13086 if (src_offset > (rb_off_t)0) {
13087 rb_off_t r;
13088
13089 /* get current offset */
13090 errno = 0;
13091 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13092 if (cur < (rb_off_t)0 && errno) {
13093 stp->error_no = errno;
13094 return 1;
13095 }
13096
13097 errno = 0;
13098 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13099 if (r < (rb_off_t)0 && errno) {
13100 stp->error_no = errno;
13101 return 1;
13102 }
13103 }
13104
13105 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
13106 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
13107 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
13108
13109 if (ret == 0) { /* success */
13110 stp->total = ss;
13111 if (src_offset > (rb_off_t)0) {
13112 rb_off_t r;
13113 errno = 0;
13114 /* reset offset */
13115 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
13116 if (r < (rb_off_t)0 && errno) {
13117 stp->error_no = errno;
13118 return 1;
13119 }
13120 }
13121 }
13122 else {
13123 switch (errno) {
13124 case ENOTSUP:
13125 case EPERM:
13126 case EINVAL:
13127 return 0;
13128 }
13129 stp->syserr = "fcopyfile";
13130 stp->error_no = errno;
13131 return (int)ret;
13132 }
13133 return 1;
13134}
13135#endif
13136
13137#ifdef HAVE_SENDFILE
13138
13139# ifdef __linux__
13140# define USE_SENDFILE
13141
13142# ifdef HAVE_SYS_SENDFILE_H
13143# include <sys/sendfile.h>
13144# endif
13145
13146static ssize_t
13147simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13148{
13149 return sendfile(out_fd, in_fd, offset, (size_t)count);
13150}
13151
13152# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
13153/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
13154 * without cpuset -l 0.
13155 */
13156# define USE_SENDFILE
13157
13158static ssize_t
13159simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13160{
13161 int r;
13162 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13163 rb_off_t sbytes;
13164# ifdef __APPLE__
13165 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13166 sbytes = count;
13167# else
13168 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
13169# endif
13170 if (r != 0 && sbytes == 0) return r;
13171 if (offset) {
13172 *offset += sbytes;
13173 }
13174 else {
13175 lseek(in_fd, sbytes, SEEK_CUR);
13176 }
13177 return (ssize_t)sbytes;
13178}
13179
13180# endif
13181
13182#endif
13183
13184#ifdef USE_SENDFILE
13185static int
13186nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
13187{
13188 ssize_t ss;
13189 rb_off_t src_size;
13190 rb_off_t copy_length;
13191 rb_off_t src_offset;
13192 int use_pread;
13193
13194 if (!S_ISREG(stp->src_stat.st_mode))
13195 return 0;
13196
13197 src_size = stp->src_stat.st_size;
13198#ifndef __linux__
13199 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13200 return 0;
13201#endif
13202
13203 src_offset = stp->src_offset;
13204 use_pread = src_offset >= (rb_off_t)0;
13205
13206 copy_length = stp->copy_length;
13207 if (copy_length < (rb_off_t)0) {
13208 if (use_pread)
13209 copy_length = src_size - src_offset;
13210 else {
13211 rb_off_t cur;
13212 errno = 0;
13213 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13214 if (cur < (rb_off_t)0 && errno) {
13215 stp->syserr = "lseek";
13216 stp->error_no = errno;
13217 return (int)cur;
13218 }
13219 copy_length = src_size - cur;
13220 }
13221 }
13222
13223 retry_sendfile:
13224# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13225 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13226 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13227# else
13228 ss = (ssize_t)copy_length;
13229# endif
13230 if (use_pread) {
13231 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
13232 }
13233 else {
13234 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
13235 }
13236 if (0 < ss) {
13237 stp->total += ss;
13238 copy_length -= ss;
13239 if (0 < copy_length) {
13240 goto retry_sendfile;
13241 }
13242 }
13243 if (ss < 0) {
13244 if (maygvl_copy_stream_continue_p(0, stp))
13245 goto retry_sendfile;
13246 switch (errno) {
13247 case EINVAL:
13248#ifdef ENOSYS
13249 case ENOSYS:
13250#endif
13251#ifdef EOPNOTSUP
13252 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
13253 see also: [Feature #16965] */
13254 case EOPNOTSUP:
13255#endif
13256 return 0;
13257 case EAGAIN:
13258#if EWOULDBLOCK != EAGAIN
13259 case EWOULDBLOCK:
13260#endif
13261 {
13262 int ret;
13263#ifndef __linux__
13264 /*
13265 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13266 * select() reports regular files to always be "ready", so
13267 * there is no need to select() on it.
13268 * Other OSes may have the same limitation for sendfile() which
13269 * allow us to bypass maygvl_copy_stream_wait_read()...
13270 */
13271 ret = maygvl_copy_stream_wait_read(0, stp);
13272 if (ret < 0) return ret;
13273#endif
13274 ret = nogvl_copy_stream_wait_write(stp);
13275 if (ret < 0) return ret;
13276 }
13277 goto retry_sendfile;
13278 }
13279 stp->syserr = "sendfile";
13280 stp->error_no = errno;
13281 return (int)ss;
13282 }
13283 return 1;
13284}
13285#endif
13286
13287static ssize_t
13288maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13289{
13290 if (has_gvl)
13291 return rb_io_read_memory(fptr, buf, count);
13292 else
13293 return read(fptr->fd, buf, count);
13294}
13295
13296static ssize_t
13297maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13298{
13299 ssize_t ss;
13300 retry_read:
13301 if (offset < (rb_off_t)0) {
13302 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13303 }
13304 else {
13305 ss = pread(stp->src_fptr->fd, buf, len, offset);
13306 }
13307 if (ss == 0) {
13308 return 0;
13309 }
13310 if (ss < 0) {
13311 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13312 goto retry_read;
13313 switch (errno) {
13314 case EAGAIN:
13315#if EWOULDBLOCK != EAGAIN
13316 case EWOULDBLOCK:
13317#endif
13318 {
13319 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13320 if (ret < 0) return ret;
13321 }
13322 goto retry_read;
13323#ifdef ENOSYS
13324 case ENOSYS:
13325 stp->notimp = "pread";
13326 return ss;
13327#endif
13328 }
13329 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13330 stp->error_no = errno;
13331 }
13332 return ss;
13333}
13334
13335static int
13336nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13337{
13338 ssize_t ss;
13339 int off = 0;
13340 while (len) {
13341 ss = write(stp->dst_fptr->fd, buf+off, len);
13342 if (ss < 0) {
13343 if (maygvl_copy_stream_continue_p(0, stp))
13344 continue;
13345 if (io_again_p(errno)) {
13346 int ret = nogvl_copy_stream_wait_write(stp);
13347 if (ret < 0) return ret;
13348 continue;
13349 }
13350 stp->syserr = "write";
13351 stp->error_no = errno;
13352 return (int)ss;
13353 }
13354 off += (int)ss;
13355 len -= (int)ss;
13356 stp->total += ss;
13357 }
13358 return 0;
13359}
13360
13361static void
13362nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13363{
13364 char buf[1024*16];
13365 size_t len;
13366 ssize_t ss;
13367 int ret;
13368 rb_off_t copy_length;
13369 rb_off_t src_offset;
13370 int use_eof;
13371 int use_pread;
13372
13373 copy_length = stp->copy_length;
13374 use_eof = copy_length < (rb_off_t)0;
13375 src_offset = stp->src_offset;
13376 use_pread = src_offset >= (rb_off_t)0;
13377
13378 if (use_pread && stp->close_src) {
13379 rb_off_t r;
13380 errno = 0;
13381 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13382 if (r < (rb_off_t)0 && errno) {
13383 stp->syserr = "lseek";
13384 stp->error_no = errno;
13385 return;
13386 }
13387 src_offset = (rb_off_t)-1;
13388 use_pread = 0;
13389 }
13390
13391 while (use_eof || 0 < copy_length) {
13392 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13393 len = (size_t)copy_length;
13394 }
13395 else {
13396 len = sizeof(buf);
13397 }
13398 if (use_pread) {
13399 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13400 if (0 < ss)
13401 src_offset += ss;
13402 }
13403 else {
13404 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13405 }
13406 if (ss <= 0) /* EOF or error */
13407 return;
13408
13409 ret = nogvl_copy_stream_write(stp, buf, ss);
13410 if (ret < 0)
13411 return;
13412
13413 if (!use_eof)
13414 copy_length -= ss;
13415 }
13416}
13417
13418static void *
13419nogvl_copy_stream_func(void *arg)
13420{
13421 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13422#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13423 int ret;
13424#endif
13425
13426#ifdef USE_COPY_FILE_RANGE
13427 ret = nogvl_copy_file_range(stp);
13428 if (ret != 0)
13429 goto finish; /* error or success */
13430#endif
13431
13432#ifdef HAVE_FCOPYFILE
13433 ret = nogvl_fcopyfile(stp);
13434 if (ret != 0)
13435 goto finish; /* error or success */
13436#endif
13437
13438#ifdef USE_SENDFILE
13439 ret = nogvl_copy_stream_sendfile(stp);
13440 if (ret != 0)
13441 goto finish; /* error or success */
13442#endif
13443
13444 nogvl_copy_stream_read_write(stp);
13445
13446#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13447 finish:
13448#endif
13449 return 0;
13450}
13451
13452static VALUE
13453copy_stream_fallback_body(VALUE arg)
13454{
13455 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13456 const int buflen = 16*1024;
13457 VALUE n;
13458 VALUE buf = rb_str_buf_new(buflen);
13459 rb_off_t rest = stp->copy_length;
13460 rb_off_t off = stp->src_offset;
13461 ID read_method = id_readpartial;
13462
13463 if (!stp->src_fptr) {
13464 if (!rb_respond_to(stp->src, read_method)) {
13465 read_method = id_read;
13466 }
13467 }
13468
13469 while (1) {
13470 long numwrote;
13471 long l;
13472 rb_str_make_independent(buf);
13473 if (stp->copy_length < (rb_off_t)0) {
13474 l = buflen;
13475 }
13476 else {
13477 if (rest == 0) {
13478 rb_str_resize(buf, 0);
13479 break;
13480 }
13481 l = buflen < rest ? buflen : (long)rest;
13482 }
13483 if (!stp->src_fptr) {
13484 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13485
13486 if (read_method == id_read && NIL_P(rc))
13487 break;
13488 }
13489 else {
13490 ssize_t ss;
13491 rb_str_resize(buf, buflen);
13492 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13493 rb_str_resize(buf, ss > 0 ? ss : 0);
13494 if (ss < 0)
13495 return Qnil;
13496 if (ss == 0)
13497 rb_eof_error();
13498 if (off >= (rb_off_t)0)
13499 off += ss;
13500 }
13501 n = rb_io_write(stp->dst, buf);
13502 numwrote = NUM2LONG(n);
13503 stp->total += numwrote;
13504 rest -= numwrote;
13505 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13506 break;
13507 }
13508 }
13509
13510 return Qnil;
13511}
13512
13513static VALUE
13514copy_stream_fallback(struct copy_stream_struct *stp)
13515{
13516 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13517 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13518 }
13519 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13520 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13521 rb_eEOFError, (VALUE)0);
13522 return Qnil;
13523}
13524
13525static VALUE
13526copy_stream_body(VALUE arg)
13527{
13528 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13529 VALUE src_io = stp->src, dst_io = stp->dst;
13530 const int common_oflags = 0
13531#ifdef O_NOCTTY
13532 | O_NOCTTY
13533#endif
13534 ;
13535
13536 stp->th = rb_thread_current();
13537
13538 stp->total = 0;
13539
13540 if (src_io == argf ||
13541 !(RB_TYPE_P(src_io, T_FILE) ||
13542 RB_TYPE_P(src_io, T_STRING) ||
13543 rb_respond_to(src_io, rb_intern("to_path")))) {
13544 stp->src_fptr = NULL;
13545 }
13546 else {
13547 int stat_ret;
13548 VALUE tmp_io = rb_io_check_io(src_io);
13549 if (!NIL_P(tmp_io)) {
13550 src_io = tmp_io;
13551 }
13552 else if (!RB_TYPE_P(src_io, T_FILE)) {
13553 VALUE args[2];
13554 FilePathValue(src_io);
13555 args[0] = src_io;
13556 args[1] = INT2NUM(O_RDONLY|common_oflags);
13557 src_io = rb_class_new_instance(2, args, rb_cFile);
13558 stp->src = src_io;
13559 stp->close_src = 1;
13560 }
13561 RB_IO_POINTER(src_io, stp->src_fptr);
13562 rb_io_check_byte_readable(stp->src_fptr);
13563
13564 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13565 if (stat_ret < 0) {
13566 stp->syserr = "fstat";
13567 stp->error_no = errno;
13568 return Qnil;
13569 }
13570 }
13571
13572 if (dst_io == argf ||
13573 !(RB_TYPE_P(dst_io, T_FILE) ||
13574 RB_TYPE_P(dst_io, T_STRING) ||
13575 rb_respond_to(dst_io, rb_intern("to_path")))) {
13576 stp->dst_fptr = NULL;
13577 }
13578 else {
13579 int stat_ret;
13580 VALUE tmp_io = rb_io_check_io(dst_io);
13581 if (!NIL_P(tmp_io)) {
13582 dst_io = GetWriteIO(tmp_io);
13583 }
13584 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13585 VALUE args[3];
13586 FilePathValue(dst_io);
13587 args[0] = dst_io;
13588 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13589 args[2] = INT2FIX(0666);
13590 dst_io = rb_class_new_instance(3, args, rb_cFile);
13591 stp->dst = dst_io;
13592 stp->close_dst = 1;
13593 }
13594 else {
13595 dst_io = GetWriteIO(dst_io);
13596 stp->dst = dst_io;
13597 }
13598 RB_IO_POINTER(dst_io, stp->dst_fptr);
13599 rb_io_check_writable(stp->dst_fptr);
13600
13601 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13602 if (stat_ret < 0) {
13603 stp->syserr = "fstat";
13604 stp->error_no = errno;
13605 return Qnil;
13606 }
13607 }
13608
13609#ifdef O_BINARY
13610 if (stp->src_fptr)
13611 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13612#endif
13613 if (stp->dst_fptr)
13614 io_ascii8bit_binmode(stp->dst_fptr);
13615
13616 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13617 size_t len = stp->src_fptr->rbuf.len;
13618 VALUE str;
13619 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13620 len = (size_t)stp->copy_length;
13621 }
13622 str = rb_str_buf_new(len);
13623 rb_str_resize(str,len);
13624 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13625 if (stp->dst_fptr) { /* IO or filename */
13626 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13627 rb_sys_fail_on_write(stp->dst_fptr);
13628 }
13629 else /* others such as StringIO */
13630 rb_io_write(dst_io, str);
13631 rb_str_resize(str, 0);
13632 stp->total += len;
13633 if (stp->copy_length >= (rb_off_t)0)
13634 stp->copy_length -= len;
13635 }
13636
13637 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13638 rb_raise(rb_eIOError, "flush failed");
13639 }
13640
13641 if (stp->copy_length == 0)
13642 return Qnil;
13643
13644 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13645 return copy_stream_fallback(stp);
13646 }
13647
13648 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13649 return Qnil;
13650}
13651
13652static VALUE
13653copy_stream_finalize(VALUE arg)
13654{
13655 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13656
13657#ifdef HAVE_FCOPYFILE
13658 if (stp->copyfile_state) {
13659 copyfile_state_free(stp->copyfile_state);
13660 }
13661#endif
13662
13663 if (stp->close_src) {
13664 rb_io_close_m(stp->src);
13665 }
13666 if (stp->close_dst) {
13667 rb_io_close_m(stp->dst);
13668 }
13669 if (stp->syserr) {
13670 rb_syserr_fail(stp->error_no, stp->syserr);
13671 }
13672 if (stp->notimp) {
13673 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13674 }
13675 return Qnil;
13676}
13677
13678/*
13679 * call-seq:
13680 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13681 *
13682 * Copies from the given +src+ to the given +dst+,
13683 * returning the number of bytes copied.
13684 *
13685 * - The given +src+ must be one of the following:
13686 *
13687 * - The path to a readable file, from which source data is to be read.
13688 * - An \IO-like object, opened for reading and capable of responding
13689 * to method +:readpartial+ or method +:read+.
13690 *
13691 * - The given +dst+ must be one of the following:
13692 *
13693 * - The path to a writable file, to which data is to be written.
13694 * - An \IO-like object, opened for writing and capable of responding
13695 * to method +:write+.
13696 *
13697 * The examples here use file <tt>t.txt</tt> as source:
13698 *
13699 * File.read('t.txt')
13700 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13701 * File.read('t.txt').size # => 47
13702 *
13703 * If only arguments +src+ and +dst+ are given,
13704 * the entire source stream is copied:
13705 *
13706 * # Paths.
13707 * IO.copy_stream('t.txt', 't.tmp') # => 47
13708 *
13709 * # IOs (recall that a File is also an IO).
13710 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13711 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13712 * IO.copy_stream(src_io, dst_io) # => 47
13713 * src_io.close
13714 * dst_io.close
13715 *
13716 * With argument +src_length+ a non-negative integer,
13717 * no more than that many bytes are copied:
13718 *
13719 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13720 * File.read('t.tmp') # => "First line"
13721 *
13722 * With argument +src_offset+ also given,
13723 * the source stream is read beginning at that offset:
13724 *
13725 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13726 * IO.read('t.tmp') # => "Second line"
13727 *
13728 */
13729static VALUE
13730rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13731{
13732 VALUE src, dst, length, src_offset;
13733 struct copy_stream_struct st;
13734
13735 MEMZERO(&st, struct copy_stream_struct, 1);
13736
13737 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13738
13739 st.src = src;
13740 st.dst = dst;
13741
13742 st.src_fptr = NULL;
13743 st.dst_fptr = NULL;
13744
13745 if (NIL_P(length))
13746 st.copy_length = (rb_off_t)-1;
13747 else
13748 st.copy_length = NUM2OFFT(length);
13749
13750 if (NIL_P(src_offset))
13751 st.src_offset = (rb_off_t)-1;
13752 else
13753 st.src_offset = NUM2OFFT(src_offset);
13754
13755 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13756
13757 return OFFT2NUM(st.total);
13758}
13759
13760/*
13761 * call-seq:
13762 * external_encoding -> encoding or nil
13763 *
13764 * Returns the Encoding object that represents the encoding of the stream,
13765 * or +nil+ if the stream is in write mode and no encoding is specified.
13766 *
13767 * See {Encodings}[rdoc-ref:File@Encodings].
13768 *
13769 */
13770
13771static VALUE
13772rb_io_external_encoding(VALUE io)
13773{
13774 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13775
13776 if (fptr->encs.enc2) {
13777 return rb_enc_from_encoding(fptr->encs.enc2);
13778 }
13779 if (fptr->mode & FMODE_WRITABLE) {
13780 if (fptr->encs.enc)
13781 return rb_enc_from_encoding(fptr->encs.enc);
13782 return Qnil;
13783 }
13784 return rb_enc_from_encoding(io_read_encoding(fptr));
13785}
13786
13787/*
13788 * call-seq:
13789 * internal_encoding -> encoding or nil
13790 *
13791 * Returns the Encoding object that represents the encoding of the internal string,
13792 * if conversion is specified,
13793 * or +nil+ otherwise.
13794 *
13795 * See {Encodings}[rdoc-ref:File@Encodings].
13796 *
13797 */
13798
13799static VALUE
13800rb_io_internal_encoding(VALUE io)
13801{
13802 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13803
13804 if (!fptr->encs.enc2) return Qnil;
13805 return rb_enc_from_encoding(io_read_encoding(fptr));
13806}
13807
13808/*
13809 * call-seq:
13810 * set_encoding(ext_enc) -> self
13811 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13812 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13813 *
13814 * See {Encodings}[rdoc-ref:File@Encodings].
13815 *
13816 * Argument +ext_enc+, if given, must be an Encoding object
13817 * or a String with the encoding name;
13818 * it is assigned as the encoding for the stream.
13819 *
13820 * Argument +int_enc+, if given, must be an Encoding object
13821 * or a String with the encoding name;
13822 * it is assigned as the encoding for the internal string.
13823 *
13824 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13825 * containing two colon-separated encoding names;
13826 * corresponding Encoding objects are assigned as the external
13827 * and internal encodings for the stream.
13828 *
13829 * If the external encoding of a string is binary/ASCII-8BIT,
13830 * the internal encoding of the string is set to nil, since no
13831 * transcoding is needed.
13832 *
13833 * Optional keyword arguments +enc_opts+ specify
13834 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13835 *
13836 */
13837
13838static VALUE
13839rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13840{
13841 rb_io_t *fptr;
13842 VALUE v1, v2, opt;
13843
13844 if (!RB_TYPE_P(io, T_FILE)) {
13845 return forward(io, id_set_encoding, argc, argv);
13846 }
13847
13848 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13849 GetOpenFile(io, fptr);
13850 io_encoding_set(fptr, v1, v2, opt);
13851 return io;
13852}
13853
13854void
13855rb_stdio_set_default_encoding(void)
13856{
13857 VALUE val = Qnil;
13858
13859#ifdef _WIN32
13860 if (isatty(fileno(stdin))) {
13861 rb_encoding *external = rb_locale_encoding();
13862 rb_encoding *internal = rb_default_internal_encoding();
13863 if (!internal) internal = rb_default_external_encoding();
13864 io_encoding_set(RFILE(rb_stdin)->fptr,
13865 rb_enc_from_encoding(external),
13866 rb_enc_from_encoding(internal),
13867 Qnil);
13868 }
13869 else
13870#endif
13871 rb_io_set_encoding(1, &val, rb_stdin);
13872 rb_io_set_encoding(1, &val, rb_stdout);
13873 rb_io_set_encoding(1, &val, rb_stderr);
13874}
13875
13876static inline int
13877global_argf_p(VALUE arg)
13878{
13879 return arg == argf;
13880}
13881
13882typedef VALUE (*argf_encoding_func)(VALUE io);
13883
13884static VALUE
13885argf_encoding(VALUE argf, argf_encoding_func func)
13886{
13887 if (!RTEST(ARGF.current_file)) {
13888 return rb_enc_default_external();
13889 }
13890 return func(rb_io_check_io(ARGF.current_file));
13891}
13892
13893/*
13894 * call-seq:
13895 * ARGF.external_encoding -> encoding
13896 *
13897 * Returns the external encoding for files read from ARGF as an Encoding
13898 * object. The external encoding is the encoding of the text as stored in a
13899 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13900 * represent this text within Ruby.
13901 *
13902 * To set the external encoding use ARGF.set_encoding.
13903 *
13904 * For example:
13905 *
13906 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13907 *
13908 */
13909static VALUE
13910argf_external_encoding(VALUE argf)
13911{
13912 return argf_encoding(argf, rb_io_external_encoding);
13913}
13914
13915/*
13916 * call-seq:
13917 * ARGF.internal_encoding -> encoding
13918 *
13919 * Returns the internal encoding for strings read from ARGF as an
13920 * Encoding object.
13921 *
13922 * If ARGF.set_encoding has been called with two encoding names, the second
13923 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13924 * value is returned. Failing that, if a default external encoding was
13925 * specified on the command-line, that value is used. If the encoding is
13926 * unknown, +nil+ is returned.
13927 */
13928static VALUE
13929argf_internal_encoding(VALUE argf)
13930{
13931 return argf_encoding(argf, rb_io_internal_encoding);
13932}
13933
13934/*
13935 * call-seq:
13936 * ARGF.set_encoding(ext_enc) -> ARGF
13937 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13938 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13939 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13940 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13941 *
13942 * If single argument is specified, strings read from ARGF are tagged with
13943 * the encoding specified.
13944 *
13945 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13946 * the read string is converted from the first encoding (external encoding)
13947 * to the second encoding (internal encoding), then tagged with the second
13948 * encoding.
13949 *
13950 * If two arguments are specified, they must be encoding objects or encoding
13951 * names. Again, the first specifies the external encoding; the second
13952 * specifies the internal encoding.
13953 *
13954 * If the external encoding and the internal encoding are specified, the
13955 * optional Hash argument can be used to adjust the conversion process. The
13956 * structure of this hash is explained in the String#encode documentation.
13957 *
13958 * For example:
13959 *
13960 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13961 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13962 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13963 * # to UTF-8.
13964 */
13965static VALUE
13966argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13967{
13968 rb_io_t *fptr;
13969
13970 if (!next_argv()) {
13971 rb_raise(rb_eArgError, "no stream to set encoding");
13972 }
13973 rb_io_set_encoding(argc, argv, ARGF.current_file);
13974 GetOpenFile(ARGF.current_file, fptr);
13975 ARGF.encs = fptr->encs;
13976 RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
13977 return argf;
13978}
13979
13980/*
13981 * call-seq:
13982 * ARGF.tell -> Integer
13983 * ARGF.pos -> Integer
13984 *
13985 * Returns the current offset (in bytes) of the current file in ARGF.
13986 *
13987 * ARGF.pos #=> 0
13988 * ARGF.gets #=> "This is line one\n"
13989 * ARGF.pos #=> 17
13990 *
13991 */
13992static VALUE
13993argf_tell(VALUE argf)
13994{
13995 if (!next_argv()) {
13996 rb_raise(rb_eArgError, "no stream to tell");
13997 }
13998 ARGF_FORWARD(0, 0);
13999 return rb_io_tell(ARGF.current_file);
14000}
14001
14002/*
14003 * call-seq:
14004 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
14005 *
14006 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
14007 * the value of _whence_. See IO#seek for further details.
14008 */
14009static VALUE
14010argf_seek_m(int argc, VALUE *argv, VALUE argf)
14011{
14012 if (!next_argv()) {
14013 rb_raise(rb_eArgError, "no stream to seek");
14014 }
14015 ARGF_FORWARD(argc, argv);
14016 return rb_io_seek_m(argc, argv, ARGF.current_file);
14017}
14018
14019/*
14020 * call-seq:
14021 * ARGF.pos = position -> Integer
14022 *
14023 * Seeks to the position given by _position_ (in bytes) in ARGF.
14024 *
14025 * For example:
14026 *
14027 * ARGF.pos = 17
14028 * ARGF.gets #=> "This is line two\n"
14029 */
14030static VALUE
14031argf_set_pos(VALUE argf, VALUE offset)
14032{
14033 if (!next_argv()) {
14034 rb_raise(rb_eArgError, "no stream to set position");
14035 }
14036 ARGF_FORWARD(1, &offset);
14037 return rb_io_set_pos(ARGF.current_file, offset);
14038}
14039
14040/*
14041 * call-seq:
14042 * ARGF.rewind -> 0
14043 *
14044 * Positions the current file to the beginning of input, resetting
14045 * ARGF.lineno to zero.
14046 *
14047 * ARGF.readline #=> "This is line one\n"
14048 * ARGF.rewind #=> 0
14049 * ARGF.lineno #=> 0
14050 * ARGF.readline #=> "This is line one\n"
14051 */
14052static VALUE
14053argf_rewind(VALUE argf)
14054{
14055 VALUE ret;
14056 int old_lineno;
14057
14058 if (!next_argv()) {
14059 rb_raise(rb_eArgError, "no stream to rewind");
14060 }
14061 ARGF_FORWARD(0, 0);
14062 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
14063 ret = rb_io_rewind(ARGF.current_file);
14064 if (!global_argf_p(argf)) {
14065 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14066 }
14067 return ret;
14068}
14069
14070/*
14071 * call-seq:
14072 * ARGF.fileno -> integer
14073 * ARGF.to_i -> integer
14074 *
14075 * Returns an integer representing the numeric file descriptor for
14076 * the current file. Raises an ArgumentError if there isn't a current file.
14077 *
14078 * ARGF.fileno #=> 3
14079 */
14080static VALUE
14081argf_fileno(VALUE argf)
14082{
14083 if (!next_argv()) {
14084 rb_raise(rb_eArgError, "no stream");
14085 }
14086 ARGF_FORWARD(0, 0);
14087 return rb_io_fileno(ARGF.current_file);
14088}
14089
14090/*
14091 * call-seq:
14092 * ARGF.to_io -> IO
14093 *
14094 * Returns an IO object representing the current file. This will be a
14095 * File object unless the current file is a stream such as STDIN.
14096 *
14097 * For example:
14098 *
14099 * ARGF.to_io #=> #<File:glark.txt>
14100 * ARGF.to_io #=> #<IO:<STDIN>>
14101 */
14102static VALUE
14103argf_to_io(VALUE argf)
14104{
14105 next_argv();
14106 ARGF_FORWARD(0, 0);
14107 return ARGF.current_file;
14108}
14109
14110/*
14111 * call-seq:
14112 * ARGF.eof? -> true or false
14113 * ARGF.eof -> true or false
14114 *
14115 * Returns true if the current file in ARGF is at end of file, i.e. it has
14116 * no data to read. The stream must be opened for reading or an IOError
14117 * will be raised.
14118 *
14119 * $ echo "eof" | ruby argf.rb
14120 *
14121 * ARGF.eof? #=> false
14122 * 3.times { ARGF.readchar }
14123 * ARGF.eof? #=> false
14124 * ARGF.readchar #=> "\n"
14125 * ARGF.eof? #=> true
14126 */
14127
14128static VALUE
14129argf_eof(VALUE argf)
14130{
14131 next_argv();
14132 if (RTEST(ARGF.current_file)) {
14133 if (ARGF.init_p == 0) return Qtrue;
14134 next_argv();
14135 ARGF_FORWARD(0, 0);
14136 if (rb_io_eof(ARGF.current_file)) {
14137 return Qtrue;
14138 }
14139 }
14140 return Qfalse;
14141}
14142
14143/*
14144 * call-seq:
14145 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
14146 *
14147 * Reads _length_ bytes from ARGF. The files named on the command line
14148 * are concatenated and treated as a single file by this method, so when
14149 * called without arguments the contents of this pseudo file are returned in
14150 * their entirety.
14151 *
14152 * _length_ must be a non-negative integer or +nil+.
14153 *
14154 * If _length_ is a positive integer, +read+ tries to read
14155 * _length_ bytes without any conversion (binary mode).
14156 * It returns +nil+ if an EOF is encountered before anything can be read.
14157 * Fewer than _length_ bytes are returned if an EOF is encountered during
14158 * the read.
14159 * In the case of an integer _length_, the resulting string is always
14160 * in ASCII-8BIT encoding.
14161 *
14162 * If _length_ is omitted or is +nil+, it reads until EOF
14163 * and the encoding conversion is applied, if applicable.
14164 * A string is returned even if EOF is encountered before any data is read.
14165 *
14166 * If _length_ is zero, it returns an empty string (<code>""</code>).
14167 *
14168 * If the optional _outbuf_ argument is present,
14169 * it must reference a String, which will receive the data.
14170 * The _outbuf_ will contain only the received data after the method call
14171 * even if it is not empty at the beginning.
14172 *
14173 * For example:
14174 *
14175 * $ echo "small" > small.txt
14176 * $ echo "large" > large.txt
14177 * $ ./glark.rb small.txt large.txt
14178 *
14179 * ARGF.read #=> "small\nlarge"
14180 * ARGF.read(200) #=> "small\nlarge"
14181 * ARGF.read(2) #=> "sm"
14182 * ARGF.read(0) #=> ""
14183 *
14184 * Note that this method behaves like the fread() function in C.
14185 * This means it retries to invoke read(2) system calls to read data
14186 * with the specified length.
14187 * If you need the behavior like a single read(2) system call,
14188 * consider ARGF#readpartial or ARGF#read_nonblock.
14189 */
14190
14191static VALUE
14192argf_read(int argc, VALUE *argv, VALUE argf)
14193{
14194 VALUE tmp, str, length;
14195 long len = 0;
14196
14197 rb_scan_args(argc, argv, "02", &length, &str);
14198 if (!NIL_P(length)) {
14199 len = NUM2LONG(argv[0]);
14200 }
14201 if (!NIL_P(str)) {
14202 StringValue(str);
14203 rb_str_resize(str,0);
14204 argv[1] = Qnil;
14205 }
14206
14207 retry:
14208 if (!next_argv()) {
14209 return str;
14210 }
14211 if (ARGF_GENERIC_INPUT_P()) {
14212 tmp = argf_forward(argc, argv, argf);
14213 }
14214 else {
14215 tmp = io_read(argc, argv, ARGF.current_file);
14216 }
14217 if (NIL_P(str)) str = tmp;
14218 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
14219 if (NIL_P(tmp) || NIL_P(length)) {
14220 if (ARGF.next_p != -1) {
14221 argf_close(argf);
14222 ARGF.next_p = 1;
14223 goto retry;
14224 }
14225 }
14226 else if (argc >= 1) {
14227 long slen = RSTRING_LEN(str);
14228 if (slen < len) {
14229 argv[0] = LONG2NUM(len - slen);
14230 goto retry;
14231 }
14232 }
14233 return str;
14234}
14235
14237 int argc;
14238 VALUE *argv;
14239 VALUE argf;
14240};
14241
14242static VALUE
14243argf_forward_call(VALUE arg)
14244{
14245 struct argf_call_arg *p = (struct argf_call_arg *)arg;
14246 argf_forward(p->argc, p->argv, p->argf);
14247 return Qnil;
14248}
14249
14250static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
14251 int nonblock);
14252
14253/*
14254 * call-seq:
14255 * ARGF.readpartial(maxlen) -> string
14256 * ARGF.readpartial(maxlen, outbuf) -> outbuf
14257 *
14258 * Reads at most _maxlen_ bytes from the ARGF stream.
14259 *
14260 * If the optional _outbuf_ argument is present,
14261 * it must reference a String, which will receive the data.
14262 * The _outbuf_ will contain only the received data after the method call
14263 * even if it is not empty at the beginning.
14264 *
14265 * It raises EOFError on end of ARGF stream.
14266 * Since ARGF stream is a concatenation of multiple files,
14267 * internally EOF is occur for each file.
14268 * ARGF.readpartial returns empty strings for EOFs except the last one and
14269 * raises EOFError for the last one.
14270 *
14271 */
14272
14273static VALUE
14274argf_readpartial(int argc, VALUE *argv, VALUE argf)
14275{
14276 return argf_getpartial(argc, argv, argf, Qnil, 0);
14277}
14278
14279/*
14280 * call-seq:
14281 * ARGF.read_nonblock(maxlen[, options]) -> string
14282 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14283 *
14284 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14285 */
14286
14287static VALUE
14288argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14289{
14290 VALUE opts;
14291
14292 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14293
14294 if (!NIL_P(opts))
14295 argc--;
14296
14297 return argf_getpartial(argc, argv, argf, opts, 1);
14298}
14299
14300static VALUE
14301argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14302{
14303 VALUE tmp, str, length;
14304 int no_exception;
14305
14306 rb_scan_args(argc, argv, "11", &length, &str);
14307 if (!NIL_P(str)) {
14308 StringValue(str);
14309 argv[1] = str;
14310 }
14311 no_exception = no_exception_p(opts);
14312
14313 if (!next_argv()) {
14314 if (!NIL_P(str)) {
14315 rb_str_resize(str, 0);
14316 }
14317 rb_eof_error();
14318 }
14319 if (ARGF_GENERIC_INPUT_P()) {
14320 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14321 struct argf_call_arg arg;
14322 arg.argc = argc;
14323 arg.argv = argv;
14324 arg.argf = argf;
14325 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14326 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14327 }
14328 else {
14329 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14330 }
14331 if (NIL_P(tmp)) {
14332 if (ARGF.next_p == -1) {
14333 return io_nonblock_eof(no_exception);
14334 }
14335 argf_close(argf);
14336 ARGF.next_p = 1;
14337 if (RARRAY_LEN(ARGF.argv) == 0) {
14338 return io_nonblock_eof(no_exception);
14339 }
14340 if (NIL_P(str))
14341 str = rb_str_new(NULL, 0);
14342 return str;
14343 }
14344 return tmp;
14345}
14346
14347/*
14348 * call-seq:
14349 * ARGF.getc -> String or nil
14350 *
14351 * Reads the next character from ARGF and returns it as a String. Returns
14352 * +nil+ at the end of the stream.
14353 *
14354 * ARGF treats the files named on the command line as a single file created
14355 * by concatenating their contents. After returning the last character of the
14356 * first file, it returns the first character of the second file, and so on.
14357 *
14358 * For example:
14359 *
14360 * $ echo "foo" > file
14361 * $ ruby argf.rb file
14362 *
14363 * ARGF.getc #=> "f"
14364 * ARGF.getc #=> "o"
14365 * ARGF.getc #=> "o"
14366 * ARGF.getc #=> "\n"
14367 * ARGF.getc #=> nil
14368 * ARGF.getc #=> nil
14369 */
14370static VALUE
14371argf_getc(VALUE argf)
14372{
14373 VALUE ch;
14374
14375 retry:
14376 if (!next_argv()) return Qnil;
14377 if (ARGF_GENERIC_INPUT_P()) {
14378 ch = forward_current(rb_intern("getc"), 0, 0);
14379 }
14380 else {
14381 ch = rb_io_getc(ARGF.current_file);
14382 }
14383 if (NIL_P(ch) && ARGF.next_p != -1) {
14384 argf_close(argf);
14385 ARGF.next_p = 1;
14386 goto retry;
14387 }
14388
14389 return ch;
14390}
14391
14392/*
14393 * call-seq:
14394 * ARGF.getbyte -> Integer or nil
14395 *
14396 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14397 * the end of the stream.
14398 *
14399 * For example:
14400 *
14401 * $ echo "foo" > file
14402 * $ ruby argf.rb file
14403 *
14404 * ARGF.getbyte #=> 102
14405 * ARGF.getbyte #=> 111
14406 * ARGF.getbyte #=> 111
14407 * ARGF.getbyte #=> 10
14408 * ARGF.getbyte #=> nil
14409 */
14410static VALUE
14411argf_getbyte(VALUE argf)
14412{
14413 VALUE ch;
14414
14415 retry:
14416 if (!next_argv()) return Qnil;
14417 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14418 ch = forward_current(rb_intern("getbyte"), 0, 0);
14419 }
14420 else {
14421 ch = rb_io_getbyte(ARGF.current_file);
14422 }
14423 if (NIL_P(ch) && ARGF.next_p != -1) {
14424 argf_close(argf);
14425 ARGF.next_p = 1;
14426 goto retry;
14427 }
14428
14429 return ch;
14430}
14431
14432/*
14433 * call-seq:
14434 * ARGF.readchar -> String or nil
14435 *
14436 * Reads the next character from ARGF and returns it as a String. Raises
14437 * an EOFError after the last character of the last file has been read.
14438 *
14439 * For example:
14440 *
14441 * $ echo "foo" > file
14442 * $ ruby argf.rb file
14443 *
14444 * ARGF.readchar #=> "f"
14445 * ARGF.readchar #=> "o"
14446 * ARGF.readchar #=> "o"
14447 * ARGF.readchar #=> "\n"
14448 * ARGF.readchar #=> end of file reached (EOFError)
14449 */
14450static VALUE
14451argf_readchar(VALUE argf)
14452{
14453 VALUE ch;
14454
14455 retry:
14456 if (!next_argv()) rb_eof_error();
14457 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14458 ch = forward_current(rb_intern("getc"), 0, 0);
14459 }
14460 else {
14461 ch = rb_io_getc(ARGF.current_file);
14462 }
14463 if (NIL_P(ch) && ARGF.next_p != -1) {
14464 argf_close(argf);
14465 ARGF.next_p = 1;
14466 goto retry;
14467 }
14468
14469 return ch;
14470}
14471
14472/*
14473 * call-seq:
14474 * ARGF.readbyte -> Integer
14475 *
14476 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14477 * an EOFError after the last byte of the last file has been read.
14478 *
14479 * For example:
14480 *
14481 * $ echo "foo" > file
14482 * $ ruby argf.rb file
14483 *
14484 * ARGF.readbyte #=> 102
14485 * ARGF.readbyte #=> 111
14486 * ARGF.readbyte #=> 111
14487 * ARGF.readbyte #=> 10
14488 * ARGF.readbyte #=> end of file reached (EOFError)
14489 */
14490static VALUE
14491argf_readbyte(VALUE argf)
14492{
14493 VALUE c;
14494
14495 NEXT_ARGF_FORWARD(0, 0);
14496 c = argf_getbyte(argf);
14497 if (NIL_P(c)) {
14498 rb_eof_error();
14499 }
14500 return c;
14501}
14502
14503#define FOREACH_ARGF() while (next_argv())
14504
14505static VALUE
14506argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14507{
14508 const VALUE current = ARGF.current_file;
14509 rb_yield_values2(argc, argv);
14510 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14512 }
14513 return Qnil;
14514}
14515
14516#define ARGF_block_call(mid, argc, argv, func, argf) \
14517 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14518 func, argf, rb_keyword_given_p())
14519
14520static void
14521argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14522{
14523 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14524 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14525}
14526
14527static VALUE
14528argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14529{
14530 if (!global_argf_p(argf)) {
14531 ARGF.last_lineno = ++ARGF.lineno;
14532 }
14533 return argf_block_call_i(i, argf, argc, argv, blockarg);
14534}
14535
14536static void
14537argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14538{
14539 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14540 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14541}
14542
14543/*
14544 * call-seq:
14545 * ARGF.each(sep=$/) {|line| block } -> ARGF
14546 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14547 * ARGF.each(...) -> an_enumerator
14548 *
14549 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14550 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14551 * ARGF.each_line(...) -> an_enumerator
14552 *
14553 * Returns an enumerator which iterates over each line (separated by _sep_,
14554 * which defaults to your platform's newline character) of each file in
14555 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14556 * block, otherwise an enumerator is returned.
14557 * The optional _limit_ argument is an Integer specifying the maximum
14558 * length of each line; longer lines will be split according to this limit.
14559 *
14560 * This method allows you to treat the files supplied on the command line as
14561 * a single file consisting of the concatenation of each named file. After
14562 * the last line of the first file has been returned, the first line of the
14563 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14564 * used to determine the filename of the current line and line number of the
14565 * whole input, respectively.
14566 *
14567 * For example, the following code prints out each line of each named file
14568 * prefixed with its line number, displaying the filename once per file:
14569 *
14570 * ARGF.each_line do |line|
14571 * puts ARGF.filename if ARGF.file.lineno == 1
14572 * puts "#{ARGF.file.lineno}: #{line}"
14573 * end
14574 *
14575 * While the following code prints only the first file's name at first, and
14576 * the contents with line number counted through all named files.
14577 *
14578 * ARGF.each_line do |line|
14579 * puts ARGF.filename if ARGF.lineno == 1
14580 * puts "#{ARGF.lineno}: #{line}"
14581 * end
14582 */
14583static VALUE
14584argf_each_line(int argc, VALUE *argv, VALUE argf)
14585{
14586 RETURN_ENUMERATOR(argf, argc, argv);
14587 FOREACH_ARGF() {
14588 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14589 }
14590 return argf;
14591}
14592
14593/*
14594 * call-seq:
14595 * ARGF.each_byte {|byte| block } -> ARGF
14596 * ARGF.each_byte -> an_enumerator
14597 *
14598 * Iterates over each byte of each file in +ARGV+.
14599 * A byte is returned as an Integer in the range 0..255.
14600 *
14601 * This method allows you to treat the files supplied on the command line as
14602 * a single file consisting of the concatenation of each named file. After
14603 * the last byte of the first file has been returned, the first byte of the
14604 * second file is returned. The ARGF.filename method can be used to
14605 * determine the filename of the current byte.
14606 *
14607 * If no block is given, an enumerator is returned instead.
14608 *
14609 * For example:
14610 *
14611 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14612 *
14613 */
14614static VALUE
14615argf_each_byte(VALUE argf)
14616{
14617 RETURN_ENUMERATOR(argf, 0, 0);
14618 FOREACH_ARGF() {
14619 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14620 }
14621 return argf;
14622}
14623
14624/*
14625 * call-seq:
14626 * ARGF.each_char {|char| block } -> ARGF
14627 * ARGF.each_char -> an_enumerator
14628 *
14629 * Iterates over each character of each file in ARGF.
14630 *
14631 * This method allows you to treat the files supplied on the command line as
14632 * a single file consisting of the concatenation of each named file. After
14633 * the last character of the first file has been returned, the first
14634 * character of the second file is returned. The ARGF.filename method can
14635 * be used to determine the name of the file in which the current character
14636 * appears.
14637 *
14638 * If no block is given, an enumerator is returned instead.
14639 */
14640static VALUE
14641argf_each_char(VALUE argf)
14642{
14643 RETURN_ENUMERATOR(argf, 0, 0);
14644 FOREACH_ARGF() {
14645 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14646 }
14647 return argf;
14648}
14649
14650/*
14651 * call-seq:
14652 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14653 * ARGF.each_codepoint -> an_enumerator
14654 *
14655 * Iterates over each codepoint of each file in ARGF.
14656 *
14657 * This method allows you to treat the files supplied on the command line as
14658 * a single file consisting of the concatenation of each named file. After
14659 * the last codepoint of the first file has been returned, the first
14660 * codepoint of the second file is returned. The ARGF.filename method can
14661 * be used to determine the name of the file in which the current codepoint
14662 * appears.
14663 *
14664 * If no block is given, an enumerator is returned instead.
14665 */
14666static VALUE
14667argf_each_codepoint(VALUE argf)
14668{
14669 RETURN_ENUMERATOR(argf, 0, 0);
14670 FOREACH_ARGF() {
14671 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14672 }
14673 return argf;
14674}
14675
14676/*
14677 * call-seq:
14678 * ARGF.filename -> String
14679 * ARGF.path -> String
14680 *
14681 * Returns the current filename. "-" is returned when the current file is
14682 * STDIN.
14683 *
14684 * For example:
14685 *
14686 * $ echo "foo" > foo
14687 * $ echo "bar" > bar
14688 * $ echo "glark" > glark
14689 *
14690 * $ ruby argf.rb foo bar glark
14691 *
14692 * ARGF.filename #=> "foo"
14693 * ARGF.read(5) #=> "foo\nb"
14694 * ARGF.filename #=> "bar"
14695 * ARGF.skip
14696 * ARGF.filename #=> "glark"
14697 */
14698static VALUE
14699argf_filename(VALUE argf)
14700{
14701 next_argv();
14702 return ARGF.filename;
14703}
14704
14705static VALUE
14706argf_filename_getter(ID id, VALUE *var)
14707{
14708 return argf_filename(*var);
14709}
14710
14711/*
14712 * call-seq:
14713 * ARGF.file -> IO or File object
14714 *
14715 * Returns the current file as an IO or File object.
14716 * <code>$stdin</code> is returned when the current file is STDIN.
14717 *
14718 * For example:
14719 *
14720 * $ echo "foo" > foo
14721 * $ echo "bar" > bar
14722 *
14723 * $ ruby argf.rb foo bar
14724 *
14725 * ARGF.file #=> #<File:foo>
14726 * ARGF.read(5) #=> "foo\nb"
14727 * ARGF.file #=> #<File:bar>
14728 */
14729static VALUE
14730argf_file(VALUE argf)
14731{
14732 next_argv();
14733 return ARGF.current_file;
14734}
14735
14736/*
14737 * call-seq:
14738 * ARGF.binmode -> ARGF
14739 *
14740 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14741 * be reset to non-binary mode. This option has the following effects:
14742 *
14743 * * Newline conversion is disabled.
14744 * * Encoding conversion is disabled.
14745 * * Content is treated as ASCII-8BIT.
14746 */
14747static VALUE
14748argf_binmode_m(VALUE argf)
14749{
14750 ARGF.binmode = 1;
14751 next_argv();
14752 ARGF_FORWARD(0, 0);
14753 rb_io_ascii8bit_binmode(ARGF.current_file);
14754 return argf;
14755}
14756
14757/*
14758 * call-seq:
14759 * ARGF.binmode? -> true or false
14760 *
14761 * Returns true if ARGF is being read in binary mode; false otherwise.
14762 * To enable binary mode use ARGF.binmode.
14763 *
14764 * For example:
14765 *
14766 * ARGF.binmode? #=> false
14767 * ARGF.binmode
14768 * ARGF.binmode? #=> true
14769 */
14770static VALUE
14771argf_binmode_p(VALUE argf)
14772{
14773 return RBOOL(ARGF.binmode);
14774}
14775
14776/*
14777 * call-seq:
14778 * ARGF.skip -> ARGF
14779 *
14780 * Sets the current file to the next file in ARGV. If there aren't any more
14781 * files it has no effect.
14782 *
14783 * For example:
14784 *
14785 * $ ruby argf.rb foo bar
14786 * ARGF.filename #=> "foo"
14787 * ARGF.skip
14788 * ARGF.filename #=> "bar"
14789 */
14790static VALUE
14791argf_skip(VALUE argf)
14792{
14793 if (ARGF.init_p && ARGF.next_p == 0) {
14794 argf_close(argf);
14795 ARGF.next_p = 1;
14796 }
14797 return argf;
14798}
14799
14800/*
14801 * call-seq:
14802 * ARGF.close -> ARGF
14803 *
14804 * Closes the current file and skips to the next file in ARGV. If there are
14805 * no more files to open, just closes the current file. STDIN will not be
14806 * closed.
14807 *
14808 * For example:
14809 *
14810 * $ ruby argf.rb foo bar
14811 *
14812 * ARGF.filename #=> "foo"
14813 * ARGF.close
14814 * ARGF.filename #=> "bar"
14815 * ARGF.close
14816 */
14817static VALUE
14818argf_close_m(VALUE argf)
14819{
14820 next_argv();
14821 argf_close(argf);
14822 if (ARGF.next_p != -1) {
14823 ARGF.next_p = 1;
14824 }
14825 ARGF.lineno = 0;
14826 return argf;
14827}
14828
14829/*
14830 * call-seq:
14831 * ARGF.closed? -> true or false
14832 *
14833 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14834 * ARGF.close to actually close the current file.
14835 */
14836static VALUE
14837argf_closed(VALUE argf)
14838{
14839 next_argv();
14840 ARGF_FORWARD(0, 0);
14841 return rb_io_closed_p(ARGF.current_file);
14842}
14843
14844/*
14845 * call-seq:
14846 * ARGF.to_s -> String
14847 *
14848 * Returns "ARGF".
14849 */
14850static VALUE
14851argf_to_s(VALUE argf)
14852{
14853 return rb_str_new2("ARGF");
14854}
14855
14856/*
14857 * call-seq:
14858 * ARGF.inplace_mode -> String
14859 *
14860 * Returns the file extension appended to the names of backup copies of
14861 * modified files under in-place edit mode. This value can be set using
14862 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14863 */
14864static VALUE
14865argf_inplace_mode_get(VALUE argf)
14866{
14867 if (!ARGF.inplace) return Qnil;
14868 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14869 return rb_str_dup(ARGF.inplace);
14870}
14871
14872static VALUE
14873opt_i_get(ID id, VALUE *var)
14874{
14875 return argf_inplace_mode_get(*var);
14876}
14877
14878/*
14879 * call-seq:
14880 * ARGF.inplace_mode = ext -> ARGF
14881 *
14882 * Sets the filename extension for in-place editing mode to the given String.
14883 * The backup copy of each file being edited has this value appended to its
14884 * filename.
14885 *
14886 * For example:
14887 *
14888 * $ ruby argf.rb file.txt
14889 *
14890 * ARGF.inplace_mode = '.bak'
14891 * ARGF.each_line do |line|
14892 * print line.sub("foo","bar")
14893 * end
14894 *
14895 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14896 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14897 * "bar".
14898 */
14899static VALUE
14900argf_inplace_mode_set(VALUE argf, VALUE val)
14901{
14902 if (!RTEST(val)) {
14903 ARGF.inplace = Qfalse;
14904 }
14905 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14906 ARGF.inplace = Qnil;
14907 }
14908 else {
14909 ARGF_SET(inplace, rb_str_new_frozen(val));
14910 }
14911 return argf;
14912}
14913
14914static void
14915opt_i_set(VALUE val, ID id, VALUE *var)
14916{
14917 argf_inplace_mode_set(*var, val);
14918}
14919
14920void
14921ruby_set_inplace_mode(const char *suffix)
14922{
14923 ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
14924}
14925
14926/*
14927 * call-seq:
14928 * ARGF.argv -> ARGV
14929 *
14930 * Returns the +ARGV+ array, which contains the arguments passed to your
14931 * script, one per element.
14932 *
14933 * For example:
14934 *
14935 * $ ruby argf.rb -v glark.txt
14936 *
14937 * ARGF.argv #=> ["-v", "glark.txt"]
14938 *
14939 */
14940static VALUE
14941argf_argv(VALUE argf)
14942{
14943 return ARGF.argv;
14944}
14945
14946static VALUE
14947argf_argv_getter(ID id, VALUE *var)
14948{
14949 return argf_argv(*var);
14950}
14951
14952VALUE
14954{
14955 return ARGF.argv;
14956}
14957
14958/*
14959 * call-seq:
14960 * ARGF.to_write_io -> io
14961 *
14962 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14963 * enabled.
14964 */
14965static VALUE
14966argf_write_io(VALUE argf)
14967{
14968 if (!RTEST(ARGF.current_file)) {
14969 rb_raise(rb_eIOError, "not opened for writing");
14970 }
14971 return GetWriteIO(ARGF.current_file);
14972}
14973
14974/*
14975 * call-seq:
14976 * ARGF.write(*objects) -> integer
14977 *
14978 * Writes each of the given +objects+ if inplace mode.
14979 */
14980static VALUE
14981argf_write(int argc, VALUE *argv, VALUE argf)
14982{
14983 return rb_io_writev(argf_write_io(argf), argc, argv);
14984}
14985
14986void
14987rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14988{
14989 rb_readwrite_syserr_fail(waiting, errno, mesg);
14990}
14991
14992void
14993rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14994{
14995 VALUE arg, c = Qnil;
14996 arg = mesg ? rb_str_new2(mesg) : Qnil;
14997 switch (waiting) {
14998 case RB_IO_WAIT_WRITABLE:
14999 switch (n) {
15000 case EAGAIN:
15001 c = rb_eEAGAINWaitWritable;
15002 break;
15003#if EAGAIN != EWOULDBLOCK
15004 case EWOULDBLOCK:
15005 c = rb_eEWOULDBLOCKWaitWritable;
15006 break;
15007#endif
15008 case EINPROGRESS:
15009 c = rb_eEINPROGRESSWaitWritable;
15010 break;
15011 default:
15013 }
15014 break;
15015 case RB_IO_WAIT_READABLE:
15016 switch (n) {
15017 case EAGAIN:
15018 c = rb_eEAGAINWaitReadable;
15019 break;
15020#if EAGAIN != EWOULDBLOCK
15021 case EWOULDBLOCK:
15022 c = rb_eEWOULDBLOCKWaitReadable;
15023 break;
15024#endif
15025 case EINPROGRESS:
15026 c = rb_eEINPROGRESSWaitReadable;
15027 break;
15028 default:
15030 }
15031 break;
15032 default:
15033 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
15034 }
15036}
15037
15038static VALUE
15039get_LAST_READ_LINE(ID _x, VALUE *_y)
15040{
15041 return rb_lastline_get();
15042}
15043
15044static void
15045set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
15046{
15047 rb_lastline_set(val);
15048}
15049
15050/*
15051 * Document-class: IOError
15052 *
15053 * Raised when an IO operation fails.
15054 *
15055 * File.open("/etc/hosts") {|f| f << "example"}
15056 * #=> IOError: not opened for writing
15057 *
15058 * File.open("/etc/hosts") {|f| f.close; f.read }
15059 * #=> IOError: closed stream
15060 *
15061 * Note that some IO failures raise <code>SystemCallError</code>s
15062 * and these are not subclasses of IOError:
15063 *
15064 * File.open("does/not/exist")
15065 * #=> Errno::ENOENT: No such file or directory - does/not/exist
15066 */
15067
15068/*
15069 * Document-class: EOFError
15070 *
15071 * Raised by some IO operations when reaching the end of file. Many IO
15072 * methods exist in two forms,
15073 *
15074 * one that returns +nil+ when the end of file is reached, the other
15075 * raises EOFError.
15076 *
15077 * EOFError is a subclass of IOError.
15078 *
15079 * file = File.open("/etc/hosts")
15080 * file.read
15081 * file.gets #=> nil
15082 * file.readline #=> EOFError: end of file reached
15083 * file.close
15084 */
15085
15086/*
15087 * Document-class: ARGF
15088 *
15089 * == \ARGF and +ARGV+
15090 *
15091 * The \ARGF object works with the array at global variable +ARGV+
15092 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
15093 *
15094 * - **ARGV** may be thought of as the <b>argument vector</b> array.
15095 *
15096 * Initially, it contains the command-line arguments and options
15097 * that are passed to the Ruby program;
15098 * the program can modify that array as it likes.
15099 *
15100 * - **ARGF** may be thought of as the <b>argument files</b> object.
15101 *
15102 * It can access file streams and/or the <tt>$stdin</tt> stream,
15103 * based on what it finds in +ARGV+.
15104 * This provides a convenient way for the command line
15105 * to specify streams for a Ruby program to read.
15106 *
15107 * == Reading
15108 *
15109 * \ARGF may read from _source_ streams,
15110 * which at any particular time are determined by the content of +ARGV+.
15111 *
15112 * === Simplest Case
15113 *
15114 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
15115 * the source is <tt>$stdin</tt>:
15116 *
15117 * - \File +t.rb+:
15118 *
15119 * p ['ARGV', ARGV]
15120 * p ['ARGF.read', ARGF.read]
15121 *
15122 * - Commands and outputs
15123 * (see below for the content of files +foo.txt+ and +bar.txt+):
15124 *
15125 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
15126 * ["ARGV", []]
15127 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15128 *
15129 * $ cat foo.txt bar.txt | ruby t.rb
15130 * ["ARGV", []]
15131 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15132 *
15133 * === About the Examples
15134 *
15135 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
15136 *
15137 * $ cat foo.txt
15138 * Foo 0
15139 * Foo 1
15140 * $ cat bar.txt
15141 * Bar 0
15142 * Bar 1
15143 * Bar 2
15144 * Bar 3
15145 *
15146 * === Sources in +ARGV+
15147 *
15148 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
15149 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
15150 * the sources are found in +ARGV+.
15151 *
15152 * \ARGF assumes that each element in array +ARGV+ is a potential source,
15153 * and is one of:
15154 *
15155 * - The string path to a file that may be opened as a stream.
15156 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
15157 *
15158 * Each element that is _not_ one of these
15159 * should be removed from +ARGV+ before \ARGF accesses that source.
15160 *
15161 * In the following example:
15162 *
15163 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
15164 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
15165 *
15166 * Example:
15167 *
15168 * - \File +t.rb+:
15169 *
15170 * # Print arguments (and options, if any) found on command line.
15171 * p ['ARGV', ARGV]
15172 *
15173 * - Command and output:
15174 *
15175 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
15176 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
15177 *
15178 * \ARGF's stream access considers the elements of +ARGV+, left to right:
15179 *
15180 * - \File +t.rb+:
15181 *
15182 * p "ARGV: #{ARGV}"
15183 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
15184 *
15185 * - Command and output:
15186 *
15187 * $ ruby t.rb foo.txt bar.txt
15188 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15189 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15190 *
15191 * Because the value at +ARGV+ is an ordinary array,
15192 * you can manipulate it to control which sources \ARGF considers:
15193 *
15194 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
15195 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
15196 *
15197 * Each element in +ARGV+ is removed when its corresponding source is accessed;
15198 * when all sources have been accessed, the array is empty:
15199 *
15200 * - \File +t.rb+:
15201 *
15202 * until ARGV.empty? && ARGF.eof?
15203 * p "ARGV: #{ARGV}"
15204 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
15205 * end
15206 *
15207 * - Command and output:
15208 *
15209 * $ ruby t.rb foo.txt bar.txt
15210 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15211 * "Line: Foo 0\n"
15212 * "ARGV: [\"bar.txt\"]"
15213 * "Line: Foo 1\n"
15214 * "ARGV: [\"bar.txt\"]"
15215 * "Line: Bar 0\n"
15216 * "ARGV: []"
15217 * "Line: Bar 1\n"
15218 * "ARGV: []"
15219 * "Line: Bar 2\n"
15220 * "ARGV: []"
15221 * "Line: Bar 3\n"
15222 *
15223 * ==== Filepaths in +ARGV+
15224 *
15225 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
15226 *
15227 * This program prints what it reads from files at the paths specified
15228 * on the command line:
15229 *
15230 * - \File +t.rb+:
15231 *
15232 * p ['ARGV', ARGV]
15233 * # Read and print all content from the specified sources.
15234 * p ['ARGF.read', ARGF.read]
15235 *
15236 * - Command and output:
15237 *
15238 * $ ruby t.rb foo.txt bar.txt
15239 * ["ARGV", [foo.txt, bar.txt]
15240 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15241 *
15242 * ==== Specifying <tt>$stdin</tt> in +ARGV+
15243 *
15244 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
15245 *
15246 * - \File +t.rb+:
15247 *
15248 * p ['ARGV', ARGV]
15249 * p ['ARGF.read', ARGF.read]
15250 *
15251 * - Command and output:
15252 *
15253 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
15254 * ["ARGV", ["-"]]
15255 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15256 *
15257 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
15258 *
15259 * - Command and output:
15260 *
15261 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15262 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15263 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15264 *
15265 * ==== Mixtures and Repetitions in +ARGV+
15266 *
15267 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15268 * and character <tt>'-'</tt>, including repetitions.
15269 *
15270 * ==== Modifications to +ARGV+
15271 *
15272 * The running Ruby program may make any modifications to the +ARGV+ array;
15273 * the current value of +ARGV+ affects \ARGF reading.
15274 *
15275 * ==== Empty +ARGV+
15276 *
15277 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15278 * or raises an exception, depending on the specific method.
15279 *
15280 * === More Read Methods
15281 *
15282 * As seen above, method ARGF#read reads the content of all sources
15283 * into a single string.
15284 * Other \ARGF methods provide other ways to access that content;
15285 * these include:
15286 *
15287 * - Byte access: #each_byte, #getbyte, #readbyte.
15288 * - Character access: #each_char, #getc, #readchar.
15289 * - Codepoint access: #each_codepoint.
15290 * - Line access: #each_line, #gets, #readline, #readlines.
15291 * - Source access: #read, #read_nonblock, #readpartial.
15292 *
15293 * === About \Enumerable
15294 *
15295 * \ARGF includes module Enumerable.
15296 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15297 *
15298 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15299 * _not_ from +ARGV+;
15300 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15301 * not an array of the strings from +ARGV+:
15302 *
15303 * - \File +t.rb+:
15304 *
15305 * p ['ARGV', ARGV]
15306 * p ['ARGF.entries', ARGF.entries]
15307 *
15308 * - Command and output:
15309 *
15310 * $ ruby t.rb foo.txt bar.txt
15311 * ["ARGV", ["foo.txt", "bar.txt"]]
15312 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15313 *
15314 * == Writing
15315 *
15316 * If <i>inplace mode</i> is in effect,
15317 * \ARGF may write to target streams,
15318 * which at any particular time are determined by the content of ARGV.
15319 *
15320 * Methods about inplace mode:
15321 *
15322 * - #inplace_mode
15323 * - #inplace_mode=
15324 * - #to_write_io
15325 *
15326 * Methods for writing:
15327 *
15328 * - #print
15329 * - #printf
15330 * - #putc
15331 * - #puts
15332 * - #write
15333 *
15334 */
15335
15336/*
15337 * An instance of class \IO (commonly called a _stream_)
15338 * represents an input/output stream in the underlying operating system.
15339 * Class \IO is the basis for input and output in Ruby.
15340 *
15341 * Class File is the only class in the Ruby core that is a subclass of \IO.
15342 * Some classes in the Ruby standard library are also subclasses of \IO;
15343 * these include TCPSocket and UDPSocket.
15344 *
15345 * The global constant ARGF (also accessible as <tt>$<</tt>)
15346 * provides an IO-like stream that allows access to all file paths
15347 * found in ARGV (or found in STDIN if ARGV is empty).
15348 * ARGF is not itself a subclass of \IO.
15349 *
15350 * Class StringIO provides an IO-like stream that handles a String.
15351 * StringIO is not itself a subclass of \IO.
15352 *
15353 * Important objects based on \IO include:
15354 *
15355 * - $stdin.
15356 * - $stdout.
15357 * - $stderr.
15358 * - Instances of class File.
15359 *
15360 * An instance of \IO may be created using:
15361 *
15362 * - IO.new: returns a new \IO object for the given integer file descriptor.
15363 * - IO.open: passes a new \IO object to the given block.
15364 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15365 * of a newly-launched subprocess.
15366 * - Kernel#open: Returns a new \IO object connected to a given source:
15367 * stream, file, or subprocess.
15368 *
15369 * Like a File stream, an \IO stream has:
15370 *
15371 * - A read/write mode, which may be read-only, write-only, or read/write;
15372 * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
15373 * - A data mode, which may be text-only or binary;
15374 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15375 * - Internal and external encodings;
15376 * see {Encodings}[rdoc-ref:File@Encodings].
15377 *
15378 * And like other \IO streams, it has:
15379 *
15380 * - A position, which determines where in the stream the next
15381 * read or write is to occur;
15382 * see {Position}[rdoc-ref:IO@Position].
15383 * - A line number, which is a special, line-oriented, "position"
15384 * (different from the position mentioned above);
15385 * see {Line Number}[rdoc-ref:IO@Line+Number].
15386 *
15387 * == Extension <tt>io/console</tt>
15388 *
15389 * Extension <tt>io/console</tt> provides numerous methods
15390 * for interacting with the console;
15391 * requiring it adds numerous methods to class \IO.
15392 *
15393 * == Example Files
15394 *
15395 * Many examples here use these variables:
15396 *
15397 * :include: doc/examples/files.rdoc
15398 *
15399 * == Open Options
15400 *
15401 * A number of \IO methods accept optional keyword arguments
15402 * that determine how a new stream is to be opened:
15403 *
15404 * - +:mode+: Stream mode.
15405 * - +:flags+: Integer file open flags;
15406 * If +mode+ is also given, the two are bitwise-ORed.
15407 * - +:external_encoding+: External encoding for the stream.
15408 * - +:internal_encoding+: Internal encoding for the stream.
15409 * <tt>'-'</tt> is a synonym for the default internal encoding.
15410 * If the value is +nil+ no conversion occurs.
15411 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15412 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15413 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15414 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15415 * when the stream closes; otherwise it remains open.
15416 * - +:path+: If a string value is provided, it is used in #inspect and is available as
15417 * #path method.
15418 *
15419 * Also available are the options offered in String#encode,
15420 * which may control conversion between external and internal encoding.
15421 *
15422 * == Basic \IO
15423 *
15424 * You can perform basic stream \IO with these methods,
15425 * which typically operate on multi-byte strings:
15426 *
15427 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15428 * - IO#write: Writes zero or more strings to the stream;
15429 * each given object that is not already a string is converted via +to_s+.
15430 *
15431 * === Position
15432 *
15433 * An \IO stream has a nonnegative integer _position_,
15434 * which is the byte offset at which the next read or write is to occur.
15435 * A new stream has position zero (and line number zero);
15436 * method +rewind+ resets the position (and line number) to zero.
15437 *
15438 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15439 * Encoding::Converter instances used for that \IO.
15440 *
15441 * The relevant methods:
15442 *
15443 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15444 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15445 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15446 * relative to a given position +whence+
15447 * (indicating the beginning, end, or current position).
15448 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15449 *
15450 * === Open and Closed Streams
15451 *
15452 * A new \IO stream may be open for reading, open for writing, or both.
15453 *
15454 * A stream is automatically closed when claimed by the garbage collector.
15455 *
15456 * Attempted reading or writing on a closed stream raises an exception.
15457 *
15458 * The relevant methods:
15459 *
15460 * - IO#close: Closes the stream for both reading and writing.
15461 * - IO#close_read: Closes the stream for reading.
15462 * - IO#close_write: Closes the stream for writing.
15463 * - IO#closed?: Returns whether the stream is closed.
15464 *
15465 * === End-of-Stream
15466 *
15467 * You can query whether a stream is positioned at its end:
15468 *
15469 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15470 *
15471 * You can reposition to end-of-stream by using method IO#seek:
15472 *
15473 * f = File.new('t.txt')
15474 * f.eof? # => false
15475 * f.seek(0, :END)
15476 * f.eof? # => true
15477 * f.close
15478 *
15479 * Or by reading all stream content (which is slower than using IO#seek):
15480 *
15481 * f.rewind
15482 * f.eof? # => false
15483 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15484 * f.eof? # => true
15485 *
15486 * == Line \IO
15487 *
15488 * Class \IO supports line-oriented
15489 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15490 *
15491 * === Line Input
15492 *
15493 * Class \IO supports line-oriented input for
15494 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input].
15495 *
15496 * ==== Line Input Options
15497 *
15498 * Optional keyword argument +chomp+ (default: +false+)
15499 * specifies whether line separators are to be excluded from the result of a read.
15500 *
15501 * ==== \File Line Input
15502 *
15503 * You can read lines from a file using these methods:
15504 *
15505 * - IO.foreach: Reads each line and passes it to the given block.
15506 * - IO.readlines: Reads and returns all lines in an array.
15507 *
15508 * For each of these methods:
15509 *
15510 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15511 * - Line parsing depends on the effective <i>line separator</i>;
15512 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15513 * - The length of each returned line depends on the effective <i>line limit</i>;
15514 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15515 *
15516 * ==== Stream Line Input
15517 *
15518 * You can read lines from an \IO stream using these methods:
15519 *
15520 * - IO#each_line: Reads each remaining line, passing it to the given block.
15521 * - IO#gets: Returns the next line.
15522 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15523 * - IO#readlines: Returns all remaining lines in an array.
15524 *
15525 * For each of these methods:
15526 *
15527 * - Reading may begin mid-line,
15528 * depending on the stream's _position_;
15529 * see {Position}[rdoc-ref:IO@Position].
15530 * - Line parsing depends on the effective <i>line separator</i>;
15531 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15532 * - The length of each returned line depends on the effective <i>line limit</i>;
15533 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15534 *
15535 * ===== Line Separator
15536 *
15537 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15538 * the string that determines what is considered a line;
15539 * it is sometimes called the <i>input record separator</i>.
15540 *
15541 * The default line separator is taken from global variable <tt>$/</tt>,
15542 * whose initial value is <tt>"\n"</tt>.
15543 *
15544 * Generally, the line to be read next is all data
15545 * from the current {position}[rdoc-ref:IO@Position]
15546 * to the next line separator
15547 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15548 *
15549 * f = File.new('t.txt')
15550 * # Method gets with no sep argument returns the next line, according to $/.
15551 * f.gets # => "First line\n"
15552 * f.gets # => "Second line\n"
15553 * f.gets # => "\n"
15554 * f.gets # => "Fourth line\n"
15555 * f.gets # => "Fifth line\n"
15556 * f.close
15557 *
15558 * You can use a different line separator by passing argument +sep+:
15559 *
15560 * f = File.new('t.txt')
15561 * f.gets('l') # => "First l"
15562 * f.gets('li') # => "ine\nSecond li"
15563 * f.gets('lin') # => "ne\n\nFourth lin"
15564 * f.gets # => "e\n"
15565 * f.close
15566 *
15567 * Or by setting global variable <tt>$/</tt>:
15568 *
15569 * f = File.new('t.txt')
15570 * $/ = 'l'
15571 * f.gets # => "First l"
15572 * f.gets # => "ine\nSecond l"
15573 * f.gets # => "ine\n\nFourth l"
15574 * f.close
15575 *
15576 * ===== Special Line Separator Values
15577 *
15578 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15579 * accepts two special values for parameter +sep+:
15580 *
15581 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15582 *
15583 * f = File.new('t.txt')
15584 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15585 * f.close
15586 *
15587 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15588 * (paragraphs being separated by two consecutive line separators):
15589 *
15590 * f = File.new('t.txt')
15591 * f.gets('') # => "First line\nSecond line\n\n"
15592 * f.gets('') # => "Fourth line\nFifth line\n"
15593 * f.close
15594 *
15595 * ===== Line Limit
15596 *
15597 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15598 * uses an integer <i>line limit</i>,
15599 * which restricts the number of bytes that may be returned.
15600 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15601 * than the limit).
15602 *
15603 * The default limit value is <tt>-1</tt>;
15604 * any negative limit value means that there is no limit.
15605 *
15606 * If there is no limit, the line is determined only by +sep+.
15607 *
15608 * # Text with 1-byte characters.
15609 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15610 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15611 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15612 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15613 * # No more than one line.
15614 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15615 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15616 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15617 *
15618 * # Text with 3-byte characters, which will not be split.
15619 * File.read('t.ja') # => "こんにちは"
15620 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15621 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15622 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15623 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15624 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15625 *
15626 * ===== Line Separator and Line Limit
15627 *
15628 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15629 *
15630 * - Returns the next line as determined by line separator +sep+.
15631 * - But returns no more bytes than are allowed by the limit +limit+.
15632 *
15633 * Example:
15634 *
15635 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15636 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15637 *
15638 * ===== Line Number
15639 *
15640 * A readable \IO stream has a non-negative integer <i>line number</i>:
15641 *
15642 * - IO#lineno: Returns the line number.
15643 * - IO#lineno=: Resets and returns the line number.
15644 *
15645 * Unless modified by a call to method IO#lineno=,
15646 * the line number is the number of lines read
15647 * by certain line-oriented methods,
15648 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15649 *
15650 * - IO.foreach: Increments the line number on each call to the block.
15651 * - IO#each_line: Increments the line number on each call to the block.
15652 * - IO#gets: Increments the line number.
15653 * - IO#readline: Increments the line number.
15654 * - IO#readlines: Increments the line number for each line read.
15655 *
15656 * A new stream is initially has line number zero (and position zero);
15657 * method +rewind+ resets the line number (and position) to zero:
15658 *
15659 * f = File.new('t.txt')
15660 * f.lineno # => 0
15661 * f.gets # => "First line\n"
15662 * f.lineno # => 1
15663 * f.rewind
15664 * f.lineno # => 0
15665 * f.close
15666 *
15667 * Reading lines from a stream usually changes its line number:
15668 *
15669 * f = File.new('t.txt', 'r')
15670 * f.lineno # => 0
15671 * f.readline # => "This is line one.\n"
15672 * f.lineno # => 1
15673 * f.readline # => "This is the second line.\n"
15674 * f.lineno # => 2
15675 * f.readline # => "Here's the third line.\n"
15676 * f.lineno # => 3
15677 * f.eof? # => true
15678 * f.close
15679 *
15680 * Iterating over lines in a stream usually changes its line number:
15681 *
15682 * File.open('t.txt') do |f|
15683 * f.each_line do |line|
15684 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15685 * end
15686 * end
15687 *
15688 * Output:
15689 *
15690 * "position=11 eof?=false lineno=1"
15691 * "position=23 eof?=false lineno=2"
15692 * "position=24 eof?=false lineno=3"
15693 * "position=36 eof?=false lineno=4"
15694 * "position=47 eof?=true lineno=5"
15695 *
15696 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15697 * the line number does not affect where the next read or write will occur:
15698 *
15699 * f = File.new('t.txt')
15700 * f.lineno = 1000
15701 * f.lineno # => 1000
15702 * f.gets # => "First line\n"
15703 * f.lineno # => 1001
15704 * f.close
15705 *
15706 * Associated with the line number is the global variable <tt>$.</tt>:
15707 *
15708 * - When a stream is opened, <tt>$.</tt> is not set;
15709 * its value is left over from previous activity in the process:
15710 *
15711 * $. = 41
15712 * f = File.new('t.txt')
15713 * $. = 41
15714 * # => 41
15715 * f.close
15716 *
15717 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15718 *
15719 * f0 = File.new('t.txt')
15720 * f1 = File.new('t.dat')
15721 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15722 * $. # => 5
15723 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15724 * $. # => 1
15725 * f0.close
15726 * f1.close
15727 *
15728 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15729 *
15730 * f = File.new('t.txt')
15731 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15732 * $. # => 5
15733 * f.rewind
15734 * f.seek(0, :SET)
15735 * $. # => 5
15736 * f.close
15737 *
15738 * === Line Output
15739 *
15740 * You can write to an \IO stream line-by-line using this method:
15741 *
15742 * - IO#puts: Writes objects to the stream.
15743 *
15744 * == Character \IO
15745 *
15746 * You can process an \IO stream character-by-character using these methods:
15747 *
15748 * - IO#getc: Reads and returns the next character from the stream.
15749 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15750 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15751 * - IO#putc: Writes a character to the stream.
15752 * - IO#each_char: Reads each remaining character in the stream,
15753 * passing the character to the given block.
15754 *
15755 * == Byte \IO
15756 *
15757 * You can process an \IO stream byte-by-byte using these methods:
15758 *
15759 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15760 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15761 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15762 * - IO#each_byte: Reads each remaining byte in the stream,
15763 * passing the byte to the given block.
15764 *
15765 * == Codepoint \IO
15766 *
15767 * You can process an \IO stream codepoint-by-codepoint:
15768 *
15769 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15770 *
15771 * == What's Here
15772 *
15773 * First, what's elsewhere. Class \IO:
15774 *
15775 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
15776 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
15777 * which provides dozens of additional methods.
15778 *
15779 * Here, class \IO provides methods that are useful for:
15780 *
15781 * - {Creating}[rdoc-ref:IO@Creating]
15782 * - {Reading}[rdoc-ref:IO@Reading]
15783 * - {Writing}[rdoc-ref:IO@Writing]
15784 * - {Positioning}[rdoc-ref:IO@Positioning]
15785 * - {Iterating}[rdoc-ref:IO@Iterating]
15786 * - {Settings}[rdoc-ref:IO@Settings]
15787 * - {Querying}[rdoc-ref:IO@Querying]
15788 * - {Buffering}[rdoc-ref:IO@Buffering]
15789 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15790 * - {Other}[rdoc-ref:IO@Other]
15791 *
15792 * === Creating
15793 *
15794 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15795 * integer file descriptor.
15796 * - ::open: Creates a new \IO object.
15797 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15798 * - ::popen: Creates an \IO object to interact with a subprocess.
15799 * - ::select: Selects which given \IO instances are ready for reading,
15800 * writing, or have pending exceptions.
15801 *
15802 * === Reading
15803 *
15804 * - ::binread: Returns a binary string with all or a subset of bytes
15805 * from the given file.
15806 * - ::read: Returns a string with all or a subset of bytes from the given file.
15807 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15808 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15809 * - #getc: Returns the next character read from +self+ as a string.
15810 * - #gets: Returns the line read from +self+.
15811 * - #pread: Returns all or the next _n_ bytes read from +self+,
15812 * not updating the receiver's offset.
15813 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15814 * for a given _n_.
15815 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15816 * in non-block mode.
15817 * - #readbyte: Returns the next byte read from +self+;
15818 * same as #getbyte, but raises an exception on end-of-stream.
15819 * - #readchar: Returns the next character read from +self+;
15820 * same as #getc, but raises an exception on end-of-stream.
15821 * - #readline: Returns the next line read from +self+;
15822 * same as #getline, but raises an exception of end-of-stream.
15823 * - #readlines: Returns an array of all lines read read from +self+.
15824 * - #readpartial: Returns up to the given number of bytes from +self+.
15825 *
15826 * === Writing
15827 *
15828 * - ::binwrite: Writes the given string to the file at the given filepath,
15829 * in binary mode.
15830 * - ::write: Writes the given string to +self+.
15831 * - #<<: Appends the given string to +self+.
15832 * - #print: Prints last read line or given objects to +self+.
15833 * - #printf: Writes to +self+ based on the given format string and objects.
15834 * - #putc: Writes a character to +self+.
15835 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15836 * - #pwrite: Writes the given string at the given offset,
15837 * not updating the receiver's offset.
15838 * - #write: Writes one or more given strings to +self+.
15839 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15840 *
15841 * === Positioning
15842 *
15843 * - #lineno: Returns the current line number in +self+.
15844 * - #lineno=: Sets the line number is +self+.
15845 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15846 * - #pos=: Sets the byte offset in +self+.
15847 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15848 * - #rewind: Positions +self+ to the beginning of input.
15849 * - #seek: Sets the offset for +self+ relative to given position.
15850 *
15851 * === Iterating
15852 *
15853 * - ::foreach: Yields each line of given file to the block.
15854 * - #each (aliased as #each_line): Calls the given block
15855 * with each successive line in +self+.
15856 * - #each_byte: Calls the given block with each successive byte in +self+
15857 * as an integer.
15858 * - #each_char: Calls the given block with each successive character in +self+
15859 * as a string.
15860 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15861 * as an integer.
15862 *
15863 * === Settings
15864 *
15865 * - #autoclose=: Sets whether +self+ auto-closes.
15866 * - #binmode: Sets +self+ to binary mode.
15867 * - #close: Closes +self+.
15868 * - #close_on_exec=: Sets the close-on-exec flag.
15869 * - #close_read: Closes +self+ for reading.
15870 * - #close_write: Closes +self+ for writing.
15871 * - #set_encoding: Sets the encoding for +self+.
15872 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15873 * Unicode byte-order-mark.
15874 * - #sync=: Sets the sync-mode to the given value.
15875 *
15876 * === Querying
15877 *
15878 * - #autoclose?: Returns whether +self+ auto-closes.
15879 * - #binmode?: Returns whether +self+ is in binary mode.
15880 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15881 * - #closed?: Returns whether +self+ is closed.
15882 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15883 * - #external_encoding: Returns the external encoding object for +self+.
15884 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15885 * - #internal_encoding: Returns the internal encoding object for +self+.
15886 * - #pid: Returns the process ID of a child process associated with +self+,
15887 * if +self+ was created by ::popen.
15888 * - #stat: Returns the File::Stat object containing status information for +self+.
15889 * - #sync: Returns whether +self+ is in sync-mode.
15890 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15891 *
15892 * === Buffering
15893 *
15894 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15895 * - #flush: Flushes any buffered data within +self+ to the underlying
15896 * operating system.
15897 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15898 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15899 * - #ungetc: Prepends buffer for +self+ with given string.
15900 *
15901 * === Low-Level Access
15902 *
15903 * - ::sysopen: Opens the file given by its path,
15904 * returning the integer file descriptor.
15905 * - #advise: Announces the intention to access data from +self+ in a specific way.
15906 * - #fcntl: Passes a low-level command to the file specified
15907 * by the given file descriptor.
15908 * - #ioctl: Passes a low-level command to the device specified
15909 * by the given file descriptor.
15910 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15911 * - #sysseek: Sets the offset for +self+.
15912 * - #syswrite: Writes the given string to +self+ using a low-level write.
15913 *
15914 * === Other
15915 *
15916 * - ::copy_stream: Copies data from a source to a destination,
15917 * each of which is a filepath or an \IO-like object.
15918 * - ::try_convert: Returns a new \IO object resulting from converting
15919 * the given object.
15920 * - #inspect: Returns the string representation of +self+.
15921 *
15922 */
15923
15924void
15925Init_IO(void)
15926{
15927 VALUE rb_cARGF;
15928#ifdef __CYGWIN__
15929#include <sys/cygwin.h>
15930 static struct __cygwin_perfile pf[] =
15931 {
15932 {"", O_RDONLY | O_BINARY},
15933 {"", O_WRONLY | O_BINARY},
15934 {"", O_RDWR | O_BINARY},
15935 {"", O_APPEND | O_BINARY},
15936 {NULL, 0}
15937 };
15938 cygwin_internal(CW_PERFILE, pf);
15939#endif
15940
15941 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15942 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15943
15944 id_write = rb_intern_const("write");
15945 id_read = rb_intern_const("read");
15946 id_flush = rb_intern_const("flush");
15947 id_readpartial = rb_intern_const("readpartial");
15948 id_set_encoding = rb_intern_const("set_encoding");
15949 id_fileno = rb_intern_const("fileno");
15950
15951 rb_define_global_function("syscall", rb_f_syscall, -1);
15952
15953 rb_define_global_function("open", rb_f_open, -1);
15954 rb_define_global_function("printf", rb_f_printf, -1);
15955 rb_define_global_function("print", rb_f_print, -1);
15956 rb_define_global_function("putc", rb_f_putc, 1);
15957 rb_define_global_function("puts", rb_f_puts, -1);
15958 rb_define_global_function("gets", rb_f_gets, -1);
15959 rb_define_global_function("readline", rb_f_readline, -1);
15960 rb_define_global_function("select", rb_f_select, -1);
15961
15962 rb_define_global_function("readlines", rb_f_readlines, -1);
15963
15964 rb_define_global_function("`", rb_f_backquote, 1);
15965
15966 rb_define_global_function("p", rb_f_p, -1);
15967 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15968
15969 rb_cIO = rb_define_class("IO", rb_cObject);
15971
15972 /* Can be raised by IO operations when IO#timeout= is set. */
15973 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15974
15975 /* Readable event mask for IO#wait. */
15976 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15977 /* Writable event mask for IO#wait. */
15978 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15979 /* Priority event mask for IO#wait. */
15980 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15981
15982 /* exception to wait for reading. see IO.select. */
15983 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15984 /* exception to wait for writing. see IO.select. */
15985 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15986 /* exception to wait for reading by EAGAIN. see IO.select. */
15987 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15988 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15989 /* exception to wait for writing by EAGAIN. see IO.select. */
15990 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15991 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15992#if EAGAIN == EWOULDBLOCK
15993 /* same as IO::EAGAINWaitReadable */
15994 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15995 /* same as IO::EAGAINWaitWritable */
15996 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15997#else
15998 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15999 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
16000 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
16001 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
16002 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
16003 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
16004#endif
16005 /* exception to wait for reading by EINPROGRESS. see IO.select. */
16006 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
16007 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
16008 /* exception to wait for writing by EINPROGRESS. see IO.select. */
16009 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
16010 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
16011
16012#if 0
16013 /* This is necessary only for forcing rdoc handle File::open */
16014 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
16015#endif
16016
16017 rb_define_alloc_func(rb_cIO, io_alloc);
16018 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
16019 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
16020 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
16021 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
16022 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
16023 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
16024 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
16025 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
16026 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
16027 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
16028 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
16029 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
16030 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
16031 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
16032 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
16033
16034 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
16035
16037 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
16038
16039 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
16040 rb_vm_register_global_object(rb_default_rs);
16041 rb_rs = rb_default_rs;
16043 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
16044 rb_gvar_ractor_local("$/"); // not local but ractor safe
16045 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
16046 rb_gvar_ractor_local("$-0"); // not local but ractor safe
16047 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
16048
16049 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
16050 rb_gvar_ractor_local("$_");
16051 rb_gvar_box_dynamic("$_");
16052
16053 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
16054 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
16055
16056 rb_define_method(rb_cIO, "print", rb_io_print, -1);
16057 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
16058 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
16059 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
16060
16061 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
16062 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
16063 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
16064 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
16065 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
16066
16067 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
16068 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
16069
16070 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
16071 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
16072
16073 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
16074 rb_define_alias(rb_cIO, "to_i", "fileno");
16075 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
16076
16077 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
16078 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
16079
16080 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
16081 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
16082 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
16083 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
16084
16085 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
16086 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
16087
16088 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
16089
16090 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
16091 rb_define_method(rb_cIO, "read", io_read, -1);
16092 rb_define_method(rb_cIO, "write", io_write_m, -1);
16093 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
16094 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
16095 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
16096 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
16097 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
16098 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
16099 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
16101 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
16102 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
16103 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
16104 /* Set I/O position from the beginning */
16105 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
16106 /* Set I/O position from the current position */
16107 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
16108 /* Set I/O position from the end */
16109 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
16110#ifdef SEEK_DATA
16111 /* Set I/O position to the next location containing data */
16112 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
16113#endif
16114#ifdef SEEK_HOLE
16115 /* Set I/O position to the next hole */
16116 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
16117#endif
16118 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
16119 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
16120 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
16121 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
16122 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
16123
16124 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
16125 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
16126
16127 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
16128 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
16129 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
16130 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
16131
16132 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
16133 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
16134 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
16135 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
16136 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
16137 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
16138
16139 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
16140 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
16141 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
16142
16143 rb_define_method(rb_cIO, "path", rb_io_path, 0);
16144 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
16145
16146 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
16147
16148 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
16149 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
16150 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
16151 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
16152
16153 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
16154 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
16155
16156 rb_define_method(rb_cIO, "wait", io_wait, -1);
16157
16158 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
16159 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
16160 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
16161
16162 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
16163 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
16164 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
16165 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
16166
16167 rb_gvar_ractor_local("$stdin");
16168 rb_gvar_ractor_local("$stdout");
16169 rb_gvar_ractor_local("$>");
16170 rb_gvar_ractor_local("$stderr");
16171
16172 rb_gvar_box_dynamic("$stdin");
16173 rb_gvar_box_dynamic("$stdout");
16174 rb_gvar_box_dynamic("$>");
16175 rb_gvar_box_dynamic("$stderr");
16176
16178 rb_stdin = rb_io_prep_stdin();
16180 rb_stdout = rb_io_prep_stdout();
16182 rb_stderr = rb_io_prep_stderr();
16183
16184 orig_stdout = rb_stdout;
16185 orig_stderr = rb_stderr;
16186
16187 /* Holds the original stdin */
16189 /* Holds the original stdout */
16191 /* Holds the original stderr */
16193
16194#if 0
16195 /* Hack to get rdoc to regard ARGF as a class: */
16196 rb_cARGF = rb_define_class("ARGF", rb_cObject);
16197#endif
16198
16199 rb_cARGF = rb_class_new(rb_cObject);
16200 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
16201 rb_define_alloc_func(rb_cARGF, argf_alloc);
16202
16204
16205 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
16206 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
16207 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
16208 rb_define_alias(rb_cARGF, "inspect", "to_s");
16209 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
16210
16211 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
16212 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
16213 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
16214 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
16215 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
16216 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
16217 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
16218 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
16219 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
16220
16221 rb_define_method(rb_cARGF, "read", argf_read, -1);
16222 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
16223 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
16224 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
16225 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
16226 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
16227 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
16228 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
16229 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
16230 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
16231 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
16232 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
16233 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
16234 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
16235 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
16236 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
16237 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
16238 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
16239 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
16240 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
16241
16242 rb_define_method(rb_cARGF, "write", argf_write, -1);
16243 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
16244 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
16245 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
16246 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
16247
16248 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
16249 rb_define_method(rb_cARGF, "path", argf_filename, 0);
16250 rb_define_method(rb_cARGF, "file", argf_file, 0);
16251 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
16252 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
16253 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
16254
16255 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
16256 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
16257
16258 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
16259 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
16260
16261 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
16262 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
16263 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
16264
16265 argf = rb_class_new_instance(0, 0, rb_cARGF);
16266
16268 /*
16269 * ARGF is a stream designed for use in scripts that process files given
16270 * as command-line arguments or passed in via STDIN.
16271 *
16272 * See ARGF (the class) for more details.
16273 */
16275
16276 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16277 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16278 ARGF_SET(filename, rb_str_new2("-"));
16279
16280 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16281 rb_gvar_ractor_local("$-i");
16282
16283 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16284
16285#if defined (_WIN32) || defined(__CYGWIN__)
16286 atexit(pipe_atexit);
16287#endif
16288
16289 Init_File();
16290
16291 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16292
16293 sym_mode = ID2SYM(rb_intern_const("mode"));
16294 sym_perm = ID2SYM(rb_intern_const("perm"));
16295 sym_flags = ID2SYM(rb_intern_const("flags"));
16296 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16297 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16298 sym_encoding = ID2SYM(rb_id_encoding());
16299 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16300 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16301 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16302 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16303 sym_normal = ID2SYM(rb_intern_const("normal"));
16304 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16305 sym_random = ID2SYM(rb_intern_const("random"));
16306 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16307 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16308 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16309 sym_SET = ID2SYM(rb_intern_const("SET"));
16310 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16311 sym_END = ID2SYM(rb_intern_const("END"));
16312#ifdef SEEK_DATA
16313 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16314#endif
16315#ifdef SEEK_HOLE
16316 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16317#endif
16318 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16319 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16320}
16321
16322static void init_builtin_io(void);
16323#define Init_builtin_io init_builtin_io
16324#include "io.rbinc"
16325#undef Init_builtin_io
16326
16327void
16328Init_builtin_io(void)
16329{
16330 init_builtin_io();
16331
16332 /* Init_IO is called earlier than `loaded_features` is initialized */
16333 rb_provide("io/wait.rb");
16334 rb_provide("io/wait.so");
16335}
#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:14993
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:14987
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2387
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c: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:2149
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2143
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
Definition proc.c:3761
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1161
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:676
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c: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:14953
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.