Ruby 4.1.0dev (2026-08-28 revision 5eb9a6925b805a17dced976d5b741afe5086aab1)
io.c (5eb9a6925b805a17dced976d5b741afe5086aab1)
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
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
248static rb_atomic_t max_file_descriptor = NOFILE;
249void
251{
252 rb_atomic_t afd = (rb_atomic_t)fd;
253 rb_atomic_t max_fd = max_file_descriptor;
254 int err;
255
256 if (fd < 0 || afd <= max_fd)
257 return;
258
259#if defined(HAVE_FCNTL) && defined(F_GETFL)
260 err = fcntl(fd, F_GETFL) == -1;
261#else
262 {
263 struct stat buf;
264 err = fstat(fd, &buf) != 0;
265 }
266#endif
267 if (err && errno == EBADF) {
268 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
269 }
270
271 while (max_fd < afd) {
272 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
273 }
274}
275
276void
277rb_maygvl_fd_fix_cloexec(int fd)
278{
279 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
280#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
281 int flags, flags2, ret;
282 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
283 if (flags == -1) {
284 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
285 }
286 if (fd <= 2)
287 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
288 else
289 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
290 if (flags != flags2) {
291 ret = fcntl(fd, F_SETFD, flags2);
292 if (ret != 0) {
293 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
294 }
295 }
296#endif
297}
298
299void
301{
302 rb_maygvl_fd_fix_cloexec(fd);
304}
305
306/* this is only called once */
307static int
308rb_fix_detect_o_cloexec(int fd)
309{
310#if defined(O_CLOEXEC) && defined(F_GETFD)
311 int flags = fcntl(fd, F_GETFD);
312
313 if (flags == -1)
314 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
315
316 if (flags & FD_CLOEXEC)
317 return 1;
318#endif /* fall through if O_CLOEXEC does not work: */
319 rb_maygvl_fd_fix_cloexec(fd);
320 return 0;
321}
322
323static inline bool
324io_again_p(int e)
325{
326 return (e == EWOULDBLOCK) || (e == EAGAIN);
327}
328
329int
330rb_cloexec_open(const char *pathname, int flags, mode_t mode)
331{
332 int ret;
333 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
334
335 static const int retry_interval = 0;
336 static const int retry_max_count = 10000;
337
338 int retry_count = 0;
339
340#ifdef O_CLOEXEC
341 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
342 flags |= O_CLOEXEC;
343#elif defined O_NOINHERIT
344 flags |= O_NOINHERIT;
345#endif
346
347 while ((ret = open(pathname, flags, mode)) == -1) {
348 int e = errno;
349 if (!io_again_p(e)) break;
350 if (retry_count++ >= retry_max_count) break;
351
352 sleep(retry_interval);
353 }
354
355 if (ret < 0) return ret;
356 if (ret <= 2 || o_cloexec_state == 0) {
357 rb_maygvl_fd_fix_cloexec(ret);
358 }
359 else if (o_cloexec_state > 0) {
360 return ret;
361 }
362 else {
363 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
364 }
365 return ret;
366}
367
368int
370{
371 /* Don't allocate standard file descriptors: 0, 1, 2 */
372 return rb_cloexec_fcntl_dupfd(oldfd, 3);
373}
374
375int
376rb_cloexec_dup2(int oldfd, int newfd)
377{
378 int ret;
379
380 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
381 * rb_cloexec_dup2 succeeds as dup2. */
382 if (oldfd == newfd) {
383 ret = newfd;
384 }
385 else {
386#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
387 static int try_dup3 = 1;
388 if (2 < newfd && try_dup3) {
389 ret = dup3(oldfd, newfd, O_CLOEXEC);
390 if (ret != -1)
391 return ret;
392 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
393 if (errno == ENOSYS) {
394 try_dup3 = 0;
395 ret = dup2(oldfd, newfd);
396 }
397 }
398 else {
399 ret = dup2(oldfd, newfd);
400 }
401#else
402 ret = dup2(oldfd, newfd);
403#endif
404 if (ret < 0) return ret;
405 }
406 rb_maygvl_fd_fix_cloexec(ret);
407 return ret;
408}
409
410static int
411rb_fd_set_nonblock(int fd)
412{
413#ifdef _WIN32
414 return rb_w32_set_nonblock(fd);
415#elif defined(F_GETFL)
416 int oflags = fcntl(fd, F_GETFL);
417
418 if (oflags == -1)
419 return -1;
420 if (oflags & O_NONBLOCK)
421 return 0;
422 oflags |= O_NONBLOCK;
423 return fcntl(fd, F_SETFL, oflags);
424#endif
425 return 0;
426}
427
428int
429rb_cloexec_pipe(int descriptors[2])
430{
431#ifdef HAVE_PIPE2
432 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
433#else
434 int result = pipe(descriptors);
435#endif
436
437 if (result < 0)
438 return result;
439
440#ifdef __CYGWIN__
441 if (result == 0 && descriptors[1] == -1) {
442 close(descriptors[0]);
443 descriptors[0] = -1;
444 errno = ENFILE;
445 return -1;
446 }
447#endif
448
449#ifndef HAVE_PIPE2
450 rb_maygvl_fd_fix_cloexec(descriptors[0]);
451 rb_maygvl_fd_fix_cloexec(descriptors[1]);
452
453#ifndef _WIN32
454 rb_fd_set_nonblock(descriptors[0]);
455 rb_fd_set_nonblock(descriptors[1]);
456#endif
457#endif
458
459 return result;
460}
461
462int
463rb_cloexec_fcntl_dupfd(int fd, int minfd)
464{
465 int ret;
466
467#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
468 static int try_dupfd_cloexec = 1;
469 if (try_dupfd_cloexec) {
470 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
471 if (ret != -1) {
472 if (ret <= 2)
473 rb_maygvl_fd_fix_cloexec(ret);
474 return ret;
475 }
476 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
477 if (errno == EINVAL) {
478 ret = fcntl(fd, F_DUPFD, minfd);
479 if (ret != -1) {
480 try_dupfd_cloexec = 0;
481 }
482 }
483 }
484 else {
485 ret = fcntl(fd, F_DUPFD, minfd);
486 }
487#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
488 ret = fcntl(fd, F_DUPFD, minfd);
489#else
490 ret = dup(fd);
491 if (ret >= 0 && ret < minfd) {
492 const int prev_fd = ret;
493 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
494 close(prev_fd);
495 }
496 return ret;
497#endif
498 if (ret < 0) return ret;
499 rb_maygvl_fd_fix_cloexec(ret);
500 return ret;
501}
502
503#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
504#define ARGF argf_of(argf)
505#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
506
507#define GetWriteIO(io) rb_io_get_write_io(io)
508
509#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
510#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
511#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
512#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
513
514#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
515#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
516#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
517
518#if defined(_WIN32)
519#define WAIT_FD_IN_WIN32(fptr) \
520 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
521#else
522#define WAIT_FD_IN_WIN32(fptr)
523#endif
524
525#define READ_CHECK(fptr) do {\
526 if (!READ_DATA_PENDING(fptr)) {\
527 WAIT_FD_IN_WIN32(fptr);\
528 rb_io_check_closed(fptr);\
529 }\
530} while(0)
531
532#ifndef S_ISSOCK
533# ifdef _S_ISSOCK
534# define S_ISSOCK(m) _S_ISSOCK(m)
535# else
536# ifdef _S_IFSOCK
537# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
538# else
539# ifdef S_IFSOCK
540# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
541# endif
542# endif
543# endif
544#endif
545
546static int io_fflush(rb_io_t *);
547static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
548static void clear_readconv(rb_io_t *fptr);
549static void clear_codeconv(rb_io_t *fptr);
550
551#define FMODE_SIGNAL_ON_EPIPE (1<<17)
552
553#define fptr_signal_on_epipe(fptr) \
554 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
555
556#define fptr_set_signal_on_epipe(fptr, flag) \
557 ((flag) ? \
558 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
559 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
560
561extern ID ruby_static_id_signo;
562
563NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
564static void
565rb_sys_fail_on_write(rb_io_t *fptr)
566{
567 int e = errno;
568 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
569#if defined EPIPE
570 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
571 const VALUE sig =
572# if defined SIGPIPE
573 INT2FIX(SIGPIPE) - INT2FIX(0) +
574# endif
575 INT2FIX(0);
576 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
577 }
578#endif
579 rb_exc_raise(errinfo);
580}
581
582#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
583#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
584#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
585# define RUBY_CRLF_ENVIRONMENT 1
586#else
587# define RUBY_CRLF_ENVIRONMENT 0
588#endif
589
590#if RUBY_CRLF_ENVIRONMENT
591/* Windows */
592# define DEFAULT_TEXTMODE FMODE_TEXTMODE
593# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
594/*
595 * CRLF newline is set as default newline decorator.
596 * If only CRLF newline conversion is needed, we use binary IO process
597 * with OS's text mode for IO performance improvement.
598 * If encoding conversion is needed or a user sets text mode, we use encoding
599 * conversion IO process and universal newline decorator by default.
600 */
601#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
602#define WRITECONV_MASK ( \
603 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
604 ECONV_STATEFUL_DECORATOR_MASK|\
605 0)
606#define NEED_WRITECONV(fptr) ( \
607 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
608 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
609 0)
610#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
611
612#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
613 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
614 if (((fptr)->mode & FMODE_READABLE) &&\
615 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
616 setmode((fptr)->fd, O_BINARY);\
617 }\
618 else {\
619 setmode((fptr)->fd, O_TEXT);\
620 }\
621 }\
622} while(0)
623
624#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
625 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
626 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
627 }\
628} while(0)
629
630/*
631 * IO unread with taking care of removed '\r' in text mode.
632 */
633static void
634io_unread(rb_io_t *fptr, bool discard_rbuf)
635{
636 rb_off_t r, pos;
637 ssize_t read_size;
638 long i;
639 long newlines = 0;
640 long extra_max;
641 char *p;
642 char *buf;
643
644 rb_io_check_closed(fptr);
645 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
646 return;
647 }
648
649 errno = 0;
650 if (!rb_w32_fd_is_text(fptr->fd)) {
651 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
652 if (r < 0 && errno) {
653 if (errno == ESPIPE)
654 fptr->mode |= FMODE_DUPLEX;
655 if (!discard_rbuf) return;
656 }
657
658 goto end;
659 }
660
661 pos = lseek(fptr->fd, 0, SEEK_CUR);
662 if (pos < 0 && errno) {
663 if (errno == ESPIPE)
664 fptr->mode |= FMODE_DUPLEX;
665 if (!discard_rbuf) goto end;
666 }
667
668 /* add extra offset for removed '\r' in rbuf */
669 extra_max = (long)(pos - fptr->rbuf.len);
670 p = fptr->rbuf.ptr + fptr->rbuf.off;
671
672 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
673 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
674 newlines++;
675 }
676
677 for (i = 0; i < fptr->rbuf.len; i++) {
678 if (*p == '\n') newlines++;
679 if (extra_max == newlines) break;
680 p++;
681 }
682
683 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
684 while (newlines >= 0) {
685 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
686 if (newlines == 0) break;
687 if (r < 0) {
688 newlines--;
689 continue;
690 }
691 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
692 if (read_size < 0) {
693 int e = errno;
694 free(buf);
695 rb_syserr_fail_path(e, fptr->pathv);
696 }
697 if (read_size == fptr->rbuf.len) {
698 lseek(fptr->fd, r, SEEK_SET);
699 break;
700 }
701 else {
702 newlines--;
703 }
704 }
705 free(buf);
706 end:
707 fptr->rbuf.off = 0;
708 fptr->rbuf.len = 0;
709 clear_codeconv(fptr);
710 return;
711}
712
713/*
714 * We use io_seek to back cursor position when changing mode from text to binary,
715 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
716 * conversion for working properly with mode change.
717 *
718 * Return previous translation mode.
719 */
720static inline int
721set_binary_mode_with_seek_cur(rb_io_t *fptr)
722{
723 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
724
725 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
726 return setmode(fptr->fd, O_BINARY);
727 }
728 flush_before_seek(fptr, false);
729 return setmode(fptr->fd, O_BINARY);
730}
731#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
732
733#else
734/* Unix */
735# define DEFAULT_TEXTMODE 0
736#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
737#define NEED_WRITECONV(fptr) ( \
738 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
739 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
740 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
741 0)
742#define SET_BINARY_MODE(fptr) (void)(fptr)
743#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
744#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
745#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
746#endif
747
748#if !defined HAVE_SHUTDOWN && !defined shutdown
749#define shutdown(a,b) 0
750#endif
751
752#if defined(_WIN32)
753#define is_socket(fd, path) rb_w32_is_socket(fd)
754#elif !defined(S_ISSOCK)
755#define is_socket(fd, path) 0
756#else
757static int
758is_socket(int fd, VALUE path)
759{
760 struct stat sbuf;
761 if (fstat(fd, &sbuf) < 0)
762 rb_sys_fail_path(path);
763 return S_ISSOCK(sbuf.st_mode);
764}
765#endif
766
767static const char closed_stream[] = "closed stream";
768
769static void
770io_fd_check_closed(int fd)
771{
772 if (fd < 0) {
773 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
774 rb_raise(rb_eIOError, closed_stream);
775 }
776}
777
778void
779rb_eof_error(void)
780{
781 rb_raise(rb_eEOFError, "end of file reached");
782}
783
784VALUE
786{
787 rb_check_frozen(io);
788 return io;
789}
790
791void
793{
794 if (!fptr) {
795 rb_raise(rb_eIOError, "uninitialized stream");
796 }
797}
798
799void
801{
803 io_fd_check_closed(fptr->fd);
804}
805
806static rb_io_t *
807rb_io_get_fptr(VALUE io)
808{
809 rb_io_t *fptr = RFILE(io)->fptr;
811 return fptr;
812}
813
814VALUE
816{
817 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
818}
819
820VALUE
822{
823 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
824}
825
826VALUE
828{
829 VALUE write_io;
830 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
831 if (write_io) {
832 return write_io;
833 }
834 return io;
835}
836
837VALUE
839{
840 VALUE write_io;
841 rb_io_t *fptr = rb_io_get_fptr(io);
842 if (!RTEST(w)) {
843 w = 0;
844 }
845 else {
846 GetWriteIO(w);
847 }
848 write_io = fptr->tied_io_for_writing;
849 fptr->tied_io_for_writing = w;
850 return write_io ? write_io : Qnil;
851}
852
853/*
854 * call-seq:
855 * timeout -> duration or nil
856 *
857 * Get the internal timeout duration or nil if it was not set.
858 *
859 */
860VALUE
862{
863 rb_io_t *fptr = rb_io_get_fptr(self);
864
865 return fptr->timeout;
866}
867
868/*
869 * call-seq:
870 * timeout = duration -> duration
871 * timeout = nil -> nil
872 *
873 * Sets the internal timeout to the specified duration or nil. The timeout
874 * applies to all blocking operations where possible.
875 *
876 * When the operation performs longer than the timeout set, IO::TimeoutError
877 * is raised.
878 *
879 * This affects the following methods (but is not limited to): #gets, #puts,
880 * #read, #write, #wait_readable and #wait_writable. This also affects
881 * blocking socket operations like Socket#accept and Socket#connect.
882 *
883 * Some operations like File#open and IO#close are not affected by the
884 * timeout. A timeout during a write operation may leave the IO in an
885 * inconsistent state, e.g. data was partially written. Generally speaking, a
886 * timeout is a last ditch effort to prevent an application from hanging on
887 * slow I/O operations, such as those that occur during a slowloris attack.
888 */
889VALUE
891{
892 // Validate it:
893 if (RTEST(timeout)) {
894 rb_time_interval(timeout);
895 }
896
897 rb_io_t *fptr = rb_io_get_fptr(self);
898
899 RB_OBJ_WRITE(self, &fptr->timeout, timeout);
900
901 return self;
902}
903
904/*
905 * call-seq:
906 * IO.try_convert(object) -> new_io or nil
907 *
908 * Attempts to convert +object+ into an \IO object via method +to_io+;
909 * returns the new \IO object if successful, or +nil+ otherwise:
910 *
911 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
912 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
913 * IO.try_convert('STDOUT') # => nil
914 *
915 */
916static VALUE
917rb_io_s_try_convert(VALUE dummy, VALUE io)
918{
919 return rb_io_check_io(io);
920}
921
922#if !RUBY_CRLF_ENVIRONMENT
923static void
924io_unread(rb_io_t *fptr, bool discard_rbuf)
925{
926 rb_off_t r;
927 rb_io_check_closed(fptr);
928 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
929 return;
930 /* xxx: target position may be negative if buffer is filled by ungetc */
931 errno = 0;
932 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
933 if (r < 0 && errno) {
934 if (errno == ESPIPE)
935 fptr->mode |= FMODE_DUPLEX;
936 if (!discard_rbuf) return;
937 }
938 fptr->rbuf.off = 0;
939 fptr->rbuf.len = 0;
940 clear_codeconv(fptr);
941 return;
942}
943#endif
944
945static rb_encoding *io_input_encoding(rb_io_t *fptr);
946
947static void
948io_ungetbyte(VALUE str, rb_io_t *fptr)
949{
950 long len = RSTRING_LEN(str);
951
952 if (fptr->rbuf.ptr == NULL) {
953 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
954 fptr->rbuf.off = 0;
955 fptr->rbuf.len = 0;
956#if SIZEOF_LONG > SIZEOF_INT
957 if (len > INT_MAX)
958 rb_raise(rb_eIOError, "ungetbyte failed");
959#endif
960 if (len > min_capa)
961 fptr->rbuf.capa = (int)len;
962 else
963 fptr->rbuf.capa = min_capa;
964 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
965 }
966 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
967 rb_raise(rb_eIOError, "ungetbyte failed");
968 }
969 if (fptr->rbuf.off < len) {
970 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
971 fptr->rbuf.ptr+fptr->rbuf.off,
972 char, fptr->rbuf.len);
973 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
974 }
975 fptr->rbuf.off-=(int)len;
976 fptr->rbuf.len+=(int)len;
977 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
978}
979
980static rb_io_t *
981flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
982{
983 if (io_fflush(fptr) < 0)
984 rb_sys_fail_on_write(fptr);
985 io_unread(fptr, discard_rbuf);
986 errno = 0;
987 return fptr;
988}
989
990#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
991#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
992
993#ifndef SEEK_CUR
994# define SEEK_SET 0
995# define SEEK_CUR 1
996# define SEEK_END 2
997#endif
998
999void
1001{
1002 rb_io_check_closed(fptr);
1003 if (!(fptr->mode & FMODE_READABLE)) {
1004 rb_raise(rb_eIOError, "not opened for reading");
1005 }
1006 if (fptr->wbuf.len) {
1007 if (io_fflush(fptr) < 0)
1008 rb_sys_fail_on_write(fptr);
1009 }
1010 if (fptr->tied_io_for_writing) {
1011 rb_io_t *wfptr;
1012 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1013 if (io_fflush(wfptr) < 0)
1014 rb_sys_fail_on_write(wfptr);
1015 }
1016}
1017
1018void
1020{
1022 if (READ_CHAR_PENDING(fptr)) {
1023 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1024 }
1025}
1026
1027void
1032
1033static rb_encoding*
1034io_read_encoding(rb_io_t *fptr)
1035{
1036 if (fptr->encs.enc) {
1037 return fptr->encs.enc;
1038 }
1039 return rb_default_external_encoding();
1040}
1041
1042static rb_encoding*
1043io_input_encoding(rb_io_t *fptr)
1044{
1045 if (fptr->encs.enc2) {
1046 return fptr->encs.enc2;
1047 }
1048 return io_read_encoding(fptr);
1049}
1050
1051void
1053{
1054 rb_io_check_closed(fptr);
1055 if (!(fptr->mode & FMODE_WRITABLE)) {
1056 rb_raise(rb_eIOError, "not opened for writing");
1057 }
1058 if (fptr->rbuf.len) {
1059 io_unread(fptr, true);
1060 }
1061}
1062
1063int
1064rb_io_read_pending(rb_io_t *fptr)
1065{
1066 /* This function is used for bytes and chars. Confusing. */
1067 if (READ_CHAR_PENDING(fptr))
1068 return 1; /* should raise? */
1069 return READ_DATA_PENDING(fptr);
1070}
1071
1072void
1074{
1075 if (!READ_DATA_PENDING(fptr)) {
1076 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1077 }
1078 return;
1079}
1080
1081int
1082rb_gc_for_fd(int err)
1083{
1084 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1085 rb_gc();
1086 return 1;
1087 }
1088 return 0;
1089}
1090
1091/* try `expr` upto twice while it returns false and `errno`
1092 * is to GC. Each `errno`s are available as `first_errno` and
1093 * `retried_errno` respectively */
1094#define TRY_WITH_GC(expr) \
1095 for (int first_errno, retried_errno = 0, retried = 0; \
1096 (!retried && \
1097 !(expr) && \
1098 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1099 (retried_errno = errno, 1)); \
1100 (void)retried_errno, retried = 1)
1101
1102static int
1103ruby_dup(int orig)
1104{
1105 int fd = -1;
1106
1107 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1108 rb_syserr_fail(first_errno, 0);
1109 }
1110 rb_update_max_fd(fd);
1111 return fd;
1112}
1113
1114static VALUE
1115io_alloc(VALUE klass)
1116{
1117 UNPROTECTED_NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile));
1118
1119 io->fptr = 0;
1120
1121 return (VALUE)io;
1122}
1123
1124#ifndef S_ISREG
1125# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1126#endif
1127
1129 VALUE th;
1130 rb_io_t *fptr;
1131 int nonblock;
1132 int fd;
1133
1134 void *buf;
1135 size_t capa;
1136 struct timeval *timeout;
1137};
1138
1140 VALUE th;
1141 rb_io_t *fptr;
1142 int nonblock;
1143 int fd;
1144
1145 const void *buf;
1146 size_t capa;
1147 struct timeval *timeout;
1148};
1149
1150#ifdef HAVE_WRITEV
1151struct io_internal_writev_struct {
1152 VALUE th;
1153 rb_io_t *fptr;
1154 int nonblock;
1155 int fd;
1156
1157 int iovcnt;
1158 const struct iovec *iov;
1159 struct timeval *timeout;
1160};
1161#endif
1162
1163static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1164
1170static inline int
1171io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1172{
1173 if (!timeout && rb_thread_mn_schedulable(thread)) {
1174 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1175 return -1;
1176 }
1177
1178 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1179
1180 if (ready > 0) {
1181 return ready;
1182 }
1183 else if (ready == 0) {
1184 errno = ETIMEDOUT;
1185 return -1;
1186 }
1187
1188 // If there was an error BEFORE we started waiting, return it:
1189 if (error) {
1190 errno = error;
1191 return -1;
1192 }
1193 else {
1194 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1195 return ready;
1196 }
1197}
1198
1199static VALUE
1200internal_read_func(void *ptr)
1201{
1202 struct io_internal_read_struct *iis = ptr;
1203 ssize_t result;
1204
1205 if (iis->timeout && !iis->nonblock) {
1206 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1207 return -1;
1208 }
1209 }
1210
1211 retry:
1212 result = read(iis->fd, iis->buf, iis->capa);
1213
1214 if (result < 0 && !iis->nonblock) {
1215 if (io_again_p(errno)) {
1216 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1217 return -1;
1218 }
1219 else {
1220 goto retry;
1221 }
1222 }
1223 }
1224
1225 return result;
1226}
1227
1228#if defined __APPLE__
1229# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1230#else
1231# define do_write_retry(code) result = code
1232#endif
1233
1234static VALUE
1235internal_write_func(void *ptr)
1236{
1237 struct io_internal_write_struct *iis = ptr;
1238 ssize_t result;
1239
1240 if (iis->timeout && !iis->nonblock) {
1241 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1242 return -1;
1243 }
1244 }
1245
1246 retry:
1247 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1248
1249 if (result < 0 && !iis->nonblock) {
1250 int e = errno;
1251 if (io_again_p(e)) {
1252 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1253 return -1;
1254 }
1255 else {
1256 goto retry;
1257 }
1258 }
1259 }
1260
1261 return result;
1262}
1263
1264#ifdef HAVE_WRITEV
1265static VALUE
1266internal_writev_func(void *ptr)
1267{
1268 struct io_internal_writev_struct *iis = ptr;
1269 ssize_t result;
1270
1271 if (iis->timeout && !iis->nonblock) {
1272 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1273 return -1;
1274 }
1275 }
1276
1277 retry:
1278 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1279
1280 if (result < 0 && !iis->nonblock) {
1281 if (io_again_p(errno)) {
1282 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1283 return -1;
1284 }
1285 else {
1286 goto retry;
1287 }
1288 }
1289 }
1290
1291 return result;
1292}
1293#endif
1294
1295static ssize_t
1296rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1297{
1298 rb_thread_t *th = GET_THREAD();
1300 if (scheduler != Qnil) {
1301 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count);
1302
1303 if (!UNDEF_P(result)) {
1305 }
1306 }
1307
1308 struct io_internal_read_struct iis = {
1309 .th = th->self,
1310 .fptr = fptr,
1311 .nonblock = 0,
1312 .fd = fptr->fd,
1313
1314 .buf = buf,
1315 .capa = count,
1316 .timeout = NULL,
1317 };
1318
1319 struct timeval timeout_storage;
1320
1321 if (fptr->timeout != Qnil) {
1322 timeout_storage = rb_time_interval(fptr->timeout);
1323 iis.timeout = &timeout_storage;
1324 }
1325
1326 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1327}
1328
1329static ssize_t
1330rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1331{
1332 rb_thread_t *th = GET_THREAD();
1334 if (scheduler != Qnil) {
1335 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count);
1336
1337 if (!UNDEF_P(result)) {
1339 }
1340 }
1341
1342 struct io_internal_write_struct iis = {
1343 .th = th->self,
1344 .fptr = fptr,
1345 .nonblock = 0,
1346 .fd = fptr->fd,
1347
1348 .buf = buf,
1349 .capa = count,
1350 .timeout = NULL
1351 };
1352
1353 struct timeval timeout_storage;
1354
1355 if (fptr->timeout != Qnil) {
1356 timeout_storage = rb_time_interval(fptr->timeout);
1357 iis.timeout = &timeout_storage;
1358 }
1359
1360 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1361}
1362
1363#ifdef HAVE_WRITEV
1364static ssize_t
1365rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1366{
1367 if (!iovcnt) return 0;
1368
1369 rb_thread_t *th = GET_THREAD();
1370
1372 if (scheduler != Qnil) {
1373 // This path assumes at least one `iov`:
1374 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len);
1375
1376 if (!UNDEF_P(result)) {
1378 }
1379 }
1380
1381 struct io_internal_writev_struct iis = {
1382 .th = th->self,
1383 .fptr = fptr,
1384 .nonblock = 0,
1385 .fd = fptr->fd,
1386
1387 .iov = iov,
1388 .iovcnt = iovcnt,
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_writev_func, &iis, RUBY_IO_WRITABLE);
1400}
1401#endif
1402
1403static VALUE
1404io_flush_buffer_sync(void *arg)
1405{
1406 rb_io_t *fptr = arg;
1407 long l = fptr->wbuf.len;
1408 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1409
1410 if (fptr->wbuf.len <= r) {
1411 fptr->wbuf.off = 0;
1412 fptr->wbuf.len = 0;
1413 return 0;
1414 }
1415
1416 if (0 <= r) {
1417 fptr->wbuf.off += (int)r;
1418 fptr->wbuf.len -= (int)r;
1419 errno = EAGAIN;
1420 }
1421
1422 return (VALUE)-1;
1423}
1424
1425static inline VALUE
1426io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
1427{
1428 VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len);
1429 if (!UNDEF_P(ret)) {
1430 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1431 if (result > 0) {
1432 fptr->wbuf.off += result;
1433 fptr->wbuf.len -= result;
1434 }
1435 return result >= 0 ? (VALUE)0 : (VALUE)-1;
1436 }
1437 return ret;
1438}
1439
1440static VALUE
1441io_flush_buffer_async(VALUE arg)
1442{
1443 rb_io_t *fptr = (rb_io_t *)arg;
1444
1445 VALUE scheduler = rb_fiber_scheduler_current();
1446 if (scheduler != Qnil) {
1447 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1448 if (!UNDEF_P(result)) {
1449 return result;
1450 }
1451 }
1452
1453 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1454}
1455
1456static inline int
1457io_flush_buffer(rb_io_t *fptr)
1458{
1459 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1460 return (int)io_flush_buffer_async((VALUE)fptr);
1461 }
1462 else {
1463 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1464 }
1465}
1466
1467static int
1468io_fflush(rb_io_t *fptr)
1469{
1470 rb_io_check_closed(fptr);
1471
1472 if (fptr->wbuf.len == 0)
1473 return 0;
1474
1475 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1476 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1477 return -1;
1478
1479 rb_io_check_closed(fptr);
1480 }
1481
1482 return 0;
1483}
1484
1485VALUE
1486rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1487{
1488 rb_thread_t *th = GET_THREAD();
1490
1491 if (scheduler != Qnil) {
1492 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1493 }
1494
1495 rb_io_t * fptr = NULL;
1496 RB_IO_POINTER(io, fptr);
1497
1498 struct timeval tv_storage;
1499 struct timeval *tv = NULL;
1500
1501 if (NIL_OR_UNDEF_P(timeout)) {
1502 timeout = fptr->timeout;
1503 }
1504
1505 if (timeout != Qnil) {
1506 tv_storage = rb_time_interval(timeout);
1507 tv = &tv_storage;
1508 }
1509
1510 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1511
1512 if (ready < 0) {
1513 rb_sys_fail(0);
1514 }
1515
1516 // Not sure if this is necessary:
1517 rb_io_check_closed(fptr);
1518
1519 if (ready) {
1520 return RB_INT2NUM(ready);
1521 }
1522 else {
1523 return Qfalse;
1524 }
1525}
1526
1527static VALUE
1528io_from_fd(int fd)
1529{
1530 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1531}
1532
1533static int
1534io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1535{
1536 if (scheduler != Qnil) {
1537 return RTEST(
1538 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1539 );
1540 }
1541
1542 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1543}
1544
1545int
1547{
1548 io_fd_check_closed(f);
1549
1550 rb_thread_t *th = GET_THREAD();
1552
1553 switch (errno) {
1554 case EINTR:
1555#if defined(ERESTART)
1556 case ERESTART:
1557#endif
1559 return TRUE;
1560
1561 case EAGAIN:
1562#if EWOULDBLOCK != EAGAIN
1563 case EWOULDBLOCK:
1564#endif
1565 if (scheduler != Qnil) {
1566 return RTEST(
1567 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1568 );
1569 }
1570 else {
1571 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1572 }
1573 return TRUE;
1574
1575 default:
1576 return FALSE;
1577 }
1578}
1579
1580int
1582{
1583 io_fd_check_closed(f);
1584
1585 rb_thread_t *th = GET_THREAD();
1587
1588 switch (errno) {
1589 case EINTR:
1590#if defined(ERESTART)
1591 case ERESTART:
1592#endif
1593 /*
1594 * In old Linux, several special files under /proc and /sys don't handle
1595 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1596 * Otherwise, we face nasty hang up. Sigh.
1597 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1598 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1599 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1600 * Then rb_thread_check_ints() is enough.
1601 */
1603 return TRUE;
1604
1605 case EAGAIN:
1606#if EWOULDBLOCK != EAGAIN
1607 case EWOULDBLOCK:
1608#endif
1609 if (scheduler != Qnil) {
1610 return RTEST(
1611 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1612 );
1613 }
1614 else {
1615 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1616 }
1617 return TRUE;
1618
1619 default:
1620 return FALSE;
1621 }
1622}
1623
1624int
1625rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1626{
1627 rb_thread_t *th = GET_THREAD();
1629 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1630}
1631
1632int
1634{
1635 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1636}
1637
1638int
1640{
1641 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1642}
1643
1644VALUE
1645rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1646{
1647 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1648 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1649 // instead relies on `read(-1) -> -1` which causes this code path. We then
1650 // check here whether the IO was in fact closed. Probably it's better to
1651 // check that `fptr->fd != -1` before using it in syscall.
1652 rb_io_check_closed(RFILE(io)->fptr);
1653
1654 switch (error) {
1655 // In old Linux, several special files under /proc and /sys don't handle
1656 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1657 // Otherwise, we face nasty hang up. Sigh.
1658 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1659 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1660 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1661 // Then rb_thread_check_ints() is enough.
1662 case EINTR:
1663#if defined(ERESTART)
1664 case ERESTART:
1665#endif
1666 // We might have pending interrupts since the previous syscall was interrupted:
1668
1669 // The operation was interrupted, so retry it immediately:
1670 return events;
1671
1672 case EAGAIN:
1673#if EWOULDBLOCK != EAGAIN
1674 case EWOULDBLOCK:
1675#endif
1676 // The operation would block, so wait for the specified events:
1677 return rb_io_wait(io, events, timeout);
1678
1679 default:
1680 // Non-specific error, no event is ready:
1681 return Qnil;
1682 }
1683}
1684
1685int
1687{
1688 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1689
1690 if (RTEST(result)) {
1691 return RB_NUM2INT(result);
1692 }
1693 else if (result == RUBY_Qfalse) {
1694 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1695 }
1696
1697 return 0;
1698}
1699
1700int
1702{
1703 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1704
1705 if (RTEST(result)) {
1706 return RB_NUM2INT(result);
1707 }
1708 else if (result == RUBY_Qfalse) {
1709 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1710 }
1711
1712 return 0;
1713}
1714
1715static void
1716make_writeconv(rb_io_t *fptr)
1717{
1718 if (!fptr->writeconv_initialized) {
1719 const char *senc, *denc;
1720 rb_encoding *enc;
1721 int ecflags;
1722 VALUE ecopts;
1723
1724 fptr->writeconv_initialized = 1;
1725
1726 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1727 ecopts = fptr->encs.ecopts;
1728
1729 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1730 /* no encoding conversion */
1731 fptr->writeconv_pre_ecflags = 0;
1732 fptr->writeconv_pre_ecopts = Qnil;
1733 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1734 if (!fptr->writeconv)
1735 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1737 }
1738 else {
1739 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1740 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1741 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1742 /* single conversion */
1743 fptr->writeconv_pre_ecflags = ecflags;
1744 fptr->writeconv_pre_ecopts = ecopts;
1745 fptr->writeconv = NULL;
1747 }
1748 else {
1749 /* double conversion */
1750 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1751 fptr->writeconv_pre_ecopts = ecopts;
1752 if (senc) {
1753 denc = rb_enc_name(enc);
1754 fptr->writeconv_asciicompat = rb_str_new2(senc);
1755 }
1756 else {
1757 senc = denc = "";
1758 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1759 }
1761 ecopts = fptr->encs.ecopts;
1762 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1763 if (!fptr->writeconv)
1764 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1765 }
1766 }
1767 }
1768}
1769
1770/* writing functions */
1772 rb_io_t *fptr;
1773 const char *ptr;
1774 long length;
1775};
1776
1778 VALUE io;
1779 VALUE str;
1780 int nosync;
1781};
1782
1783#ifdef HAVE_WRITEV
1784static ssize_t
1785io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1786{
1787 if (fptr->wbuf.len) {
1788 struct iovec iov[2];
1789
1790 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1791 iov[0].iov_len = fptr->wbuf.len;
1792 iov[1].iov_base = (void*)ptr;
1793 iov[1].iov_len = length;
1794
1795 ssize_t result = rb_writev_internal(fptr, iov, 2);
1796
1797 if (result < 0)
1798 return result;
1799
1800 if (result >= fptr->wbuf.len) {
1801 // We wrote more than the internal buffer:
1802 result -= fptr->wbuf.len;
1803 fptr->wbuf.off = 0;
1804 fptr->wbuf.len = 0;
1805 }
1806 else {
1807 // We only wrote less data than the internal buffer:
1808 fptr->wbuf.off += (int)result;
1809 fptr->wbuf.len -= (int)result;
1810
1811 result = 0;
1812 }
1813
1814 return result;
1815 }
1816 else {
1817 return rb_io_write_memory(fptr, ptr, length);
1818 }
1819}
1820#else
1821static ssize_t
1822io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1823{
1824 long remaining = length;
1825
1826 if (fptr->wbuf.len) {
1827 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1828 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1829 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1830 fptr->wbuf.off = 0;
1831 }
1832
1833 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1834 fptr->wbuf.len += (int)length;
1835
1836 // We copied the entire incoming data to the internal buffer:
1837 remaining = 0;
1838 }
1839
1840 // Flush the internal buffer:
1841 if (io_fflush(fptr) < 0) {
1842 return -1;
1843 }
1844
1845 // If all the data was buffered, we are done:
1846 if (remaining == 0) {
1847 return length;
1848 }
1849 }
1850
1851 // Otherwise, we should write the data directly:
1852 return rb_io_write_memory(fptr, ptr, length);
1853}
1854#endif
1855
1856static VALUE
1857io_binwrite_string(VALUE arg)
1858{
1859 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1860
1861 const char *ptr = p->ptr;
1862 size_t remaining = p->length;
1863
1864 while (remaining) {
1865 // Write as much as possible:
1866 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1867
1868 if (result == 0) {
1869 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1870 // should try again immediately.
1871 }
1872 else if (result > 0) {
1873 if ((size_t)result == remaining) break;
1874 ptr += result;
1875 remaining -= result;
1876 }
1877 // Wait for it to become writable:
1878 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1879 rb_io_check_closed(p->fptr);
1880 }
1881 else {
1882 // The error was unrelated to waiting for it to become writable, so we fail:
1883 return -1;
1884 }
1885 }
1886
1887 return p->length;
1888}
1889
1890inline static void
1891io_allocate_write_buffer(rb_io_t *fptr, int sync)
1892{
1893 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1894 fptr->wbuf.off = 0;
1895 fptr->wbuf.len = 0;
1896 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1897 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1898 }
1899
1900 if (NIL_P(fptr->write_lock)) {
1901 fptr->write_lock = rb_mutex_new();
1902 rb_mutex_allow_trap(fptr->write_lock, 1);
1903 }
1904}
1905
1906static inline int
1907io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1908{
1909 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1910 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1911 return 1;
1912
1913 // If the amount of data we want to write exceeds the internal buffer:
1914 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1915 return 1;
1916
1917 // Otherwise, we can append to the internal buffer:
1918 return 0;
1919}
1920
1921static long
1922io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1923{
1924 if (len <= 0) return len;
1925
1926 // Don't write anything if current thread has a pending interrupt:
1928
1929 io_allocate_write_buffer(fptr, !nosync);
1930
1931 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1932 struct binwrite_arg arg;
1933
1934 arg.fptr = fptr;
1935 arg.ptr = ptr;
1936 arg.length = len;
1937
1938 if (!NIL_P(fptr->write_lock)) {
1939 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1940 }
1941 else {
1942 return io_binwrite_string((VALUE)&arg);
1943 }
1944 }
1945 else {
1946 if (fptr->wbuf.off) {
1947 if (fptr->wbuf.len)
1948 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1949 fptr->wbuf.off = 0;
1950 }
1951
1952 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1953 fptr->wbuf.len += (int)len;
1954
1955 return len;
1956 }
1957}
1958
1959# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1960 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1961
1962#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1963 MODE_BTMODE(d, e, f) : \
1964 MODE_BTMODE(a, b, c))
1965
1966static VALUE
1967do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1968{
1969 if (NEED_WRITECONV(fptr)) {
1970 VALUE common_encoding = Qnil;
1971 SET_BINARY_MODE(fptr);
1972
1973 make_writeconv(fptr);
1974
1975 if (fptr->writeconv) {
1976#define fmode (fptr->mode)
1977 if (!NIL_P(fptr->writeconv_asciicompat))
1978 common_encoding = fptr->writeconv_asciicompat;
1979 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1980 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1981 rb_enc_name(rb_enc_get(str)));
1982 }
1983#undef fmode
1984 }
1985 else {
1986 if (fptr->encs.enc2)
1987 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1988 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1989 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1990 }
1991
1992 if (!NIL_P(common_encoding)) {
1993 str = rb_str_encode(str, common_encoding,
1995 *converted = 1;
1996 }
1997
1998 if (fptr->writeconv) {
2000 *converted = 1;
2001 }
2002 }
2003#if RUBY_CRLF_ENVIRONMENT
2004#define fmode (fptr->mode)
2005 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2006 if ((fptr->mode & FMODE_READABLE) &&
2008 setmode(fptr->fd, O_BINARY);
2009 }
2010 else {
2011 setmode(fptr->fd, O_TEXT);
2012 }
2013 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2014 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2015 rb_enc_name(rb_enc_get(str)));
2016 }
2017 }
2018#undef fmode
2019#endif
2020 return str;
2021}
2022
2023static long
2024io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
2025{
2026 int converted = 0;
2027 VALUE tmp;
2028 long n, len;
2029 const char *ptr;
2030
2031#ifdef _WIN32
2032 if (fptr->mode & FMODE_TTY) {
2033 long len = rb_w32_write_console(str, fptr->fd);
2034 if (len > 0) return len;
2035 }
2036#endif
2037
2038 str = do_writeconv(str, fptr, &converted);
2039 if (converted)
2040 OBJ_FREEZE(str);
2041
2042 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2043 RSTRING_GETMEM(tmp, ptr, len);
2044 n = io_binwrite(ptr, len, fptr, nosync);
2045 rb_str_tmp_frozen_release(str, tmp);
2046
2047 return n;
2048}
2049
2050ssize_t
2051rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2052{
2053 rb_io_t *fptr;
2054
2055 GetOpenFile(io, fptr);
2057 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2058}
2059
2060static VALUE
2061io_write(VALUE io, VALUE str, int nosync)
2062{
2063 rb_io_t *fptr;
2064 long n;
2065 VALUE tmp;
2066
2067 io = GetWriteIO(io);
2068 str = rb_obj_as_string(str);
2069 tmp = rb_io_check_io(io);
2070
2071 if (NIL_P(tmp)) {
2072 /* port is not IO, call write method for it. */
2073 return rb_funcall(io, id_write, 1, str);
2074 }
2075
2076 io = tmp;
2077 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2078
2079 GetOpenFile(io, fptr);
2081
2082 n = io_fwrite(str, fptr, nosync);
2083 if (n < 0L) rb_sys_fail_on_write(fptr);
2084
2085 return LONG2FIX(n);
2086}
2087
2088#ifdef HAVE_WRITEV
2089struct binwritev_arg {
2090 rb_io_t *fptr;
2091 struct iovec *iov;
2092 int iovcnt;
2093 size_t total;
2094};
2095
2096static VALUE
2097io_binwritev_internal(VALUE arg)
2098{
2099 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2100
2101 size_t remaining = p->total;
2102 size_t offset = 0;
2103
2104 rb_io_t *fptr = p->fptr;
2105 struct iovec *iov = p->iov;
2106 int iovcnt = p->iovcnt;
2107
2108 while (remaining) {
2109 long result = rb_writev_internal(fptr, iov, iovcnt);
2110
2111 if (result >= 0) {
2112 offset += result;
2113 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2114 if (offset < (size_t)fptr->wbuf.len) {
2115 fptr->wbuf.off += result;
2116 fptr->wbuf.len -= result;
2117 }
2118 else {
2119 offset -= (size_t)fptr->wbuf.len;
2120 fptr->wbuf.off = 0;
2121 fptr->wbuf.len = 0;
2122 }
2123 }
2124
2125 if (offset == p->total) {
2126 return p->total;
2127 }
2128
2129 while (result >= (ssize_t)iov->iov_len) {
2130 /* iovcnt > 0 */
2131 result -= iov->iov_len;
2132 iov->iov_len = 0;
2133 iov++;
2134
2135 if (!--iovcnt) {
2136 // I don't believe this code path can ever occur.
2137 return offset;
2138 }
2139 }
2140
2141 iov->iov_base = (char *)iov->iov_base + result;
2142 iov->iov_len -= result;
2143 }
2144 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2145 rb_io_check_closed(fptr);
2146 }
2147 else {
2148 return -1;
2149 }
2150 }
2151
2152 return offset;
2153}
2154
2155static long
2156io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2157{
2158 // Don't write anything if current thread has a pending interrupt:
2160
2161 if (iovcnt == 0) return 0;
2162
2163 size_t total = 0;
2164 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2165
2166 io_allocate_write_buffer(fptr, 1);
2167
2168 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2169 // The end of the buffered data:
2170 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2171
2172 if (offset + total <= (size_t)fptr->wbuf.capa) {
2173 for (int i = 1; i < iovcnt; i++) {
2174 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2175 offset += iov[i].iov_len;
2176 }
2177
2178 fptr->wbuf.len += total;
2179
2180 return total;
2181 }
2182 else {
2183 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2184 iov[0].iov_len = fptr->wbuf.len;
2185 }
2186 }
2187 else {
2188 // The first iov is reserved for the internal buffer, and it's empty.
2189 iov++;
2190
2191 if (!--iovcnt) {
2192 // If there are no other io vectors we are done.
2193 return 0;
2194 }
2195 }
2196
2197 struct binwritev_arg arg;
2198 arg.fptr = fptr;
2199 arg.iov = iov;
2200 arg.iovcnt = iovcnt;
2201 arg.total = total;
2202
2203 if (!NIL_P(fptr->write_lock)) {
2204 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2205 }
2206 else {
2207 return io_binwritev_internal((VALUE)&arg);
2208 }
2209}
2210
2211static long
2212io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2213{
2214 int i, converted, iovcnt = argc + 1;
2215 long n;
2216 VALUE v1, v2, str, tmp, *tmp_array;
2217 struct iovec *iov;
2218
2219 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2220 tmp_array = ALLOCV_N(VALUE, v2, argc);
2221
2222 for (i = 0; i < argc; i++) {
2223 str = rb_obj_as_string(argv[i]);
2224 converted = 0;
2225 str = do_writeconv(str, fptr, &converted);
2226
2227 if (converted)
2228 OBJ_FREEZE(str);
2229
2230 tmp = rb_str_tmp_frozen_acquire(str);
2231 tmp_array[i] = tmp;
2232
2233 /* iov[0] is reserved for buffer of fptr */
2234 iov[i+1].iov_base = RSTRING_PTR(tmp);
2235 iov[i+1].iov_len = RSTRING_LEN(tmp);
2236 }
2237
2238 n = io_binwritev(iov, iovcnt, fptr);
2239 if (v1) ALLOCV_END(v1);
2240
2241 for (i = 0; i < argc; i++) {
2242 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2243 }
2244
2245 if (v2) ALLOCV_END(v2);
2246
2247 return n;
2248}
2249
2250static int
2251iovcnt_ok(int iovcnt)
2252{
2253#ifdef IOV_MAX
2254 return iovcnt < IOV_MAX;
2255#else /* GNU/Hurd has writev, but no IOV_MAX */
2256 return 1;
2257#endif
2258}
2259#endif /* HAVE_WRITEV */
2260
2261static VALUE
2262io_writev(int argc, const VALUE *argv, VALUE io)
2263{
2264 rb_io_t *fptr;
2265 long n;
2266 VALUE tmp, total = INT2FIX(0);
2267 int i, cnt = 1;
2268
2269 io = GetWriteIO(io);
2270 tmp = rb_io_check_io(io);
2271
2272 if (NIL_P(tmp)) {
2273 /* port is not IO, call write method for it. */
2274 return rb_funcallv(io, id_write, argc, argv);
2275 }
2276
2277 io = tmp;
2278
2279 GetOpenFile(io, fptr);
2281
2282 for (i = 0; i < argc; i += cnt) {
2283#ifdef HAVE_WRITEV
2284 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2285 n = io_fwritev(cnt, &argv[i], fptr);
2286 }
2287 else
2288#endif
2289 {
2290 cnt = 1;
2291 /* sync at last item */
2292 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2293 }
2294
2295 if (n < 0L)
2296 rb_sys_fail_on_write(fptr);
2297
2298 total = rb_fix_plus(LONG2FIX(n), total);
2299 }
2300
2301 return total;
2302}
2303
2304/*
2305 * call-seq:
2306 * write(*objects) -> integer
2307 *
2308 * Writes each of the given +objects+ to +self+,
2309 * which must be opened for writing
2310 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2311 * returns the total number bytes written;
2312 * each of +objects+ that is not a string is converted via method +to_s+:
2313 *
2314 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2315 * $stdout.write('foo', :bar, 2, "\n") # => 8
2316 *
2317 * Output:
2318 *
2319 * Hello, World!
2320 * foobar2
2321 *
2322 * Related: IO#read.
2323 */
2324
2325static VALUE
2326io_write_m(int argc, VALUE *argv, VALUE io)
2327{
2328 if (argc != 1) {
2329 return io_writev(argc, argv, io);
2330 }
2331 else {
2332 VALUE str = argv[0];
2333 return io_write(io, str, 0);
2334 }
2335}
2336
2337VALUE
2338rb_io_write(VALUE io, VALUE str)
2339{
2340 return rb_funcallv(io, id_write, 1, &str);
2341}
2342
2343static VALUE
2344rb_io_writev(VALUE io, int argc, const VALUE *argv)
2345{
2346 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2347 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2348 VALUE klass = CLASS_OF(io);
2349 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2351 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2352 " which accepts just one argument",
2353 klass, sep
2354 );
2355 }
2356
2357 do rb_io_write(io, *argv++); while (--argc);
2358
2359 return Qnil;
2360 }
2361
2362 return rb_funcallv(io, id_write, argc, argv);
2363}
2364
2365/*
2366 * call-seq:
2367 * self << object -> self
2368 *
2369 * Writes the given +object+ to +self+,
2370 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2371 * returns +self+;
2372 * if +object+ is not a string, it is converted via method +to_s+:
2373 *
2374 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2375 * $stdout << 'foo' << :bar << 2 << "\n"
2376 *
2377 * Output:
2378 *
2379 * Hello, World!
2380 * foobar2
2381 *
2382 */
2383
2384
2385VALUE
2387{
2388 rb_io_write(io, str);
2389 return io;
2390}
2391
2392#ifdef HAVE_FSYNC
2393static VALUE
2394nogvl_fsync(void *ptr)
2395{
2396 rb_io_t *fptr = ptr;
2397
2398#ifdef _WIN32
2399 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2400 return 0;
2401#endif
2402 return (VALUE)fsync(fptr->fd);
2403}
2404#endif
2405
2406VALUE
2407rb_io_flush_raw(VALUE io, int sync)
2408{
2409 rb_io_t *fptr;
2410
2411 if (!RB_TYPE_P(io, T_FILE)) {
2412 return rb_funcall(io, id_flush, 0);
2413 }
2414
2415 io = GetWriteIO(io);
2416 GetOpenFile(io, fptr);
2417
2418 if (fptr->mode & FMODE_WRITABLE) {
2419 if (io_fflush(fptr) < 0)
2420 rb_sys_fail_on_write(fptr);
2421 }
2422 if (fptr->mode & FMODE_READABLE) {
2423 io_unread(fptr, true);
2424 }
2425
2426 return io;
2427}
2428
2429/*
2430 * call-seq:
2431 * flush -> self
2432 *
2433 * Flushes data buffered in +self+ to the operating system
2434 * (but does not necessarily flush data buffered in the operating system):
2435 *
2436 * $stdout.print 'no newline' # Not necessarily flushed.
2437 * $stdout.flush # Flushed.
2438 *
2439 */
2440
2441VALUE
2442rb_io_flush(VALUE io)
2443{
2444 return rb_io_flush_raw(io, 1);
2445}
2446
2447/*
2448 * call-seq:
2449 * tell -> integer
2450 *
2451 * Returns the current position (in bytes) in +self+
2452 * (see {Position}[rdoc-ref:IO@Position]):
2453 *
2454 * f = File.open('t.txt')
2455 * f.tell # => 0
2456 * f.gets # => "First line\n"
2457 * f.tell # => 12
2458 * f.close
2459 *
2460 * Related: IO#pos=, IO#seek.
2461 */
2462
2463static VALUE
2464rb_io_tell(VALUE io)
2465{
2466 rb_io_t *fptr;
2467 rb_off_t pos;
2468
2469 GetOpenFile(io, fptr);
2470 pos = io_tell(fptr);
2471 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2472 pos -= fptr->rbuf.len;
2473 return OFFT2NUM(pos);
2474}
2475
2476static VALUE
2477rb_io_seek(VALUE io, VALUE offset, int whence)
2478{
2479 rb_io_t *fptr;
2480 rb_off_t pos;
2481
2482 pos = NUM2OFFT(offset);
2483 GetOpenFile(io, fptr);
2484 pos = io_seek(fptr, pos, whence);
2485 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2486 if (fptr->readconv) clear_readconv(fptr);
2487
2488 return INT2FIX(0);
2489}
2490
2491static int
2492interpret_seek_whence(VALUE vwhence)
2493{
2494 if (vwhence == sym_SET)
2495 return SEEK_SET;
2496 if (vwhence == sym_CUR)
2497 return SEEK_CUR;
2498 if (vwhence == sym_END)
2499 return SEEK_END;
2500#ifdef SEEK_DATA
2501 if (vwhence == sym_DATA)
2502 return SEEK_DATA;
2503#endif
2504#ifdef SEEK_HOLE
2505 if (vwhence == sym_HOLE)
2506 return SEEK_HOLE;
2507#endif
2508 return NUM2INT(vwhence);
2509}
2510
2511/*
2512 * call-seq:
2513 * seek(offset, whence = IO::SEEK_SET) -> 0
2514 *
2515 * Seeks to the position given by integer +offset+
2516 * (see {Position}[rdoc-ref:IO@Position])
2517 * and constant +whence+, which is one of:
2518 *
2519 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2520 * Repositions the stream to its current position plus the given +offset+:
2521 *
2522 * f = File.open('t.txt')
2523 * f.tell # => 0
2524 * f.seek(20, :CUR) # => 0
2525 * f.tell # => 20
2526 * f.seek(-10, :CUR) # => 0
2527 * f.tell # => 10
2528 * f.close
2529 *
2530 * - +:END+ or <tt>IO::SEEK_END</tt>:
2531 * Repositions the stream to its end plus the given +offset+:
2532 *
2533 * f = File.open('t.txt')
2534 * f.tell # => 0
2535 * f.seek(0, :END) # => 0 # Repositions to stream end.
2536 * f.tell # => 52
2537 * f.seek(-20, :END) # => 0
2538 * f.tell # => 32
2539 * f.seek(-40, :END) # => 0
2540 * f.tell # => 12
2541 * f.close
2542 *
2543 * - +:SET+ or <tt>IO::SEEK_SET</tt>:
2544 * Repositions the stream to the given +offset+:
2545 *
2546 * f = File.open('t.txt')
2547 * f.tell # => 0
2548 * f.seek(20, :SET) # => 0
2549 * f.tell # => 20
2550 * f.seek(40, :SET) # => 0
2551 * f.tell # => 40
2552 * f.close
2553 *
2554 * Related: IO#pos=, IO#tell.
2555 *
2556 */
2557
2558static VALUE
2559rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2560{
2561 VALUE offset, ptrname;
2562 int whence = SEEK_SET;
2563
2564 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2565 whence = interpret_seek_whence(ptrname);
2566 }
2567
2568 return rb_io_seek(io, offset, whence);
2569}
2570
2571/*
2572 * call-seq:
2573 * pos = new_position -> new_position
2574 *
2575 * Seeks to the given +new_position+ (in bytes);
2576 * see {Position}[rdoc-ref:IO@Position]:
2577 *
2578 * f = File.open('t.txt')
2579 * f.tell # => 0
2580 * f.pos = 20 # => 20
2581 * f.tell # => 20
2582 * f.close
2583 *
2584 * Related: IO#seek, IO#tell.
2585 *
2586 */
2587
2588static VALUE
2589rb_io_set_pos(VALUE io, VALUE offset)
2590{
2591 rb_io_t *fptr;
2592 rb_off_t pos;
2593
2594 pos = NUM2OFFT(offset);
2595 GetOpenFile(io, fptr);
2596 pos = io_seek(fptr, pos, SEEK_SET);
2597 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2598 if (fptr->readconv) clear_readconv(fptr);
2599
2600 return OFFT2NUM(pos);
2601}
2602
2603/*
2604 * call-seq:
2605 * rewind -> 0
2606 *
2607 * Repositions the stream to its beginning,
2608 * setting both the position and the line number to zero;
2609 * see {Position}[rdoc-ref:IO@Position]
2610 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2611 *
2612 * f = File.open('t.txt')
2613 * f.tell # => 0
2614 * f.lineno # => 0
2615 * f.gets # => "First line\n"
2616 * f.tell # => 12
2617 * f.lineno # => 1
2618 * f.rewind # => 0
2619 * f.tell # => 0
2620 * f.lineno # => 0
2621 * f.close
2622 *
2623 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2624 *
2625 */
2626
2627static VALUE
2628rb_io_rewind(VALUE io)
2629{
2630 rb_io_t *fptr;
2631
2632 GetOpenFile(io, fptr);
2633 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2634 if (io == ARGF.current_file) {
2635 ARGF.lineno -= fptr->lineno;
2636 }
2637 fptr->lineno = 0;
2638 if (fptr->readconv) {
2639 clear_readconv(fptr);
2640 }
2641
2642 return INT2FIX(0);
2643}
2644
2645static int
2646fptr_wait_readable(rb_io_t *fptr)
2647{
2648 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2649
2650 if (result)
2651 rb_io_check_closed(fptr);
2652
2653 return result;
2654}
2655
2656static int
2657io_fillbuf(rb_io_t *fptr)
2658{
2659 ssize_t r;
2660
2661 if (fptr->rbuf.ptr == NULL) {
2662 fptr->rbuf.off = 0;
2663 fptr->rbuf.len = 0;
2664 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2665 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2666 }
2667 if (fptr->rbuf.len == 0) {
2668 retry:
2669 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2670
2671 if (r < 0) {
2672 if (fptr_wait_readable(fptr))
2673 goto retry;
2674
2675 int e = errno;
2676 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2677 if (!NIL_P(fptr->pathv)) {
2678 rb_str_append(path, fptr->pathv);
2679 }
2680
2681 rb_syserr_fail_path(e, path);
2682 }
2683 if (r > 0) rb_io_check_closed(fptr);
2684 fptr->rbuf.off = 0;
2685 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2686 if (r == 0)
2687 return -1; /* EOF */
2688 }
2689 return 0;
2690}
2691
2692/*
2693 * call-seq:
2694 * eof -> true or false
2695 *
2696 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2697 * see {Position}[rdoc-ref:IO@Position]:
2698 *
2699 * f = File.open('t.txt')
2700 * f.eof # => false
2701 * f.seek(0, :END) # => 0
2702 * f.eof # => true
2703 * f.close
2704 *
2705 * Raises an exception unless the stream is opened for reading;
2706 * see {Mode}[rdoc-ref:File@Access+Modes].
2707 *
2708 * If +self+ is a stream such as pipe or socket, this method
2709 * blocks until the other end sends some data or closes it:
2710 *
2711 * r, w = IO.pipe
2712 * Thread.new { sleep 1; w.close }
2713 * r.eof? # => true # After 1-second wait.
2714 *
2715 * r, w = IO.pipe
2716 * Thread.new { sleep 1; w.puts "a" }
2717 * r.eof? # => false # After 1-second wait.
2718 *
2719 * r, w = IO.pipe
2720 * r.eof? # blocks forever
2721 *
2722 * Note that this method reads data to the input byte buffer. So
2723 * IO#sysread may not behave as you intend with IO#eof?, unless you
2724 * call IO#rewind first (which is not available for some streams).
2725 */
2726
2727VALUE
2729{
2730 rb_io_t *fptr;
2731
2732 GetOpenFile(io, fptr);
2734
2735 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2736 if (READ_DATA_PENDING(fptr)) return Qfalse;
2737 READ_CHECK(fptr);
2738#if RUBY_CRLF_ENVIRONMENT
2739 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2740 return RBOOL(eof(fptr->fd));
2741 }
2742#endif
2743 return RBOOL(io_fillbuf(fptr) < 0);
2744}
2745
2746/*
2747 * call-seq:
2748 * sync -> true or false
2749 *
2750 * Returns the current sync mode of the stream.
2751 * When sync mode is true, all output is immediately flushed to the underlying
2752 * operating system and is not buffered by Ruby internally. See also #fsync.
2753 *
2754 * f = File.open('t.tmp', 'w')
2755 * f.sync # => false
2756 * f.sync = true
2757 * f.sync # => true
2758 * f.close
2759 *
2760 */
2761
2762static VALUE
2763rb_io_sync(VALUE io)
2764{
2765 rb_io_t *fptr;
2766
2767 io = GetWriteIO(io);
2768 GetOpenFile(io, fptr);
2769 return RBOOL(fptr->mode & FMODE_SYNC);
2770}
2771
2772#ifdef HAVE_FSYNC
2773
2774/*
2775 * call-seq:
2776 * sync = boolean -> boolean
2777 *
2778 * Sets the _sync_ _mode_ for the stream to the given value;
2779 * returns the given value.
2780 *
2781 * Values for the sync mode:
2782 *
2783 * - +true+: All output is immediately flushed to the
2784 * underlying operating system and is not buffered internally.
2785 * - +false+: Output may be buffered internally.
2786 *
2787 * Example;
2788 *
2789 * f = File.open('t.tmp', 'w')
2790 * f.sync # => false
2791 * f.sync = true
2792 * f.sync # => true
2793 * f.close
2794 *
2795 * Related: IO#fsync.
2796 *
2797 */
2798
2799static VALUE
2800rb_io_set_sync(VALUE io, VALUE sync)
2801{
2802 rb_io_t *fptr;
2803
2804 io = GetWriteIO(io);
2805 GetOpenFile(io, fptr);
2806 if (RTEST(sync)) {
2807 fptr->mode |= FMODE_SYNC;
2808 }
2809 else {
2810 fptr->mode &= ~FMODE_SYNC;
2811 }
2812 return sync;
2813}
2814
2815/*
2816 * call-seq:
2817 * fsync -> 0
2818 *
2819 * Immediately writes to disk all data buffered in the stream,
2820 * via the operating system's <tt>fsync(2)</tt>.
2821
2822 * Note this difference:
2823 *
2824 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2825 * but does not guarantee that the operating system actually writes the data to disk.
2826 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2827 * and that data is written to disk.
2828 *
2829 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2830 *
2831 */
2832
2833static VALUE
2834rb_io_fsync(VALUE io)
2835{
2836 rb_io_t *fptr;
2837
2838 io = GetWriteIO(io);
2839 GetOpenFile(io, fptr);
2840
2841 if (io_fflush(fptr) < 0)
2842 rb_sys_fail_on_write(fptr);
2843
2844 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2845 rb_sys_fail_path(fptr->pathv);
2846
2847 return INT2FIX(0);
2848}
2849#else
2850# define rb_io_fsync rb_f_notimplement
2851# define rb_io_sync rb_f_notimplement
2852static VALUE
2853rb_io_set_sync(VALUE io, VALUE sync)
2854{
2855 rb_notimplement();
2857}
2858#endif
2859
2860#ifdef HAVE_FDATASYNC
2861static VALUE
2862nogvl_fdatasync(void *ptr)
2863{
2864 rb_io_t *fptr = ptr;
2865
2866#ifdef _WIN32
2867 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2868 return 0;
2869#endif
2870 return (VALUE)fdatasync(fptr->fd);
2871}
2872
2873/*
2874 * call-seq:
2875 * fdatasync -> 0
2876 *
2877 * Immediately writes to disk all data buffered in the stream,
2878 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2879 * otherwise via <tt>fsync(2)</tt>, if supported;
2880 * otherwise raises an exception.
2881 *
2882 */
2883
2884static VALUE
2885rb_io_fdatasync(VALUE io)
2886{
2887 rb_io_t *fptr;
2888
2889 io = GetWriteIO(io);
2890 GetOpenFile(io, fptr);
2891
2892 if (io_fflush(fptr) < 0)
2893 rb_sys_fail_on_write(fptr);
2894
2895 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2896 return INT2FIX(0);
2897
2898 /* fall back */
2899 return rb_io_fsync(io);
2900}
2901#else
2902#define rb_io_fdatasync rb_io_fsync
2903#endif
2904
2905/*
2906 * call-seq:
2907 * fileno -> integer
2908 *
2909 * Returns the integer file descriptor for the stream:
2910 *
2911 * $stdin.fileno # => 0
2912 * $stdout.fileno # => 1
2913 * $stderr.fileno # => 2
2914 * File.open('t.txt').fileno # => 10
2915 * f.close
2916 *
2917 */
2918
2919static VALUE
2920rb_io_fileno(VALUE io)
2921{
2922 rb_io_t *fptr = RFILE(io)->fptr;
2923 int fd;
2924
2925 rb_io_check_closed(fptr);
2926 fd = fptr->fd;
2927 return INT2FIX(fd);
2928}
2929
2930int
2932{
2933 if (RB_TYPE_P(io, T_FILE)) {
2934 rb_io_t *fptr = RFILE(io)->fptr;
2935 rb_io_check_closed(fptr);
2936 return fptr->fd;
2937 }
2938 else {
2939 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2940 if (!UNDEF_P(fileno)) {
2941 return RB_NUM2INT(fileno);
2942 }
2943 }
2944
2945 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2946
2948}
2949
2950int
2951rb_io_mode(VALUE io)
2952{
2953 rb_io_t *fptr;
2954 GetOpenFile(io, fptr);
2955 return fptr->mode;
2956}
2957
2958/*
2959 * call-seq:
2960 * pid -> integer or nil
2961 *
2962 * Returns the process ID of a child process associated with the stream,
2963 * which will have been set by IO#popen, or +nil+ if the stream was not
2964 * created by IO#popen:
2965 *
2966 * pipe = IO.popen("-")
2967 * if pipe
2968 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2969 * else
2970 * $stderr.puts "In child, pid is #{$$}"
2971 * end
2972 *
2973 * Output:
2974 *
2975 * In child, pid is 26209
2976 * In parent, child pid is 26209
2977 *
2978 */
2979
2980static VALUE
2981rb_io_pid(VALUE io)
2982{
2983 rb_io_t *fptr;
2984
2985 GetOpenFile(io, fptr);
2986 if (!fptr->pid)
2987 return Qnil;
2988 return PIDT2NUM(fptr->pid);
2989}
2990
2991/*
2992 * call-seq:
2993 * path -> string or nil
2994 *
2995 * Returns the path associated with the IO, or +nil+ if there is no path
2996 * associated with the IO. It is not guaranteed that the path exists on
2997 * the filesystem.
2998 *
2999 * $stdin.path # => "<STDIN>"
3000 *
3001 * File.open("testfile") {|f| f.path} # => "testfile"
3002 */
3003
3004VALUE
3006{
3007 rb_io_t *fptr = RFILE(io)->fptr;
3008
3009 if (!fptr)
3010 return Qnil;
3011
3012 return rb_obj_dup(fptr->pathv);
3013}
3014
3015/*
3016 * call-seq:
3017 * inspect -> string
3018 *
3019 * Returns a string representation of +self+:
3020 *
3021 * f = File.open('t.txt')
3022 * f.inspect # => "#<File:t.txt>"
3023 * f.close
3024 *
3025 */
3026
3027static VALUE
3028rb_io_inspect(VALUE obj)
3029{
3030 rb_io_t *fptr;
3031 VALUE result;
3032 static const char closed[] = " (closed)";
3033
3034 fptr = RFILE(obj)->fptr;
3035 if (!fptr) return rb_any_to_s(obj);
3036 result = rb_str_new_cstr("#<");
3037 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3038 rb_str_cat2(result, ":");
3039 if (NIL_P(fptr->pathv)) {
3040 if (fptr->fd < 0) {
3041 rb_str_cat(result, closed+1, strlen(closed)-1);
3042 }
3043 else {
3044 rb_str_catf(result, "fd %d", fptr->fd);
3045 }
3046 }
3047 else {
3048 rb_str_append(result, fptr->pathv);
3049 if (fptr->fd < 0) {
3050 rb_str_cat(result, closed, strlen(closed));
3051 }
3052 }
3053 return rb_str_cat2(result, ">");
3054}
3055
3056/*
3057 * call-seq:
3058 * to_io -> self
3059 *
3060 * Returns +self+.
3061 *
3062 */
3063
3064static VALUE
3065rb_io_to_io(VALUE io)
3066{
3067 return io;
3068}
3069
3070/* reading functions */
3071static long
3072read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3073{
3074 int n;
3075
3076 n = READ_DATA_PENDING_COUNT(fptr);
3077 if (n <= 0) return 0;
3078 if (n > len) n = (int)len;
3079 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3080 fptr->rbuf.off += n;
3081 fptr->rbuf.len -= n;
3082 return n;
3083}
3084
3085static long
3086io_bufread(char *ptr, long len, rb_io_t *fptr)
3087{
3088 long offset = 0;
3089 long n = len;
3090 long c;
3091
3092 if (READ_DATA_PENDING(fptr) == 0) {
3093 while (n > 0) {
3094 again:
3095 rb_io_check_closed(fptr);
3096 c = rb_io_read_memory(fptr, ptr+offset, n);
3097 if (c == 0) break;
3098 if (c < 0) {
3099 if (fptr_wait_readable(fptr))
3100 goto again;
3101 return -1;
3102 }
3103 offset += c;
3104 if ((n -= c) <= 0) break;
3105 }
3106 return len - n;
3107 }
3108
3109 while (n > 0) {
3110 c = read_buffered_data(ptr+offset, n, fptr);
3111 if (c > 0) {
3112 offset += c;
3113 if ((n -= c) <= 0) break;
3114 }
3115 rb_io_check_closed(fptr);
3116 if (io_fillbuf(fptr) < 0) {
3117 break;
3118 }
3119 }
3120 return len - n;
3121}
3122
3123static int io_setstrbuf(VALUE *str, long len);
3124
3126 char *str_ptr;
3127 long len;
3128 rb_io_t *fptr;
3129};
3130
3131static VALUE
3132bufread_call(VALUE arg)
3133{
3134 struct bufread_arg *p = (struct bufread_arg *)arg;
3135 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3136 return Qundef;
3137}
3138
3139static long
3140io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3141{
3142 long len;
3143 struct bufread_arg arg;
3144
3145 io_setstrbuf(&str, offset + size);
3146 arg.str_ptr = RSTRING_PTR(str) + offset;
3147 arg.len = size;
3148 arg.fptr = fptr;
3149 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3150 len = arg.len;
3151 if (len < 0) rb_sys_fail_path(fptr->pathv);
3152 return len;
3153}
3154
3155static long
3156remain_size(rb_io_t *fptr)
3157{
3158 struct stat st;
3159 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3160 rb_off_t pos;
3161
3162 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3163#if defined(__HAIKU__)
3164 && (st.st_dev > 3)
3165#endif
3166 )
3167 {
3168 if (io_fflush(fptr) < 0)
3169 rb_sys_fail_on_write(fptr);
3170 pos = lseek(fptr->fd, 0, SEEK_CUR);
3171 if (st.st_size >= pos && pos >= 0) {
3172 siz += st.st_size - pos;
3173 if (siz > LONG_MAX) {
3174 rb_raise(rb_eIOError, "file too big for single read");
3175 }
3176 }
3177 }
3178 else {
3179 siz += BUFSIZ;
3180 }
3181 return (long)siz;
3182}
3183
3184static VALUE
3185io_enc_str(VALUE str, rb_io_t *fptr)
3186{
3187 rb_enc_associate(str, io_read_encoding(fptr));
3188 return str;
3189}
3190
3191static void
3192make_readconv(rb_io_t *fptr, int size)
3193{
3194 if (!fptr->readconv) {
3195 int ecflags;
3196 VALUE ecopts;
3197 const char *sname, *dname;
3198 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3199 ecopts = fptr->encs.ecopts;
3200 if (fptr->encs.enc2) {
3201 sname = rb_enc_name(fptr->encs.enc2);
3202 dname = rb_enc_name(io_read_encoding(fptr));
3203 }
3204 else {
3205 sname = dname = "";
3206 }
3207 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3208 if (!fptr->readconv)
3209 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3210 fptr->cbuf.off = 0;
3211 fptr->cbuf.len = 0;
3212 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3213 fptr->cbuf.capa = size;
3214 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3215 }
3216}
3217
3218#define MORE_CHAR_SUSPENDED Qtrue
3219#define MORE_CHAR_FINISHED Qnil
3220static VALUE
3221fill_cbuf(rb_io_t *fptr, int ec_flags)
3222{
3223 const unsigned char *ss, *sp, *se;
3224 unsigned char *ds, *dp, *de;
3226 int putbackable;
3227 int cbuf_len0;
3228 VALUE exc;
3229
3230 ec_flags |= ECONV_PARTIAL_INPUT;
3231
3232 if (fptr->cbuf.len == fptr->cbuf.capa)
3233 return MORE_CHAR_SUSPENDED; /* cbuf full */
3234 if (fptr->cbuf.len == 0)
3235 fptr->cbuf.off = 0;
3236 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3237 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3238 fptr->cbuf.off = 0;
3239 }
3240
3241 cbuf_len0 = fptr->cbuf.len;
3242
3243 while (1) {
3244 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3245 se = sp + fptr->rbuf.len;
3246 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3247 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3248 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3249 fptr->rbuf.off += (int)(sp - ss);
3250 fptr->rbuf.len -= (int)(sp - ss);
3251 fptr->cbuf.len += (int)(dp - ds);
3252
3253 putbackable = rb_econv_putbackable(fptr->readconv);
3254 if (putbackable) {
3255 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3256 fptr->rbuf.off -= putbackable;
3257 fptr->rbuf.len += putbackable;
3258 }
3259
3260 exc = rb_econv_make_exception(fptr->readconv);
3261 if (!NIL_P(exc))
3262 return exc;
3263
3264 if (cbuf_len0 != fptr->cbuf.len)
3265 return MORE_CHAR_SUSPENDED;
3266
3267 if (res == econv_finished) {
3268 return MORE_CHAR_FINISHED;
3269 }
3270
3271 if (res == econv_source_buffer_empty) {
3272 if (fptr->rbuf.len == 0) {
3273 READ_CHECK(fptr);
3274 if (io_fillbuf(fptr) < 0) {
3275 if (!fptr->readconv) {
3276 return MORE_CHAR_FINISHED;
3277 }
3278 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3279 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3280 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3281 fptr->cbuf.len += (int)(dp - ds);
3283 break;
3284 }
3285 }
3286 }
3287 }
3288 if (cbuf_len0 != fptr->cbuf.len)
3289 return MORE_CHAR_SUSPENDED;
3290
3291 return MORE_CHAR_FINISHED;
3292}
3293
3294static VALUE
3295more_char(rb_io_t *fptr)
3296{
3297 VALUE v;
3298 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3299 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3300 rb_exc_raise(v);
3301 return v;
3302}
3303
3304static VALUE
3305io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3306{
3307 VALUE str = Qnil;
3308 if (strp) {
3309 str = *strp;
3310 if (NIL_P(str)) {
3311 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3312 }
3313 else {
3314 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3315 }
3316 rb_enc_associate(str, fptr->encs.enc);
3317 }
3318 fptr->cbuf.off += len;
3319 fptr->cbuf.len -= len;
3320 /* xxx: set coderange */
3321 if (fptr->cbuf.len == 0)
3322 fptr->cbuf.off = 0;
3323 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3324 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3325 fptr->cbuf.off = 0;
3326 }
3327 return str;
3328}
3329
3330static int
3331io_setstrbuf(VALUE *str, long len)
3332{
3333 if (NIL_P(*str)) {
3334 *str = rb_str_new(0, len);
3335 return TRUE;
3336 }
3337 else {
3338 VALUE s = StringValue(*str);
3339 rb_str_modify(s);
3340
3341 long clen = RSTRING_LEN(s);
3342 if (clen >= len) {
3343 return FALSE;
3344 }
3345 len -= clen;
3346 }
3347 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3349 }
3350 return FALSE;
3351}
3352
3353#define MAX_REALLOC_GAP 4096
3354static void
3355io_shrink_read_string(VALUE str, long n)
3356{
3357 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3358 rb_str_resize(str, n);
3359 }
3360}
3361
3362static void
3363io_set_read_length(VALUE str, long n, int shrinkable)
3364{
3365 if (RSTRING_LEN(str) != n) {
3366 rb_str_modify(str);
3367 rb_str_set_len(str, n);
3368 if (shrinkable) io_shrink_read_string(str, n);
3369 }
3370}
3371
3372static VALUE
3373read_all(rb_io_t *fptr, long siz, VALUE str)
3374{
3375 long bytes;
3376 long n;
3377 long pos;
3378 rb_encoding *enc;
3379 int cr;
3380 int shrinkable;
3381
3382 if (NEED_READCONV(fptr)) {
3383 int first = !NIL_P(str);
3384 SET_BINARY_MODE(fptr);
3385 shrinkable = io_setstrbuf(&str,0);
3386 make_readconv(fptr, 0);
3387 while (1) {
3388 VALUE v;
3389 if (fptr->cbuf.len) {
3390 if (first) rb_str_set_len(str, first = 0);
3391 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3392 }
3393 v = fill_cbuf(fptr, 0);
3394 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3395 if (fptr->cbuf.len) {
3396 if (first) rb_str_set_len(str, first = 0);
3397 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3398 }
3399 rb_exc_raise(v);
3400 }
3401 if (v == MORE_CHAR_FINISHED) {
3402 clear_readconv(fptr);
3403 if (first) rb_str_set_len(str, first = 0);
3404 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3405 return io_enc_str(str, fptr);
3406 }
3407 }
3408 }
3409
3410 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3411 bytes = 0;
3412 pos = 0;
3413
3414 enc = io_read_encoding(fptr);
3415 cr = 0;
3416
3417 if (siz == 0) {
3418 siz = BUFSIZ;
3419 }
3420 else {
3421 // If `siz` is set, we got it from `stat(2)`.
3422 // We attempt to read one extra byte because:
3423 // - If the file was appended to since then, we'll continue reading.
3424 // - If the file is still the same length, we won't issue a second `io_fread`.
3425 siz++;
3426 }
3427 shrinkable = io_setstrbuf(&str, siz);
3428 for (;;) {
3429 READ_CHECK(fptr);
3430 n = io_fread(str, bytes, siz - bytes, fptr);
3431 if (n == 0 && bytes == 0) {
3432 rb_str_set_len(str, 0);
3433 break;
3434 }
3435 bytes += n;
3436 rb_str_set_len(str, bytes);
3437 if (cr != ENC_CODERANGE_BROKEN)
3438 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3439 if (bytes < siz) break;
3440 siz += BUFSIZ;
3441
3442 size_t capa = rb_str_capacity(str);
3443 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3444 if (capa < BUFSIZ) {
3445 capa = BUFSIZ;
3446 }
3447 else if (capa > IO_MAX_BUFFER_GROWTH) {
3448 capa = IO_MAX_BUFFER_GROWTH;
3449 }
3451 }
3452 }
3453 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3454 str = io_enc_str(str, fptr);
3455 ENC_CODERANGE_SET(str, cr);
3456 return str;
3457}
3458
3459void
3461{
3462 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3463 rb_sys_fail_path(fptr->pathv);
3464 }
3465}
3466
3467static VALUE
3468io_read_memory_call(VALUE arg)
3469{
3470 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3471
3472 VALUE scheduler = rb_fiber_scheduler_current();
3473 if (scheduler != Qnil) {
3474 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa);
3475
3476 if (!UNDEF_P(result)) {
3477 // This is actually returned as a pseudo-VALUE and later cast to a long:
3479 }
3480 }
3481
3482 if (iis->nonblock) {
3483 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3484 }
3485 else {
3486 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3487 }
3488}
3489
3490static long
3491io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3492{
3493 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3494}
3495
3496#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3497
3498static VALUE
3499io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3500{
3501 rb_io_t *fptr;
3502 VALUE length, str;
3503 long n, len;
3504 struct io_internal_read_struct iis;
3505 int shrinkable;
3506
3507 rb_scan_args(argc, argv, "11", &length, &str);
3508
3509 if ((len = NUM2LONG(length)) < 0) {
3510 rb_raise(rb_eArgError, "negative length %ld given", len);
3511 }
3512
3513 shrinkable = io_setstrbuf(&str, len);
3514
3515 GetOpenFile(io, fptr);
3517
3518 if (len == 0) {
3519 io_set_read_length(str, 0, shrinkable);
3520 return str;
3521 }
3522
3523 if (!nonblock)
3524 READ_CHECK(fptr);
3525 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3526 if (n <= 0) {
3527 again:
3528 if (nonblock) {
3529 rb_io_set_nonblock(fptr);
3530 }
3531 io_setstrbuf(&str, len);
3532 iis.th = rb_thread_current();
3533 iis.fptr = fptr;
3534 iis.nonblock = nonblock;
3535 iis.fd = fptr->fd;
3536 iis.buf = RSTRING_PTR(str);
3537 iis.capa = len;
3538 iis.timeout = NULL;
3539 n = io_read_memory_locktmp(str, &iis);
3540 if (n < 0) {
3541 int e = errno;
3542 if (!nonblock && fptr_wait_readable(fptr))
3543 goto again;
3544 if (nonblock && (io_again_p(e))) {
3545 if (no_exception)
3546 return sym_wait_readable;
3547 else
3548 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3549 e, "read would block");
3550 }
3551 rb_syserr_fail_path(e, fptr->pathv);
3552 }
3553 }
3554 io_set_read_length(str, n, shrinkable);
3555
3556 if (n == 0)
3557 return Qnil;
3558 else
3559 return str;
3560}
3561
3562/*
3563 * call-seq:
3564 * readpartial(maxlen) -> string
3565 * readpartial(maxlen, out_string) -> out_string
3566 *
3567 * Reads up to +maxlen+ bytes from the stream;
3568 * returns a string (either a new string or the given +out_string+).
3569 * Its encoding is:
3570 *
3571 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3572 * - ASCII-8BIT, otherwise.
3573 *
3574 * - Contains +maxlen+ bytes from the stream, if available.
3575 * - Otherwise contains all available bytes, if any available.
3576 * - Is an empty string if +maxlen+ is zero.
3577 *
3578 * With the single non-negative integer argument +maxlen+ given,
3579 * returns a new string:
3580 *
3581 * f = File.new('t.txt')
3582 * f.readpartial(20) # => "First line\nSecond l"
3583 * f.readpartial(20) # => "ine\n\nFourth line\n"
3584 * f.readpartial(20) # => "Fifth line\n"
3585 * f.readpartial(20) # Raises EOFError.
3586 * f.close
3587 *
3588 * With both argument +maxlen+ and string argument +out_string+ given,
3589 * returns modified +out_string+:
3590 *
3591 * f = File.new('t.txt')
3592 * s = 'foo'
3593 * f.readpartial(20, s) # => "First line\nSecond l"
3594 * s = 'bar'
3595 * f.readpartial(0, s) # => ""
3596 * f.close
3597 *
3598 * This method is useful for a stream such as a pipe, a socket, or a tty.
3599 * It blocks only when no data is immediately available.
3600 * This means that it blocks only when _all_ of the following are true:
3601 *
3602 * - The byte buffer in the stream is empty.
3603 * - The content of the stream is empty.
3604 * - The stream is not at EOF.
3605 *
3606 * When blocked, the method waits for either more data or EOF on the stream:
3607 *
3608 * - If more data is read, the method returns the data.
3609 * - If EOF is reached, the method raises EOFError.
3610 *
3611 * When not blocked, the method responds immediately:
3612 *
3613 * - Returns data from the buffer if there is any.
3614 * - Otherwise returns data from the stream if there is any.
3615 * - Otherwise raises EOFError if the stream has reached EOF.
3616 *
3617 * Note that this method is similar to sysread. The differences are:
3618 *
3619 * - If the byte buffer is not empty, read from the byte buffer
3620 * instead of "sysread for buffered IO (IOError)".
3621 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3622 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3623 * readpartial retries the system call.
3624 *
3625 * The latter means that readpartial is non-blocking-flag insensitive.
3626 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3627 * if the fd is blocking mode.
3628 *
3629 * Examples:
3630 *
3631 * # # Returned Buffer Content Pipe Content
3632 * r, w = IO.pipe #
3633 * w << 'abc' # "" "abc".
3634 * r.readpartial(4096) # => "abc" "" ""
3635 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3636 *
3637 * # # Returned Buffer Content Pipe Content
3638 * r, w = IO.pipe #
3639 * w << 'abc' # "" "abc"
3640 * w.close # "" "abc" EOF
3641 * r.readpartial(4096) # => "abc" "" EOF
3642 * r.readpartial(4096) # raises EOFError
3643 *
3644 * # # Returned Buffer Content Pipe Content
3645 * r, w = IO.pipe #
3646 * w << "abc\ndef\n" # "" "abc\ndef\n"
3647 * r.gets # => "abc\n" "def\n" ""
3648 * w << "ghi\n" # "def\n" "ghi\n"
3649 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3650 * r.readpartial(4096) # => "ghi\n" "" ""
3651 *
3652 */
3653
3654static VALUE
3655io_readpartial(int argc, VALUE *argv, VALUE io)
3656{
3657 VALUE ret;
3658
3659 ret = io_getpartial(argc, argv, io, Qnil, 0);
3660 if (NIL_P(ret))
3661 rb_eof_error();
3662 return ret;
3663}
3664
3665static VALUE
3666io_nonblock_eof(int no_exception)
3667{
3668 if (!no_exception) {
3669 rb_eof_error();
3670 }
3671 return Qnil;
3672}
3673
3674/* :nodoc: */
3675static VALUE
3676io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3677{
3678 rb_io_t *fptr;
3679 long n, len;
3680 struct io_internal_read_struct iis;
3681 int shrinkable;
3682
3683 if ((len = NUM2LONG(length)) < 0) {
3684 rb_raise(rb_eArgError, "negative length %ld given", len);
3685 }
3686
3687 shrinkable = io_setstrbuf(&str, len);
3688 rb_bool_expected(ex, "exception", TRUE);
3689
3690 GetOpenFile(io, fptr);
3692
3693 if (len == 0) {
3694 io_set_read_length(str, 0, shrinkable);
3695 return str;
3696 }
3697
3698 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3699 if (n <= 0) {
3700 rb_fd_set_nonblock(fptr->fd);
3701 shrinkable |= io_setstrbuf(&str, len);
3702 iis.fptr = fptr;
3703 iis.nonblock = 1;
3704 iis.fd = fptr->fd;
3705 iis.buf = RSTRING_PTR(str);
3706 iis.capa = len;
3707 iis.timeout = NULL;
3708 n = io_read_memory_locktmp(str, &iis);
3709 if (n < 0) {
3710 int e = errno;
3711 if (io_again_p(e)) {
3712 if (!ex) return sym_wait_readable;
3713 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3714 e, "read would block");
3715 }
3716 rb_syserr_fail_path(e, fptr->pathv);
3717 }
3718 }
3719 io_set_read_length(str, n, shrinkable);
3720
3721 if (n == 0) {
3722 if (!ex) return Qnil;
3723 rb_eof_error();
3724 }
3725
3726 return str;
3727}
3728
3729/* :nodoc: */
3730static VALUE
3731io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3732{
3733 rb_io_t *fptr;
3734 long n;
3735
3736 if (!RB_TYPE_P(str, T_STRING))
3737 str = rb_obj_as_string(str);
3738 rb_bool_expected(ex, "exception", TRUE);
3739
3740 io = GetWriteIO(io);
3741 GetOpenFile(io, fptr);
3743
3744 if (io_fflush(fptr) < 0)
3745 rb_sys_fail_on_write(fptr);
3746
3747 rb_fd_set_nonblock(fptr->fd);
3748 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3749 RB_GC_GUARD(str);
3750
3751 if (n < 0) {
3752 int e = errno;
3753 if (io_again_p(e)) {
3754 if (!ex) {
3755 return sym_wait_writable;
3756 }
3757 else {
3758 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3759 }
3760 }
3761 rb_syserr_fail_path(e, fptr->pathv);
3762 }
3763
3764 return LONG2FIX(n);
3765}
3766
3767/*
3768 * call-seq:
3769 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3770 *
3771 * Reads bytes from the stream; the stream must be opened for reading
3772 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3773 *
3774 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3775 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3776 *
3777 * Returns a string (either a new string or the given +out_string+)
3778 * containing the bytes read.
3779 * The encoding of the string depends on both +maxLen+ and +out_string+:
3780 *
3781 * - +maxlen+ is +nil+: uses internal encoding of +self+
3782 * (regardless of whether +out_string+ was given).
3783 * - +maxlen+ not +nil+:
3784 *
3785 * - +out_string+ given: encoding of +out_string+ not modified.
3786 * - +out_string+ not given: ASCII-8BIT is used.
3787 *
3788 * <b>Without Argument +out_string+</b>
3789 *
3790 * When argument +out_string+ is omitted,
3791 * the returned value is a new string:
3792 *
3793 * f = File.new('t.txt')
3794 * f.read
3795 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3796 * f.rewind
3797 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3798 * f.read(30) # => "rth line\r\nFifth line\r\n"
3799 * f.read(30) # => nil
3800 * f.close
3801 *
3802 * If +maxlen+ is zero, returns an empty string.
3803 *
3804 * <b> With Argument +out_string+</b>
3805 *
3806 * When argument +out_string+ is given,
3807 * the returned value is +out_string+, whose content is replaced:
3808 *
3809 * f = File.new('t.txt')
3810 * s = 'foo' # => "foo"
3811 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3812 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3813 * f.rewind
3814 * s = 'bar'
3815 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3816 * s # => "First line\r\nSecond line\r\n\r\nFou"
3817 * s = 'baz'
3818 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3819 * s # => "rth line\r\nFifth line\r\n"
3820 * s = 'bat'
3821 * f.read(30, s) # => nil
3822 * s # => ""
3823 * f.close
3824 *
3825 * Note that this method behaves like the fread() function in C.
3826 * This means it retries to invoke read(2) system calls to read data
3827 * with the specified maxlen (or until EOF).
3828 *
3829 * This behavior is preserved even if the stream is in non-blocking mode.
3830 * (This method is non-blocking-flag insensitive as other methods.)
3831 *
3832 * If you need the behavior like a single read(2) system call,
3833 * consider #readpartial, #read_nonblock, and #sysread.
3834 *
3835 * Related: IO#write.
3836 */
3837
3838static VALUE
3839io_read(int argc, VALUE *argv, VALUE io)
3840{
3841 rb_io_t *fptr;
3842 long n, len;
3843 VALUE length, str;
3844 int shrinkable;
3845#if RUBY_CRLF_ENVIRONMENT
3846 int previous_mode;
3847#endif
3848
3849 rb_scan_args(argc, argv, "02", &length, &str);
3850
3851 if (NIL_P(length)) {
3852 GetOpenFile(io, fptr);
3854 return read_all(fptr, remain_size(fptr), str);
3855 }
3856 len = NUM2LONG(length);
3857 if (len < 0) {
3858 rb_raise(rb_eArgError, "negative length %ld given", len);
3859 }
3860
3861 shrinkable = io_setstrbuf(&str,len);
3862
3863 GetOpenFile(io, fptr);
3865 if (len == 0) {
3866 io_set_read_length(str, 0, shrinkable);
3867 return str;
3868 }
3869
3870 READ_CHECK(fptr);
3871#if RUBY_CRLF_ENVIRONMENT
3872 previous_mode = set_binary_mode_with_seek_cur(fptr);
3873#endif
3874 n = io_fread(str, 0, len, fptr);
3875 io_set_read_length(str, n, shrinkable);
3876#if RUBY_CRLF_ENVIRONMENT
3877 if (previous_mode == O_TEXT) {
3878 setmode(fptr->fd, O_TEXT);
3879 }
3880#endif
3881 if (n == 0) return Qnil;
3882
3883 return str;
3884}
3885
3886static void
3887rscheck(const char *rsptr, long rslen, VALUE rs)
3888{
3889 if (!rs) return;
3890 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3891 rb_raise(rb_eRuntimeError, "rs modified");
3892}
3893
3894static const char *
3895search_delim(const char *p, long len, int delim, rb_encoding *enc)
3896{
3897 if (rb_enc_mbminlen(enc) == 1) {
3898 p = memchr(p, delim, len);
3899 if (p) return p + 1;
3900 }
3901 else {
3902 const char *end = p + len;
3903 while (p < end) {
3904 int r = rb_enc_precise_mbclen(p, end, enc);
3905 if (!MBCLEN_CHARFOUND_P(r)) {
3906 p += rb_enc_mbminlen(enc);
3907 continue;
3908 }
3909 int n = MBCLEN_CHARFOUND_LEN(r);
3910 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3911 return p + n;
3912 }
3913 p += n;
3914 }
3915 }
3916 return NULL;
3917}
3918
3919static int
3920appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3921{
3922 VALUE str = *strp;
3923 long limit = *lp;
3924
3925 if (NEED_READCONV(fptr)) {
3926 SET_BINARY_MODE(fptr);
3927 make_readconv(fptr, 0);
3928 do {
3929 const char *p, *e;
3930 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3931 if (searchlen) {
3932 p = READ_CHAR_PENDING_PTR(fptr);
3933 if (0 < limit && limit < searchlen)
3934 searchlen = (int)limit;
3935 e = search_delim(p, searchlen, delim, enc);
3936 if (e) {
3937 int len = (int)(e-p);
3938 if (NIL_P(str))
3939 *strp = str = rb_str_new(p, len);
3940 else
3941 rb_str_buf_cat(str, p, len);
3942 fptr->cbuf.off += len;
3943 fptr->cbuf.len -= len;
3944 limit -= len;
3945 *lp = limit;
3946 return delim;
3947 }
3948
3949 if (NIL_P(str))
3950 *strp = str = rb_str_new(p, searchlen);
3951 else
3952 rb_str_buf_cat(str, p, searchlen);
3953 fptr->cbuf.off += searchlen;
3954 fptr->cbuf.len -= searchlen;
3955 limit -= searchlen;
3956
3957 if (limit == 0) {
3958 *lp = limit;
3959 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3960 }
3961 }
3962 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3963 clear_readconv(fptr);
3964 *lp = limit;
3965 return EOF;
3966 }
3967
3968 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3969 do {
3970 long pending = READ_DATA_PENDING_COUNT(fptr);
3971 if (pending > 0) {
3972 const char *p = READ_DATA_PENDING_PTR(fptr);
3973 const char *e;
3974 long last;
3975
3976 if (limit > 0 && pending > limit) pending = limit;
3977 e = search_delim(p, pending, delim, enc);
3978 if (e) pending = e - p;
3979 if (!NIL_P(str)) {
3980 last = RSTRING_LEN(str);
3981 rb_str_resize(str, last + pending);
3982 }
3983 else {
3984 last = 0;
3985 *strp = str = rb_str_buf_new(pending);
3986 rb_str_set_len(str, pending);
3987 }
3988 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3989 limit -= pending;
3990 *lp = limit;
3991 if (e) return delim;
3992 if (limit == 0)
3993 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3994 }
3995 READ_CHECK(fptr);
3996 } while (io_fillbuf(fptr) >= 0);
3997 *lp = limit;
3998 return EOF;
3999}
4000
4001static inline int
4002swallow(rb_io_t *fptr, int term)
4003{
4004 if (NEED_READCONV(fptr)) {
4005 rb_encoding *enc = io_read_encoding(fptr);
4006 int needconv = rb_enc_mbminlen(enc) != 1;
4007 SET_BINARY_MODE(fptr);
4008 make_readconv(fptr, 0);
4009 do {
4010 size_t cnt;
4011 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4012 const char *p = READ_CHAR_PENDING_PTR(fptr);
4013 int i;
4014 if (!needconv) {
4015 if (*p != term) return TRUE;
4016 i = (int)cnt;
4017 while (--i && *++p == term);
4018 }
4019 else {
4020 const char *e = p + cnt;
4021 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4022 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4023 i = (int)(e - p);
4024 }
4025 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4026 }
4027 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4028 return FALSE;
4029 }
4030
4031 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4032 do {
4033 size_t cnt;
4034 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4035 char buf[1024];
4036 const char *p = READ_DATA_PENDING_PTR(fptr);
4037 int i;
4038 if (cnt > sizeof buf) cnt = sizeof buf;
4039 if (*p != term) return TRUE;
4040 i = (int)cnt;
4041 while (--i && *++p == term);
4042 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4043 rb_sys_fail_path(fptr->pathv);
4044 }
4045 READ_CHECK(fptr);
4046 } while (io_fillbuf(fptr) == 0);
4047 return FALSE;
4048}
4049
4050static VALUE
4051rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4052{
4053 VALUE str = Qnil;
4054 int len = 0;
4055 long pos = 0;
4056 int cr = 0;
4057
4058 do {
4059 int pending = READ_DATA_PENDING_COUNT(fptr);
4060
4061 if (pending > 0) {
4062 const char *p = READ_DATA_PENDING_PTR(fptr);
4063 const char *e;
4064 int chomplen = 0;
4065
4066 e = memchr(p, '\n', pending);
4067 if (e) {
4068 pending = (int)(e - p + 1);
4069 if (chomp) {
4070 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4071 }
4072 }
4073 if (NIL_P(str)) {
4074 str = rb_str_new(p, pending - chomplen);
4075 fptr->rbuf.off += pending;
4076 fptr->rbuf.len -= pending;
4077 }
4078 else {
4079 rb_str_resize(str, len + pending - chomplen);
4080 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4081 fptr->rbuf.off += chomplen;
4082 fptr->rbuf.len -= chomplen;
4083 if (pending == 1 && chomplen == 1 && len > 0) {
4084 if (RSTRING_PTR(str)[len-1] == '\r') {
4085 rb_str_resize(str, --len);
4086 break;
4087 }
4088 }
4089 }
4090 len += pending - chomplen;
4091 if (cr != ENC_CODERANGE_BROKEN)
4092 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4093 if (e) break;
4094 }
4095 READ_CHECK(fptr);
4096 } while (io_fillbuf(fptr) >= 0);
4097 if (NIL_P(str)) return Qnil;
4098
4099 str = io_enc_str(str, fptr);
4100 ENC_CODERANGE_SET(str, cr);
4101 fptr->lineno++;
4102
4103 return str;
4104}
4105
4107 VALUE io;
4108 VALUE rs;
4109 long limit;
4110 unsigned int chomp: 1;
4111};
4112
4113static void
4114extract_getline_opts(VALUE opts, struct getline_arg *args)
4115{
4116 int chomp = FALSE;
4117 if (!NIL_P(opts)) {
4118 static ID kwds[1];
4119 VALUE vchomp;
4120 if (!kwds[0]) {
4121 kwds[0] = rb_intern_const("chomp");
4122 }
4123 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4124 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4125 }
4126 args->chomp = chomp;
4127}
4128
4129static void
4130extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4131{
4132 VALUE rs = rb_rs, lim = Qnil;
4133
4134 if (argc == 1) {
4135 VALUE tmp = Qnil;
4136
4137 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4138 rs = tmp;
4139 }
4140 else {
4141 lim = argv[0];
4142 }
4143 }
4144 else if (2 <= argc) {
4145 rs = argv[0], lim = argv[1];
4146 if (!NIL_P(rs))
4147 StringValue(rs);
4148 }
4149 args->rs = rs;
4150 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4151}
4152
4153static void
4154check_getline_args(VALUE *rsp, long *limit, VALUE io)
4155{
4156 rb_io_t *fptr;
4157 VALUE rs = *rsp;
4158
4159 if (!NIL_P(rs)) {
4160 rb_encoding *enc_rs, *enc_io;
4161
4162 GetOpenFile(io, fptr);
4163 enc_rs = rb_enc_get(rs);
4164 enc_io = io_read_encoding(fptr);
4165 if (enc_io != enc_rs &&
4166 (!is_ascii_string(rs) ||
4167 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4168 if (rs == rb_default_rs) {
4169 rs = rb_enc_str_new(0, 0, enc_io);
4170 rb_str_buf_cat_ascii(rs, "\n");
4171 *rsp = rs;
4172 }
4173 else {
4174 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4175 rb_enc_name(enc_io),
4176 rb_enc_name(enc_rs));
4177 }
4178 }
4179 }
4180}
4181
4182static void
4183prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4184{
4185 VALUE opts;
4186 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4187 extract_getline_args(argc, argv, args);
4188 extract_getline_opts(opts, args);
4189 check_getline_args(&args->rs, &args->limit, io);
4190}
4191
4192static VALUE
4193rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4194{
4195 VALUE str = Qnil;
4196 int nolimit = 0;
4197 rb_encoding *enc;
4198
4200 if (NIL_P(rs) && limit < 0) {
4201 str = read_all(fptr, 0, Qnil);
4202 if (RSTRING_LEN(str) == 0) return Qnil;
4203 }
4204 else if (limit == 0) {
4205 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4206 }
4207 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4208 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4209 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4210 return rb_io_getline_fast(fptr, enc, chomp);
4211 }
4212 else {
4213 int c, newline = -1;
4214 const char *rsptr = 0;
4215 long rslen = 0;
4216 int rspara = 0;
4217 int extra_limit = 16;
4218 int chomp_cr = chomp;
4219
4220 SET_BINARY_MODE(fptr);
4221 enc = io_read_encoding(fptr);
4222
4223 if (!NIL_P(rs)) {
4224 rslen = RSTRING_LEN(rs);
4225 if (rslen == 0) {
4226 rsptr = "\n\n";
4227 rslen = 2;
4228 rspara = 1;
4229 swallow(fptr, '\n');
4230 rs = 0;
4231 if (!rb_enc_asciicompat(enc)) {
4232 rs = rb_usascii_str_new(rsptr, rslen);
4233 rs = rb_str_conv_enc(rs, 0, enc);
4234 OBJ_FREEZE(rs);
4235 rsptr = RSTRING_PTR(rs);
4236 rslen = RSTRING_LEN(rs);
4237 }
4238 newline = '\n';
4239 }
4240 else if (rb_enc_mbminlen(enc) == 1) {
4241 rsptr = RSTRING_PTR(rs);
4242 newline = (unsigned char)rsptr[rslen - 1];
4243 }
4244 else {
4245 rs = rb_str_conv_enc(rs, 0, enc);
4246 rsptr = RSTRING_PTR(rs);
4247 const char *e = rsptr + rslen;
4248 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4249 int n;
4250 newline = rb_enc_codepoint_len(last, e, &n, enc);
4251 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4252 }
4253 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4254 }
4255
4256 /* MS - Optimization */
4257 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4258 const char *s, *p, *pp, *e;
4259
4260 if (c == newline) {
4261 if (RSTRING_LEN(str) < rslen) continue;
4262 s = RSTRING_PTR(str);
4263 e = RSTRING_END(str);
4264 p = e - rslen;
4265 if (!at_char_boundary(s, p, e, enc)) continue;
4266 if (!rspara) rscheck(rsptr, rslen, rs);
4267 if (memcmp(p, rsptr, rslen) == 0) {
4268 if (chomp) {
4269 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4270 rb_str_set_len(str, p - s);
4271 }
4272 break;
4273 }
4274 }
4275 if (limit == 0) {
4276 s = RSTRING_PTR(str);
4277 p = RSTRING_END(str);
4278 pp = rb_enc_prev_char(s, p, p, enc);
4279 if (extra_limit && pp &&
4280 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4281 /* relax the limit while incomplete character.
4282 * extra_limit limits the relax length */
4283 limit = 1;
4284 extra_limit--;
4285 }
4286 else {
4287 nolimit = 1;
4288 break;
4289 }
4290 }
4291 }
4292
4293 if (rspara && c != EOF)
4294 swallow(fptr, '\n');
4295 if (!NIL_P(str))
4296 str = io_enc_str(str, fptr);
4297 }
4298
4299 if (!NIL_P(str) && !nolimit) {
4300 fptr->lineno++;
4301 }
4302
4303 return str;
4304}
4305
4306static VALUE
4307rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4308{
4309 rb_io_t *fptr;
4310 int old_lineno, new_lineno;
4311 VALUE str;
4312
4313 GetOpenFile(io, fptr);
4314 old_lineno = fptr->lineno;
4315 str = rb_io_getline_0(rs, limit, chomp, fptr);
4316 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4317 if (io == ARGF.current_file) {
4318 ARGF.lineno += new_lineno - old_lineno;
4319 ARGF.last_lineno = ARGF.lineno;
4320 }
4321 else {
4322 ARGF.last_lineno = new_lineno;
4323 }
4324 }
4325
4326 return str;
4327}
4328
4329static VALUE
4330rb_io_getline(int argc, VALUE *argv, VALUE io)
4331{
4332 struct getline_arg args;
4333
4334 prepare_getline_args(argc, argv, &args, io);
4335 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4336}
4337
4338VALUE
4340{
4341 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4342}
4343
4344VALUE
4345rb_io_gets_limit_internal(VALUE io, long limit)
4346{
4347 rb_io_t *fptr;
4348 GetOpenFile(io, fptr);
4349 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4350}
4351
4352VALUE
4353rb_io_gets_internal(VALUE io)
4354{
4355 return rb_io_gets_limit_internal(io, -1);
4356}
4357
4358/*
4359 * call-seq:
4360 * gets(sep = $/, chomp: false) -> string or nil
4361 * gets(limit, chomp: false) -> string or nil
4362 * gets(sep, limit, chomp: false) -> string or nil
4363 *
4364 * Reads and returns a line from the stream;
4365 * assigns the return value to <tt>$_</tt>.
4366 * See {Line IO}[rdoc-ref:IO@Line+IO].
4367 *
4368 * With no arguments given, returns the next line
4369 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4370 *
4371 * f = File.open('t.txt')
4372 * f.gets # => "First line\n"
4373 * $_ # => "First line\n"
4374 * f.gets # => "\n"
4375 * f.gets # => "Fourth line\n"
4376 * f.gets # => "Fifth line\n"
4377 * f.gets # => nil
4378 * f.close
4379 *
4380 * With only string argument +sep+ given,
4381 * returns the next line as determined by line separator +sep+,
4382 * or +nil+ if none;
4383 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4384 *
4385 * f = File.new('t.txt')
4386 * f.gets('l') # => "First l"
4387 * f.gets('li') # => "ine\nSecond li"
4388 * f.gets('lin') # => "ne\n\nFourth lin"
4389 * f.gets # => "e\n"
4390 * f.close
4391 *
4392 * The two special values for +sep+ are honored:
4393 *
4394 * f = File.new('t.txt')
4395 * # Get all.
4396 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4397 * f.rewind
4398 * # Get paragraph (up to two line separators).
4399 * f.gets('') # => "First line\nSecond line\n\n"
4400 * f.close
4401 *
4402 * With only integer argument +limit+ given,
4403 * limits the number of bytes in the line;
4404 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4405 *
4406 * # No more than one line.
4407 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4408 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4409 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4410 *
4411 * With arguments +sep+ and +limit+ given,
4412 * combines the two behaviors
4413 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4414 *
4415 * Optional keyword argument +chomp+ specifies whether line separators
4416 * are to be omitted:
4417 *
4418 * f = File.open('t.txt')
4419 * # Chomp the lines.
4420 * f.gets(chomp: true) # => "First line"
4421 * f.gets(chomp: true) # => "Second line"
4422 * f.gets(chomp: true) # => ""
4423 * f.gets(chomp: true) # => "Fourth line"
4424 * f.gets(chomp: true) # => "Fifth line"
4425 * f.gets(chomp: true) # => nil
4426 * f.close
4427 *
4428 */
4429
4430static VALUE
4431rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4432{
4433 VALUE str;
4434
4435 str = rb_io_getline(argc, argv, io);
4436 rb_lastline_set(str);
4437
4438 return str;
4439}
4440
4441/*
4442 * call-seq:
4443 * lineno -> integer
4444 *
4445 * Returns the current line number for the stream;
4446 * see {Line Number}[rdoc-ref:IO@Line+Number].
4447 *
4448 */
4449
4450static VALUE
4451rb_io_lineno(VALUE io)
4452{
4453 rb_io_t *fptr;
4454
4455 GetOpenFile(io, fptr);
4457 return INT2NUM(fptr->lineno);
4458}
4459
4460/*
4461 * call-seq:
4462 * lineno = integer -> integer
4463 *
4464 * Sets and returns the line number for the stream;
4465 * see {Line Number}[rdoc-ref:IO@Line+Number].
4466 *
4467 */
4468
4469static VALUE
4470rb_io_set_lineno(VALUE io, VALUE lineno)
4471{
4472 rb_io_t *fptr;
4473
4474 GetOpenFile(io, fptr);
4476 fptr->lineno = NUM2INT(lineno);
4477 return lineno;
4478}
4479
4480/* :nodoc: */
4481static VALUE
4482io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4483{
4484 long limit = -1;
4485 if (NIL_P(lim)) {
4486 VALUE tmp = Qnil;
4487 // If sep is specified, but it's not a string and not nil, then assume
4488 // it's the limit (it should be an integer)
4489 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4490 // If the user has specified a non-nil / non-string value
4491 // for the separator, we assume it's the limit and set the
4492 // separator to default: rb_rs.
4493 lim = sep;
4494 limit = NUM2LONG(lim);
4495 sep = rb_rs;
4496 }
4497 else {
4498 sep = tmp;
4499 }
4500 }
4501 else {
4502 if (!NIL_P(sep)) StringValue(sep);
4503 limit = NUM2LONG(lim);
4504 }
4505
4506 check_getline_args(&sep, &limit, io);
4507
4508 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4509 rb_lastline_set_up(line, 1);
4510
4511 if (NIL_P(line)) {
4512 rb_eof_error();
4513 }
4514 return line;
4515}
4516
4517static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4518
4519/*
4520 * call-seq:
4521 * readlines(sep = $/, chomp: false) -> array
4522 * readlines(limit, chomp: false) -> array
4523 * readlines(sep, limit, chomp: false) -> array
4524 *
4525 * Reads and returns all remaining line from the stream;
4526 * does not modify <tt>$_</tt>.
4527 * See {Line IO}[rdoc-ref:IO@Line+IO].
4528 *
4529 * With no arguments given, returns lines
4530 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4531 *
4532 * f = File.new('t.txt')
4533 * f.readlines
4534 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4535 * f.readlines # => []
4536 * f.close
4537 *
4538 * With only string argument +sep+ given,
4539 * returns lines as determined by line separator +sep+,
4540 * or +nil+ if none;
4541 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4542 *
4543 * f = File.new('t.txt')
4544 * f.readlines('li')
4545 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4546 * f.close
4547 *
4548 * The two special values for +sep+ are honored:
4549 *
4550 * f = File.new('t.txt')
4551 * # Get all into one string.
4552 * f.readlines(nil)
4553 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4554 * # Get paragraphs (up to two line separators).
4555 * f.rewind
4556 * f.readlines('')
4557 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4558 * f.close
4559 *
4560 * With only integer argument +limit+ given,
4561 * limits the number of bytes in each line;
4562 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4563 *
4564 * f = File.new('t.txt')
4565 * f.readlines(8)
4566 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4567 * f.close
4568 *
4569 * With arguments +sep+ and +limit+ given,
4570 * combines the two behaviors
4571 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4572 *
4573 * Optional keyword argument +chomp+ specifies whether line separators
4574 * are to be omitted:
4575 *
4576 * f = File.new('t.txt')
4577 * f.readlines(chomp: true)
4578 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4579 * f.close
4580 *
4581 */
4582
4583static VALUE
4584rb_io_readlines(int argc, VALUE *argv, VALUE io)
4585{
4586 struct getline_arg args;
4587
4588 prepare_getline_args(argc, argv, &args, io);
4589 return io_readlines(&args, io);
4590}
4591
4592static VALUE
4593io_readlines(const struct getline_arg *arg, VALUE io)
4594{
4595 VALUE line, ary;
4596
4597 if (arg->limit == 0)
4598 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4599 ary = rb_ary_new();
4600 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4601 rb_ary_push(ary, line);
4602 }
4603 return ary;
4604}
4605
4606/*
4607 * call-seq:
4608 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4609 * each_line(limit, chomp: false) {|line| ... } -> self
4610 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4611 * each_line -> enumerator
4612 *
4613 * Calls the block with each remaining line read from the stream;
4614 * returns +self+.
4615 * Does nothing if already at end-of-stream;
4616 * See {Line IO}[rdoc-ref:IO@Line+IO].
4617 *
4618 * With no arguments given, reads lines
4619 * as determined by line separator <tt>$/</tt>:
4620 *
4621 * f = File.new('t.txt')
4622 * f.each_line {|line| p line }
4623 * f.each_line {|line| fail 'Cannot happen' }
4624 * f.close
4625 *
4626 * Output:
4627 *
4628 * "First line\n"
4629 * "Second line\n"
4630 * "\n"
4631 * "Fourth line\n"
4632 * "Fifth line\n"
4633 *
4634 * With only string argument +sep+ given,
4635 * reads lines as determined by line separator +sep+;
4636 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4637 *
4638 * f = File.new('t.txt')
4639 * f.each_line('li') {|line| p line }
4640 * f.close
4641 *
4642 * Output:
4643 *
4644 * "First li"
4645 * "ne\nSecond li"
4646 * "ne\n\nFourth li"
4647 * "ne\nFifth li"
4648 * "ne\n"
4649 *
4650 * The two special values for +sep+ are honored:
4651 *
4652 * f = File.new('t.txt')
4653 * # Get all into one string.
4654 * f.each_line(nil) {|line| p line }
4655 * f.close
4656 *
4657 * Output:
4658 *
4659 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4660 *
4661 * f.rewind
4662 * # Get paragraphs (up to two line separators).
4663 * f.each_line('') {|line| p line }
4664 *
4665 * Output:
4666 *
4667 * "First line\nSecond line\n\n"
4668 * "Fourth line\nFifth line\n"
4669 *
4670 * With only integer argument +limit+ given,
4671 * limits the number of bytes in each line;
4672 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4673 *
4674 * f = File.new('t.txt')
4675 * f.each_line(8) {|line| p line }
4676 * f.close
4677 *
4678 * Output:
4679 *
4680 * "First li"
4681 * "ne\n"
4682 * "Second l"
4683 * "ine\n"
4684 * "\n"
4685 * "Fourth l"
4686 * "ine\n"
4687 * "Fifth li"
4688 * "ne\n"
4689 *
4690 * With arguments +sep+ and +limit+ given,
4691 * combines the two behaviors
4692 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4693 *
4694 * Optional keyword argument +chomp+ specifies whether line separators
4695 * are to be omitted:
4696 *
4697 * f = File.new('t.txt')
4698 * f.each_line(chomp: true) {|line| p line }
4699 * f.close
4700 *
4701 * Output:
4702 *
4703 * "First line"
4704 * "Second line"
4705 * ""
4706 * "Fourth line"
4707 * "Fifth line"
4708 *
4709 * Returns an Enumerator if no block is given.
4710 */
4711
4712static VALUE
4713rb_io_each_line(int argc, VALUE *argv, VALUE io)
4714{
4715 VALUE str;
4716 struct getline_arg args;
4717
4718 RETURN_ENUMERATOR(io, argc, argv);
4719 prepare_getline_args(argc, argv, &args, io);
4720 if (args.limit == 0)
4721 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4722 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4723 rb_yield(str);
4724 }
4725 return io;
4726}
4727
4728/*
4729 * call-seq:
4730 * each_byte {|byte| ... } -> self
4731 * each_byte -> enumerator
4732 *
4733 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4734 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4735 *
4736 * File.read('t.ja') # => "こんにちは"
4737 * f = File.new('t.ja')
4738 * a = []
4739 * f.each_byte {|b| a << b }
4740 * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
4741 * f.close
4742 *
4743 * Returns an Enumerator if no block is given.
4744 *
4745 * Related: IO#each_char, IO#each_codepoint.
4746 *
4747 */
4748
4749static VALUE
4750rb_io_each_byte(VALUE io)
4751{
4752 rb_io_t *fptr;
4753
4754 RETURN_ENUMERATOR(io, 0, 0);
4755 GetOpenFile(io, fptr);
4756
4757 do {
4758 while (fptr->rbuf.len > 0) {
4759 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4760 fptr->rbuf.len--;
4761 rb_yield(INT2FIX(*p & 0xff));
4763 errno = 0;
4764 }
4765 READ_CHECK(fptr);
4766 } while (io_fillbuf(fptr) >= 0);
4767 return io;
4768}
4769
4770static VALUE
4771io_getc(rb_io_t *fptr, rb_encoding *enc)
4772{
4773 int r, n, cr = 0;
4774 VALUE str;
4775
4776 if (NEED_READCONV(fptr)) {
4777 rb_encoding *read_enc = io_read_encoding(fptr);
4778
4779 str = Qnil;
4780 SET_BINARY_MODE(fptr);
4781 make_readconv(fptr, 0);
4782
4783 while (1) {
4784 if (fptr->cbuf.len) {
4785 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4786 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4787 read_enc);
4788 if (!MBCLEN_NEEDMORE_P(r))
4789 break;
4790 if (fptr->cbuf.len == fptr->cbuf.capa) {
4791 rb_raise(rb_eIOError, "too long character");
4792 }
4793 }
4794
4795 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4796 if (fptr->cbuf.len == 0) {
4797 clear_readconv(fptr);
4798 return Qnil;
4799 }
4800 /* return an unit of an incomplete character just before EOF */
4801 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4802 fptr->cbuf.off += 1;
4803 fptr->cbuf.len -= 1;
4804 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4806 return str;
4807 }
4808 }
4809 if (MBCLEN_INVALID_P(r)) {
4810 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4811 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4812 read_enc);
4813 io_shift_cbuf(fptr, r, &str);
4815 }
4816 else {
4817 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4819 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4820 ISASCII(RSTRING_PTR(str)[0])) {
4821 cr = ENC_CODERANGE_7BIT;
4822 }
4823 }
4824 str = io_enc_str(str, fptr);
4825 ENC_CODERANGE_SET(str, cr);
4826 return str;
4827 }
4828
4829 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4830 if (io_fillbuf(fptr) < 0) {
4831 return Qnil;
4832 }
4833 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4834 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4835 fptr->rbuf.off += 1;
4836 fptr->rbuf.len -= 1;
4837 cr = ENC_CODERANGE_7BIT;
4838 }
4839 else {
4840 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4841 if (MBCLEN_CHARFOUND_P(r) &&
4842 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4843 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4844 fptr->rbuf.off += n;
4845 fptr->rbuf.len -= n;
4847 }
4848 else if (MBCLEN_NEEDMORE_P(r)) {
4849 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4850 fptr->rbuf.len = 0;
4851 getc_needmore:
4852 if (io_fillbuf(fptr) != -1) {
4853 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4854 fptr->rbuf.off++;
4855 fptr->rbuf.len--;
4856 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4857 if (MBCLEN_NEEDMORE_P(r)) {
4858 goto getc_needmore;
4859 }
4860 else if (MBCLEN_CHARFOUND_P(r)) {
4862 }
4863 }
4864 }
4865 else {
4866 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4867 fptr->rbuf.off++;
4868 fptr->rbuf.len--;
4869 }
4870 }
4871 if (!cr) cr = ENC_CODERANGE_BROKEN;
4872 str = io_enc_str(str, fptr);
4873 ENC_CODERANGE_SET(str, cr);
4874 return str;
4875}
4876
4877/*
4878 * call-seq:
4879 * each_char {|c| ... } -> self
4880 * each_char -> enumerator
4881 *
4882 * Calls the given block with each character in the stream; returns +self+.
4883 * See {Character IO}[rdoc-ref:IO@Character+IO].
4884 *
4885 * File.read('t.ja') # => "こんにちは"
4886 * f = File.new('t.ja')
4887 * a = []
4888 * f.each_char {|c| a << c.ord }
4889 * a # => [12371, 12435, 12395, 12385, 12399]
4890 * f.close
4891 *
4892 * Returns an Enumerator if no block is given.
4893 *
4894 * Related: IO#each_byte, IO#each_codepoint.
4895 *
4896 */
4897
4898static VALUE
4899rb_io_each_char(VALUE io)
4900{
4901 rb_io_t *fptr;
4902 rb_encoding *enc;
4903 VALUE c;
4904
4905 RETURN_ENUMERATOR(io, 0, 0);
4906 GetOpenFile(io, fptr);
4908
4909 enc = io_input_encoding(fptr);
4910 READ_CHECK(fptr);
4911 while (!NIL_P(c = io_getc(fptr, enc))) {
4912 rb_yield(c);
4913 }
4914 return io;
4915}
4916
4917/*
4918 * call-seq:
4919 * each_codepoint {|c| ... } -> self
4920 * each_codepoint -> enumerator
4921 *
4922 * Calls the given block with each codepoint in the stream; returns +self+:
4923 *
4924 * File.read('t.ja') # => "こんにちは"
4925 * f = File.new('t.ja')
4926 * a = []
4927 * f.each_codepoint {|c| a << c }
4928 * a # => [12371, 12435, 12395, 12385, 12399]
4929 * f.close
4930 *
4931 * Returns an Enumerator if no block is given.
4932 *
4933 * Related: IO#each_byte, IO#each_char.
4934 *
4935 */
4936
4937static VALUE
4938rb_io_each_codepoint(VALUE io)
4939{
4940 rb_io_t *fptr;
4941 rb_encoding *enc;
4942 unsigned int c;
4943 int r, n;
4944
4945 RETURN_ENUMERATOR(io, 0, 0);
4946 GetOpenFile(io, fptr);
4948
4949 READ_CHECK(fptr);
4950 enc = io_read_encoding(fptr);
4951 if (NEED_READCONV(fptr)) {
4952 SET_BINARY_MODE(fptr);
4953 r = 1; /* no invalid char yet */
4954 for (;;) {
4955 make_readconv(fptr, 0);
4956 for (;;) {
4957 if (fptr->cbuf.len) {
4958 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4959 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4960 enc);
4961 if (!MBCLEN_NEEDMORE_P(r))
4962 break;
4963 if (fptr->cbuf.len == fptr->cbuf.capa) {
4964 rb_raise(rb_eIOError, "too long character");
4965 }
4966 }
4967 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4968 clear_readconv(fptr);
4969 if (!MBCLEN_CHARFOUND_P(r)) {
4970 goto invalid;
4971 }
4972 return io;
4973 }
4974 }
4975 if (MBCLEN_INVALID_P(r)) {
4976 goto invalid;
4977 }
4978 n = MBCLEN_CHARFOUND_LEN(r);
4979 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4980 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4981 enc);
4982 fptr->cbuf.off += n;
4983 fptr->cbuf.len -= n;
4984 rb_yield(UINT2NUM(c));
4986 }
4987 }
4988 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4989 while (io_fillbuf(fptr) >= 0) {
4990 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4991 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4992 if (MBCLEN_CHARFOUND_P(r) &&
4993 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4994 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4995 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4996 fptr->rbuf.off += n;
4997 fptr->rbuf.len -= n;
4998 rb_yield(UINT2NUM(c));
4999 }
5000 else if (MBCLEN_INVALID_P(r)) {
5001 goto invalid;
5002 }
5003 else if (MBCLEN_NEEDMORE_P(r)) {
5004 char cbuf[8], *p = cbuf;
5005 int more = MBCLEN_NEEDMORE_LEN(r);
5006 if (more > numberof(cbuf)) goto invalid;
5007 more += n = fptr->rbuf.len;
5008 if (more > numberof(cbuf)) goto invalid;
5009 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
5010 (p += n, (more -= n) > 0)) {
5011 if (io_fillbuf(fptr) < 0) goto invalid;
5012 if ((n = fptr->rbuf.len) > more) n = more;
5013 }
5014 r = rb_enc_precise_mbclen(cbuf, p, enc);
5015 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5016 c = rb_enc_codepoint(cbuf, p, enc);
5017 rb_yield(UINT2NUM(c));
5018 }
5019 else {
5020 continue;
5021 }
5023 }
5024 return io;
5025
5026 invalid:
5027 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5029}
5030
5031/*
5032 * call-seq:
5033 * getc -> character or nil
5034 *
5035 * Reads and returns the next 1-character string from the stream;
5036 * returns +nil+ if already at end-of-stream.
5037 * See {Character IO}[rdoc-ref:IO@Character+IO].
5038 *
5039 * f = File.open('t.txt')
5040 * f.getc # => "F"
5041 * f.close
5042 * File.read('t.ja') # => "こんにちは"
5043 * f = File.open('t.ja')
5044 * f.getc.ord # => 12371
5045 * f.close
5046 *
5047 * Related: IO#readchar (may raise EOFError).
5048 *
5049 */
5050
5051static VALUE
5052rb_io_getc(VALUE io)
5053{
5054 rb_io_t *fptr;
5055 rb_encoding *enc;
5056
5057 GetOpenFile(io, fptr);
5059
5060 enc = io_input_encoding(fptr);
5061 READ_CHECK(fptr);
5062 return io_getc(fptr, enc);
5063}
5064
5065/*
5066 * call-seq:
5067 * readchar -> string
5068 *
5069 * Reads and returns the next 1-character string from the stream;
5070 * raises EOFError if already at end-of-stream.
5071 * See {Character IO}[rdoc-ref:IO@Character+IO].
5072 *
5073 * f = File.open('t.txt')
5074 * f.readchar # => "F"
5075 * f.close
5076 * File.read('t.ja') # => "こんにちは"
5077 * f = File.open('t.ja')
5078 * f.readchar.ord # => 12371
5079 * f.close
5080 *
5081 * Related: IO#getc (will not raise EOFError).
5082 *
5083 */
5084
5085static VALUE
5086rb_io_readchar(VALUE io)
5087{
5088 VALUE c = rb_io_getc(io);
5089
5090 if (NIL_P(c)) {
5091 rb_eof_error();
5092 }
5093 return c;
5094}
5095
5096/*
5097 * call-seq:
5098 * getbyte -> integer or nil
5099 *
5100 * Reads and returns the next byte (in range 0..255) from the stream;
5101 * returns +nil+ if already at end-of-stream.
5102 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5103 *
5104 * f = File.open('t.txt')
5105 * f.getbyte # => 70
5106 * f.close
5107 * File.read('t.ja') # => "こんにちは"
5108 * f = File.open('t.ja')
5109 * f.getbyte # => 227
5110 * f.close
5111 *
5112 * Related: IO#readbyte (may raise EOFError).
5113 */
5114
5115VALUE
5117{
5118 rb_io_t *fptr;
5119 int c;
5120
5121 GetOpenFile(io, fptr);
5123 READ_CHECK(fptr);
5124 VALUE r_stdout = rb_ractor_stdout();
5125 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5126 rb_io_t *ofp;
5127 GetOpenFile(r_stdout, ofp);
5128 if (ofp->mode & FMODE_TTY) {
5129 rb_io_flush(r_stdout);
5130 }
5131 }
5132 if (io_fillbuf(fptr) < 0) {
5133 return Qnil;
5134 }
5135 fptr->rbuf.off++;
5136 fptr->rbuf.len--;
5137 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5138 return INT2FIX(c & 0xff);
5139}
5140
5141/*
5142 * call-seq:
5143 * readbyte -> integer
5144 *
5145 * Reads and returns the next byte (in range 0..255) from the stream;
5146 * raises EOFError if already at end-of-stream.
5147 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5148 *
5149 * f = File.open('t.txt')
5150 * f.readbyte # => 70
5151 * f.close
5152 * File.read('t.ja') # => "こんにちは"
5153 * f = File.open('t.ja')
5154 * f.readbyte # => 227
5155 * f.close
5156 *
5157 * Related: IO#getbyte (will not raise EOFError).
5158 *
5159 */
5160
5161static VALUE
5162rb_io_readbyte(VALUE io)
5163{
5164 VALUE c = rb_io_getbyte(io);
5165
5166 if (NIL_P(c)) {
5167 rb_eof_error();
5168 }
5169 return c;
5170}
5171
5172/*
5173 * call-seq:
5174 * ungetbyte(integer) -> nil
5175 * ungetbyte(string) -> nil
5176 *
5177 * Pushes back ("unshifts") the given data onto the stream's buffer,
5178 * placing the data so that it is next to be read; returns +nil+.
5179 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5180 *
5181 * Note that:
5182 *
5183 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5184 * - Calling #rewind on the stream discards the pushed-back data.
5185 *
5186 * When argument +integer+ is given, uses only its low-order byte:
5187 *
5188 * File.write('t.tmp', '012')
5189 * f = File.open('t.tmp')
5190 * f.ungetbyte(0x41) # => nil
5191 * f.read # => "A012"
5192 * f.rewind
5193 * f.ungetbyte(0x4243) # => nil
5194 * f.read # => "C012"
5195 * f.close
5196 *
5197 * When argument +string+ is given, uses all bytes:
5198 *
5199 * File.write('t.tmp', '012')
5200 * f = File.open('t.tmp')
5201 * f.ungetbyte('A') # => nil
5202 * f.read # => "A012"
5203 * f.rewind
5204 * f.ungetbyte('BCDE') # => nil
5205 * f.read # => "BCDE012"
5206 * f.close
5207 *
5208 */
5209
5210VALUE
5212{
5213 rb_io_t *fptr;
5214
5215 GetOpenFile(io, fptr);
5217 switch (TYPE(b)) {
5218 case T_NIL:
5219 return Qnil;
5220 case T_FIXNUM:
5221 case T_BIGNUM: ;
5222 VALUE v = rb_int_modulo(b, INT2FIX(256));
5223 unsigned char c = NUM2INT(v) & 0xFF;
5224 b = rb_str_new((const char *)&c, 1);
5225 break;
5226 default:
5227 StringValue(b);
5228 }
5229 io_ungetbyte(b, fptr);
5230 return Qnil;
5231}
5232
5233/*
5234 * call-seq:
5235 * ungetc(integer) -> nil
5236 * ungetc(string) -> nil
5237 *
5238 * Pushes back ("unshifts") the given data onto the stream's buffer,
5239 * placing the data so that it is next to be read; returns +nil+.
5240 * See {Character IO}[rdoc-ref:IO@Character+IO].
5241 *
5242 * Note that:
5243 *
5244 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5245 * - Calling #rewind on the stream discards the pushed-back data.
5246 *
5247 * When argument +integer+ is given, interprets the integer as a character:
5248 *
5249 * File.write('t.tmp', '012')
5250 * f = File.open('t.tmp')
5251 * f.ungetc(0x41) # => nil
5252 * f.read # => "A012"
5253 * f.rewind
5254 * f.ungetc(0x0442) # => nil
5255 * f.getc.ord # => 1090
5256 * f.close
5257 *
5258 * When argument +string+ is given, uses all characters:
5259 *
5260 * File.write('t.tmp', '012')
5261 * f = File.open('t.tmp')
5262 * f.ungetc('A') # => nil
5263 * f.read # => "A012"
5264 * f.rewind
5265 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5266 * f.getc.ord # => 1090
5267 * f.getc.ord # => 1077
5268 * f.getc.ord # => 1089
5269 * f.getc.ord # => 1090
5270 * f.close
5271 *
5272 */
5273
5274VALUE
5276{
5277 rb_io_t *fptr;
5278 long len;
5279
5280 GetOpenFile(io, fptr);
5282 if (FIXNUM_P(c)) {
5283 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5284 }
5285 else if (RB_BIGNUM_TYPE_P(c)) {
5286 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5287 }
5288 else {
5289 StringValue(c);
5290 }
5291 if (NEED_READCONV(fptr)) {
5292 SET_BINARY_MODE(fptr);
5293 len = RSTRING_LEN(c);
5294#if SIZEOF_LONG > SIZEOF_INT
5295 if (len > INT_MAX)
5296 rb_raise(rb_eIOError, "ungetc failed");
5297#endif
5298 make_readconv(fptr, (int)len);
5299 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5300 rb_raise(rb_eIOError, "ungetc failed");
5301 if (fptr->cbuf.off < len) {
5302 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5303 fptr->cbuf.ptr+fptr->cbuf.off,
5304 char, fptr->cbuf.len);
5305 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5306 }
5307 fptr->cbuf.off -= (int)len;
5308 fptr->cbuf.len += (int)len;
5309 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5310 }
5311 else {
5312 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5313 io_ungetbyte(c, fptr);
5314 }
5315 return Qnil;
5316}
5317
5318/*
5319 * call-seq:
5320 * isatty -> true or false
5321 *
5322 * Returns +true+ if the stream is associated with a terminal device (tty),
5323 * +false+ otherwise:
5324 *
5325 * f = File.new('t.txt').isatty #=> false
5326 * f.close
5327 * f = File.new('/dev/tty').isatty #=> true
5328 * f.close
5329 *
5330 */
5331
5332static VALUE
5333rb_io_isatty(VALUE io)
5334{
5335 rb_io_t *fptr;
5336
5337 GetOpenFile(io, fptr);
5338 return RBOOL(isatty(fptr->fd) != 0);
5339}
5340
5341#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5342/*
5343 * call-seq:
5344 * close_on_exec? -> true or false
5345 *
5346 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5347 *
5348 * f = File.open('t.txt')
5349 * f.close_on_exec? # => true
5350 * f.close_on_exec = false
5351 * f.close_on_exec? # => false
5352 * f.close
5353 *
5354 */
5355
5356static VALUE
5357rb_io_close_on_exec_p(VALUE io)
5358{
5359 rb_io_t *fptr;
5360 VALUE write_io;
5361 int fd, ret;
5362
5363 write_io = GetWriteIO(io);
5364 if (io != write_io) {
5365 GetOpenFile(write_io, fptr);
5366 if (fptr && 0 <= (fd = fptr->fd)) {
5367 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5368 if (!(ret & FD_CLOEXEC)) return Qfalse;
5369 }
5370 }
5371
5372 GetOpenFile(io, fptr);
5373 if (fptr && 0 <= (fd = fptr->fd)) {
5374 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5375 if (!(ret & FD_CLOEXEC)) return Qfalse;
5376 }
5377 return Qtrue;
5378}
5379#else
5380#define rb_io_close_on_exec_p rb_f_notimplement
5381#endif
5382
5383#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5384/*
5385 * call-seq:
5386 * self.close_on_exec = bool -> true or false
5387 *
5388 * Sets a close-on-exec flag.
5389 *
5390 * f = File.open(File::NULL)
5391 * f.close_on_exec = true
5392 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5393 * f.closed? #=> false
5394 *
5395 * Ruby sets close-on-exec flags of all file descriptors by default
5396 * since Ruby 2.0.0.
5397 * So you don't need to set by yourself.
5398 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5399 * if another thread use fork() and exec() (via system() method for example).
5400 * If you really needs file descriptor inheritance to child process,
5401 * use spawn()'s argument such as fd=>fd.
5402 */
5403
5404static VALUE
5405rb_io_set_close_on_exec(VALUE io, VALUE arg)
5406{
5407 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5408 rb_io_t *fptr;
5409 VALUE write_io;
5410 int fd, ret;
5411
5412 write_io = GetWriteIO(io);
5413 if (io != write_io) {
5414 GetOpenFile(write_io, fptr);
5415 if (fptr && 0 <= (fd = fptr->fd)) {
5416 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5417 if ((ret & FD_CLOEXEC) != flag) {
5418 ret = (ret & ~FD_CLOEXEC) | flag;
5419 ret = fcntl(fd, F_SETFD, ret);
5420 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5421 }
5422 }
5423
5424 }
5425
5426 GetOpenFile(io, fptr);
5427 if (fptr && 0 <= (fd = fptr->fd)) {
5428 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5429 if ((ret & FD_CLOEXEC) != flag) {
5430 ret = (ret & ~FD_CLOEXEC) | flag;
5431 ret = fcntl(fd, F_SETFD, ret);
5432 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5433 }
5434 }
5435 return Qnil;
5436}
5437#else
5438#define rb_io_set_close_on_exec rb_f_notimplement
5439#endif
5440
5441#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5442#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5443
5444static VALUE
5445finish_writeconv(rb_io_t *fptr, int noalloc)
5446{
5447 unsigned char *ds, *dp, *de;
5449
5450 if (!fptr->wbuf.ptr) {
5451 unsigned char buf[1024];
5452
5454 while (res == econv_destination_buffer_full) {
5455 ds = dp = buf;
5456 de = buf + sizeof(buf);
5457 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5458 while (dp-ds) {
5459 size_t remaining = dp-ds;
5460 long result = rb_io_write_memory(fptr, ds, remaining);
5461
5462 if (result > 0) {
5463 ds += result;
5464 if ((size_t)result == remaining) break;
5465 }
5466 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5467 if (fptr->fd < 0)
5468 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5469 }
5470 else {
5471 return noalloc ? Qtrue : INT2NUM(errno);
5472 }
5473 }
5474 if (res == econv_invalid_byte_sequence ||
5475 res == econv_incomplete_input ||
5477 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5478 }
5479 }
5480
5481 return Qnil;
5482 }
5483
5485 while (res == econv_destination_buffer_full) {
5486 if (fptr->wbuf.len == fptr->wbuf.capa) {
5487 if (io_fflush(fptr) < 0) {
5488 return noalloc ? Qtrue : INT2NUM(errno);
5489 }
5490 }
5491
5492 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5493 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5494 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5495 fptr->wbuf.len += (int)(dp - ds);
5496 if (res == econv_invalid_byte_sequence ||
5497 res == econv_incomplete_input ||
5499 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5500 }
5501 }
5502 return Qnil;
5503}
5504
5506 rb_io_t *fptr;
5507 int noalloc;
5508};
5509
5510static VALUE
5511finish_writeconv_sync(VALUE arg)
5512{
5513 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5514 return finish_writeconv(p->fptr, p->noalloc);
5515}
5516
5517static void*
5518nogvl_close(void *ptr)
5519{
5520 int *fd = ptr;
5521
5522 return (void*)(intptr_t)close(*fd);
5523}
5524
5525static int
5526maygvl_close(int fd, int keepgvl)
5527{
5528 if (keepgvl)
5529 return close(fd);
5530
5531 /*
5532 * close() may block for certain file types (NFS, SO_LINGER sockets,
5533 * inotify), so let other threads run.
5534 */
5535 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5536}
5537
5538static void*
5539nogvl_fclose(void *ptr)
5540{
5541 FILE *file = ptr;
5542
5543 return (void*)(intptr_t)fclose(file);
5544}
5545
5546static int
5547maygvl_fclose(FILE *file, int keepgvl)
5548{
5549 if (keepgvl)
5550 return fclose(file);
5551
5552 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5553}
5554
5555static void free_io_buffer(rb_io_buffer_t *buf);
5556
5557static void
5558fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5559{
5560 VALUE error = Qnil;
5561 int fd = fptr->fd;
5562 FILE *stdio_file = fptr->stdio_file;
5563 int mode = fptr->mode;
5564
5565 if (fptr->writeconv) {
5566 if (!NIL_P(fptr->write_lock) && !noraise) {
5567 struct finish_writeconv_arg arg;
5568 arg.fptr = fptr;
5569 arg.noalloc = noraise;
5570 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5571 }
5572 else {
5573 error = finish_writeconv(fptr, noraise);
5574 }
5575 }
5576 if (fptr->wbuf.len) {
5577 if (noraise) {
5578 io_flush_buffer_sync(fptr);
5579 }
5580 else {
5581 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5582 error = INT2NUM(errno);
5583 }
5584 }
5585 }
5586
5587 int done = 0;
5588
5589 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5590 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5591 done = 1;
5592 }
5593
5594 fptr->fd = -1;
5595 fptr->stdio_file = 0;
5597
5598 // Wait for blocking operations to ensure they do not hit EBADF:
5599 rb_thread_io_close_wait(fptr);
5600
5601 if (!done && stdio_file) {
5602 // stdio_file is deallocated anyway even if fclose failed.
5603 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5604 if (!noraise) {
5605 error = INT2NUM(errno);
5606 }
5607 }
5608
5609 done = 1;
5610 }
5611
5612 VALUE scheduler = rb_fiber_scheduler_current();
5613 if (!done && fd >= 0 && scheduler != Qnil) {
5614 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5615
5616 if (!UNDEF_P(result)) {
5617 done = RTEST(result);
5618 }
5619 }
5620
5621 if (!done && fd >= 0) {
5622 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5623 // We assumes it is closed.
5624
5625 keepgvl |= !(mode & FMODE_WRITABLE);
5626 keepgvl |= noraise;
5627 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5628 if (!noraise) {
5629 error = INT2NUM(errno);
5630 }
5631 }
5632
5633 done = 1;
5634 }
5635
5636 if (!NIL_P(error) && !noraise) {
5637 if (RB_INTEGER_TYPE_P(error))
5638 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5639 else
5640 rb_exc_raise(error);
5641 }
5642}
5643
5644static void
5645fptr_finalize(rb_io_t *fptr, int noraise)
5646{
5647 fptr_finalize_flush(fptr, noraise, FALSE);
5648 free_io_buffer(&fptr->rbuf);
5649 free_io_buffer(&fptr->wbuf);
5650 clear_codeconv(fptr);
5651}
5652
5653static void
5654rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5655{
5656 if (fptr->finalize) {
5657 (*fptr->finalize)(fptr, noraise);
5658 }
5659 else {
5660 fptr_finalize(fptr, noraise);
5661 }
5662}
5663
5664static void
5665free_io_buffer(rb_io_buffer_t *buf)
5666{
5667 if (buf->ptr) {
5668 ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
5669 buf->ptr = NULL;
5670 }
5671 buf->off = buf->len = buf->capa = 0;
5672}
5673
5674static void
5675clear_readconv(rb_io_t *fptr)
5676{
5677 if (fptr->readconv) {
5678 rb_econv_close(fptr->readconv);
5679 fptr->readconv = NULL;
5680 }
5681 free_io_buffer(&fptr->cbuf);
5682}
5683
5684static void
5685clear_writeconv(rb_io_t *fptr)
5686{
5687 if (fptr->writeconv) {
5689 fptr->writeconv = NULL;
5690 }
5691 fptr->writeconv_initialized = 0;
5692}
5693
5694static void
5695clear_codeconv(rb_io_t *fptr)
5696{
5697 clear_readconv(fptr);
5698 clear_writeconv(fptr);
5699}
5700
5701static void
5702rb_io_fptr_cleanup_all(rb_io_t *fptr)
5703{
5704 fptr->pathv = Qnil;
5705 if (0 <= fptr->fd)
5706 rb_io_fptr_cleanup(fptr, TRUE);
5707 fptr->write_lock = Qnil;
5708 free_io_buffer(&fptr->rbuf);
5709 free_io_buffer(&fptr->wbuf);
5710 clear_codeconv(fptr);
5711}
5712
5713int
5715{
5716 if (!io) return 0;
5717 rb_io_fptr_cleanup_all(io);
5718 free(io);
5719
5720 return 1;
5721}
5722
5723bool
5724rb_io_fptr_finalize_closed(struct rb_io *io)
5725{
5726 if (!io) return true;
5727 if (io->fd >= 0) return false;
5729 return true;
5730}
5731
5732size_t
5733rb_io_memsize(const rb_io_t *io)
5734{
5735 size_t size = sizeof(rb_io_t);
5736 size += io->rbuf.capa;
5737 size += io->wbuf.capa;
5738 size += io->cbuf.capa;
5739 if (io->readconv) size += rb_econv_memsize(io->readconv);
5740 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5741
5742 struct rb_io_blocking_operation *blocking_operation = 0;
5743
5744 // 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.
5745 rb_serial_t fork_generation = GET_VM()->fork_gen;
5746 if (io->fork_generation == fork_generation) {
5747 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5748 size += sizeof(struct rb_io_blocking_operation);
5749 }
5750 }
5751
5752 return size;
5753}
5754
5755#ifdef _WIN32
5756/* keep GVL while closing to prevent crash on Windows */
5757# define KEEPGVL TRUE
5758#else
5759# define KEEPGVL FALSE
5760#endif
5761
5762static rb_io_t *
5763io_close_fptr(VALUE io)
5764{
5765 rb_io_t *fptr;
5766 VALUE write_io;
5767 rb_io_t *write_fptr;
5768
5769 write_io = GetWriteIO(io);
5770 if (io != write_io) {
5771 write_fptr = RFILE(write_io)->fptr;
5772 if (write_fptr && 0 <= write_fptr->fd) {
5773 rb_io_fptr_cleanup(write_fptr, TRUE);
5774 }
5775 }
5776
5777 fptr = RFILE(io)->fptr;
5778 if (!fptr) return 0;
5779 if (fptr->fd < 0) return 0;
5780
5781 // This guards against multiple threads closing the same IO object:
5782 if (rb_thread_io_close_interrupt(fptr)) {
5783 /* calls close(fptr->fd): */
5784 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5785 }
5786
5787 rb_io_fptr_cleanup(fptr, FALSE);
5788 return fptr;
5789}
5790
5791static void
5792fptr_waitpid(rb_io_t *fptr, int nohang)
5793{
5794 int status;
5795 if (fptr->pid) {
5796 rb_last_status_clear();
5797 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5798 fptr->pid = 0;
5799 }
5800}
5801
5802VALUE
5804{
5805 rb_io_t *fptr = io_close_fptr(io);
5806 if (fptr) fptr_waitpid(fptr, 0);
5807 return Qnil;
5808}
5809
5810/*
5811 * call-seq:
5812 * close -> nil
5813 *
5814 * Closes the stream for both reading and writing
5815 * if open for either or both; returns +nil+.
5816 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5817 *
5818 * If the stream is open for writing, flushes any buffered writes
5819 * to the operating system before closing.
5820 *
5821 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5822 * (child exit status).
5823 *
5824 * It is not an error to close an IO object that has already been closed.
5825 * It just returns nil.
5826 *
5827 * Example:
5828 *
5829 * IO.popen('ruby', 'r+') do |pipe|
5830 * puts pipe.closed?
5831 * pipe.close
5832 * puts $?
5833 * puts pipe.closed?
5834 * end
5835 *
5836 * Output:
5837 *
5838 * false
5839 * pid 13760 exit 0
5840 * true
5841 *
5842 * Related: IO#close_read, IO#close_write, IO#closed?.
5843 */
5844
5845static VALUE
5846rb_io_close_m(VALUE io)
5847{
5848 rb_io_t *fptr = rb_io_get_fptr(io);
5849 if (fptr->fd < 0) {
5850 return Qnil;
5851 }
5852 rb_io_close(io);
5853 return Qnil;
5854}
5855
5856static VALUE
5857io_call_close(VALUE io)
5858{
5859 rb_check_funcall(io, rb_intern("close"), 0, 0);
5860 return io;
5861}
5862
5863static VALUE
5864ignore_closed_stream(VALUE io, VALUE exc)
5865{
5866 enum {mesg_len = sizeof(closed_stream)-1};
5867 VALUE mesg = rb_attr_get(exc, idMesg);
5868 if (!RB_TYPE_P(mesg, T_STRING) ||
5869 RSTRING_LEN(mesg) != mesg_len ||
5870 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5871 rb_exc_raise(exc);
5872 }
5873 return io;
5874}
5875
5876static VALUE
5877io_close(VALUE io)
5878{
5879 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5880 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5881 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5882 rb_eIOError, (VALUE)0);
5883 return io;
5884}
5885
5886/*
5887 * call-seq:
5888 * closed? -> true or false
5889 *
5890 * Returns +true+ if the stream is closed for both reading and writing,
5891 * +false+ otherwise.
5892 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5893 *
5894 * IO.popen('ruby', 'r+') do |pipe|
5895 * puts pipe.closed?
5896 * pipe.close_read
5897 * puts pipe.closed?
5898 * pipe.close_write
5899 * puts pipe.closed?
5900 * end
5901 *
5902 * Output:
5903 *
5904 * false
5905 * false
5906 * true
5907 *
5908 * Related: IO#close_read, IO#close_write, IO#close.
5909 */
5910VALUE
5912{
5913 rb_io_t *fptr;
5914 VALUE write_io;
5915 rb_io_t *write_fptr;
5916
5917 write_io = GetWriteIO(io);
5918 if (io != write_io) {
5919 write_fptr = RFILE(write_io)->fptr;
5920 if (write_fptr && 0 <= write_fptr->fd) {
5921 return Qfalse;
5922 }
5923 }
5924
5925 fptr = rb_io_get_fptr(io);
5926 return RBOOL(0 > fptr->fd);
5927}
5928
5929/*
5930 * call-seq:
5931 * close_read -> nil
5932 *
5933 * Closes the stream for reading if open for reading;
5934 * returns +nil+.
5935 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5936 *
5937 * If the stream was opened by IO.popen and is also closed for writing,
5938 * sets global variable <tt>$?</tt> (child exit status).
5939 *
5940 * Example:
5941 *
5942 * IO.popen('ruby', 'r+') do |pipe|
5943 * puts pipe.closed?
5944 * pipe.close_write
5945 * puts pipe.closed?
5946 * pipe.close_read
5947 * puts $?
5948 * puts pipe.closed?
5949 * end
5950 *
5951 * Output:
5952 *
5953 * false
5954 * false
5955 * pid 14748 exit 0
5956 * true
5957 *
5958 * Related: IO#close, IO#close_write, IO#closed?.
5959 */
5960
5961static VALUE
5962rb_io_close_read(VALUE io)
5963{
5964 rb_io_t *fptr;
5965 VALUE write_io;
5966
5967 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5968 if (fptr->fd < 0) return Qnil;
5969 if (is_socket(fptr->fd, fptr->pathv)) {
5970#ifndef SHUT_RD
5971# define SHUT_RD 0
5972#endif
5973 if (shutdown(fptr->fd, SHUT_RD) < 0)
5974 rb_sys_fail_path(fptr->pathv);
5975 fptr->mode &= ~FMODE_READABLE;
5976 if (!(fptr->mode & FMODE_WRITABLE))
5977 return rb_io_close(io);
5978 return Qnil;
5979 }
5980
5981 write_io = GetWriteIO(io);
5982 if (io != write_io) {
5983 rb_io_t *wfptr;
5984 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5985 wfptr->pid = fptr->pid;
5986 fptr->pid = 0;
5987 RFILE(io)->fptr = wfptr;
5988 /* bind to write_io temporarily to get rid of memory/fd leak */
5989 fptr->tied_io_for_writing = 0;
5990 RFILE(write_io)->fptr = fptr;
5991 rb_io_fptr_cleanup(fptr, FALSE);
5992 /* should not finalize fptr because another thread may be reading it */
5993 return Qnil;
5994 }
5995
5996 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5997 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5998 }
5999 return rb_io_close(io);
6000}
6001
6002/*
6003 * call-seq:
6004 * close_write -> nil
6005 *
6006 * Closes the stream for writing if open for writing;
6007 * returns +nil+.
6008 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6009 *
6010 * Flushes any buffered writes to the operating system before closing.
6011 *
6012 * If the stream was opened by IO.popen and is also closed for reading,
6013 * sets global variable <tt>$?</tt> (child exit status).
6014 *
6015 * IO.popen('ruby', 'r+') do |pipe|
6016 * puts pipe.closed?
6017 * pipe.close_read
6018 * puts pipe.closed?
6019 * pipe.close_write
6020 * puts $?
6021 * puts pipe.closed?
6022 * end
6023 *
6024 * Output:
6025 *
6026 * false
6027 * false
6028 * pid 15044 exit 0
6029 * true
6030 *
6031 * Related: IO#close, IO#close_read, IO#closed?.
6032 */
6033
6034static VALUE
6035rb_io_close_write(VALUE io)
6036{
6037 rb_io_t *fptr;
6038 VALUE write_io;
6039
6040 write_io = GetWriteIO(io);
6041 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6042 if (fptr->fd < 0) return Qnil;
6043 if (is_socket(fptr->fd, fptr->pathv)) {
6044#ifndef SHUT_WR
6045# define SHUT_WR 1
6046#endif
6047 if (shutdown(fptr->fd, SHUT_WR) < 0)
6048 rb_sys_fail_path(fptr->pathv);
6049 fptr->mode &= ~FMODE_WRITABLE;
6050 if (!(fptr->mode & FMODE_READABLE))
6051 return rb_io_close(write_io);
6052 return Qnil;
6053 }
6054
6055 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6056 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6057 }
6058
6059 if (io != write_io) {
6060 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6061 fptr->tied_io_for_writing = 0;
6062 }
6063 rb_io_close(write_io);
6064 return Qnil;
6065}
6066
6067/*
6068 * call-seq:
6069 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6070 *
6071 * Behaves like IO#seek, except that it:
6072 *
6073 * - Uses low-level system functions.
6074 * - Returns the new position.
6075 *
6076 */
6077
6078static VALUE
6079rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6080{
6081 VALUE offset, ptrname;
6082 int whence = SEEK_SET;
6083 rb_io_t *fptr;
6084 rb_off_t pos;
6085
6086 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6087 whence = interpret_seek_whence(ptrname);
6088 }
6089 pos = NUM2OFFT(offset);
6090 GetOpenFile(io, fptr);
6091 if ((fptr->mode & FMODE_READABLE) &&
6092 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6093 rb_raise(rb_eIOError, "sysseek for buffered IO");
6094 }
6095 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6096 rb_warn("sysseek for buffered IO");
6097 }
6098 errno = 0;
6099 pos = lseek(fptr->fd, pos, whence);
6100 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6101
6102 return OFFT2NUM(pos);
6103}
6104
6105/*
6106 * call-seq:
6107 * syswrite(object) -> integer
6108 *
6109 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6110 * returns the number bytes written.
6111 * If +object+ is not a string is converted via method to_s:
6112 *
6113 * f = File.new('t.tmp', 'w')
6114 * f.syswrite('foo') # => 3
6115 * f.syswrite(30) # => 2
6116 * f.syswrite(:foo) # => 3
6117 * f.close
6118 *
6119 * This methods should not be used with other stream-writer methods.
6120 *
6121 */
6122
6123static VALUE
6124rb_io_syswrite(VALUE io, VALUE str)
6125{
6126 VALUE tmp;
6127 rb_io_t *fptr;
6128 long n, len;
6129 const char *ptr;
6130
6131 if (!RB_TYPE_P(str, T_STRING))
6132 str = rb_obj_as_string(str);
6133
6134 io = GetWriteIO(io);
6135 GetOpenFile(io, fptr);
6137
6138 if (fptr->wbuf.len) {
6139 rb_warn("syswrite for buffered IO");
6140 }
6141
6142 tmp = rb_str_tmp_frozen_acquire(str);
6143 RSTRING_GETMEM(tmp, ptr, len);
6144 n = rb_io_write_memory(fptr, ptr, len);
6145 if (n < 0) rb_sys_fail_path(fptr->pathv);
6146 rb_str_tmp_frozen_release(str, tmp);
6147
6148 return LONG2FIX(n);
6149}
6150
6151/*
6152 * call-seq:
6153 * sysread(maxlen) -> string
6154 * sysread(maxlen, out_string) -> string
6155 *
6156 * Behaves like IO#readpartial, except that it uses low-level system functions.
6157 *
6158 * This method should not be used with other stream-reader methods.
6159 *
6160 */
6161
6162static VALUE
6163rb_io_sysread(int argc, VALUE *argv, VALUE io)
6164{
6165 VALUE len, str;
6166 rb_io_t *fptr;
6167 long n, ilen;
6168 struct io_internal_read_struct iis;
6169 int shrinkable;
6170
6171 rb_scan_args(argc, argv, "11", &len, &str);
6172 ilen = NUM2LONG(len);
6173
6174 shrinkable = io_setstrbuf(&str, ilen);
6175 if (ilen == 0) return str;
6176
6177 GetOpenFile(io, fptr);
6179
6180 if (READ_DATA_BUFFERED(fptr)) {
6181 rb_raise(rb_eIOError, "sysread for buffered IO");
6182 }
6183
6184 rb_io_check_closed(fptr);
6185
6186 io_setstrbuf(&str, ilen);
6187 iis.th = rb_thread_current();
6188 iis.fptr = fptr;
6189 iis.nonblock = 0;
6190 iis.fd = fptr->fd;
6191 iis.buf = RSTRING_PTR(str);
6192 iis.capa = ilen;
6193 iis.timeout = NULL;
6194 n = io_read_memory_locktmp(str, &iis);
6195
6196 if (n < 0) {
6197 rb_sys_fail_path(fptr->pathv);
6198 }
6199
6200 io_set_read_length(str, n, shrinkable);
6201
6202 if (n == 0 && ilen > 0) {
6203 rb_eof_error();
6204 }
6205
6206 return str;
6207}
6208
6210 struct rb_io *io;
6211 int fd;
6212 void *buf;
6213 size_t count;
6214 rb_off_t offset;
6215};
6216
6217static VALUE
6218internal_pread_func(void *_arg)
6219{
6220 struct prdwr_internal_arg *arg = _arg;
6221
6222 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6223}
6224
6225static VALUE
6226pread_internal_call(VALUE _arg)
6227{
6228 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6229
6230 VALUE scheduler = rb_fiber_scheduler_current();
6231 if (scheduler != Qnil) {
6232 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6233
6234 if (!UNDEF_P(result)) {
6236 }
6237 }
6238
6239 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6240}
6241
6242/*
6243 * call-seq:
6244 * pread(maxlen, offset) -> string
6245 * pread(maxlen, offset, out_string) -> string
6246 *
6247 * Behaves like IO#readpartial, except that it:
6248 *
6249 * - Reads at the given +offset+ (in bytes).
6250 * - Disregards, and does not modify, the stream's position
6251 * (see {Position}[rdoc-ref:IO@Position]).
6252 * - Bypasses any user space buffering in the stream.
6253 *
6254 * Because this method does not disturb the stream's state
6255 * (its position, in particular), +pread+ allows multiple threads and processes
6256 * to use the same \IO object for reading at various offsets.
6257 *
6258 * f = File.open('t.txt')
6259 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6260 * f.pos # => 52
6261 * # Read 12 bytes at offset 0.
6262 * f.pread(12, 0) # => "First line\n"
6263 * # Read 9 bytes at offset 8.
6264 * f.pread(9, 8) # => "ne\nSecon"
6265 * f.close
6266 *
6267 * Not available on some platforms.
6268 *
6269 */
6270static VALUE
6271rb_io_pread(int argc, VALUE *argv, VALUE io)
6272{
6273 VALUE len, offset, str;
6274 rb_io_t *fptr;
6275 ssize_t n;
6276 struct prdwr_internal_arg arg;
6277 int shrinkable;
6278
6279 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6280 arg.count = NUM2SIZET(len);
6281 arg.offset = NUM2OFFT(offset);
6282
6283 shrinkable = io_setstrbuf(&str, (long)arg.count);
6284 if (arg.count == 0) return str;
6285 arg.buf = RSTRING_PTR(str);
6286
6287 GetOpenFile(io, fptr);
6289
6290 arg.io = fptr;
6291 arg.fd = fptr->fd;
6292 rb_io_check_closed(fptr);
6293
6294 rb_str_locktmp(str);
6295 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6296
6297 if (n < 0) {
6298 rb_sys_fail_path(fptr->pathv);
6299 }
6300 io_set_read_length(str, n, shrinkable);
6301 if (n == 0 && arg.count > 0) {
6302 rb_eof_error();
6303 }
6304
6305 return str;
6306}
6307
6308static VALUE
6309internal_pwrite_func(void *_arg)
6310{
6311 struct prdwr_internal_arg *arg = _arg;
6312
6313 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6314}
6315
6316static VALUE
6317pwrite_internal_call(VALUE _arg)
6318{
6319 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6320
6321 VALUE scheduler = rb_fiber_scheduler_current();
6322 if (scheduler != Qnil) {
6323 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6324
6325 if (!UNDEF_P(result)) {
6327 }
6328 }
6329
6330 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6331}
6332
6333/*
6334 * call-seq:
6335 * pwrite(object, offset) -> integer
6336 *
6337 * Behaves like IO#write, except that it:
6338 *
6339 * - Writes at the given +offset+ (in bytes).
6340 * - Disregards, and does not modify, the stream's position
6341 * (see {Position}[rdoc-ref:IO@Position]).
6342 * - Bypasses any user space buffering in the stream.
6343 *
6344 * Because this method does not disturb the stream's state
6345 * (its position, in particular), +pwrite+ allows multiple threads and processes
6346 * to use the same \IO object for writing at various offsets.
6347 *
6348 * f = File.open('t.tmp', 'w+')
6349 * # Write 6 bytes at offset 3.
6350 * f.pwrite('ABCDEF', 3) # => 6
6351 * f.rewind
6352 * f.read # => "\u0000\u0000\u0000ABCDEF"
6353 * f.close
6354 *
6355 * Not available on some platforms.
6356 *
6357 */
6358static VALUE
6359rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6360{
6361 rb_io_t *fptr;
6362 ssize_t n;
6363 struct prdwr_internal_arg arg;
6364 VALUE tmp;
6365
6366 if (!RB_TYPE_P(str, T_STRING))
6367 str = rb_obj_as_string(str);
6368
6369 arg.offset = NUM2OFFT(offset);
6370
6371 io = GetWriteIO(io);
6372 GetOpenFile(io, fptr);
6374
6375 arg.io = fptr;
6376 arg.fd = fptr->fd;
6377
6378 tmp = rb_str_tmp_frozen_acquire(str);
6379 arg.buf = RSTRING_PTR(tmp);
6380 arg.count = (size_t)RSTRING_LEN(tmp);
6381
6382 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6383 if (n < 0) rb_sys_fail_path(fptr->pathv);
6384 rb_str_tmp_frozen_release(str, tmp);
6385
6386 return SSIZET2NUM(n);
6387}
6388
6389VALUE
6391{
6392 rb_io_t *fptr;
6393
6394 GetOpenFile(io, fptr);
6395 if (fptr->readconv)
6397 if (fptr->writeconv)
6399 fptr->mode |= FMODE_BINMODE;
6400 fptr->mode &= ~FMODE_TEXTMODE;
6401 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6402#ifdef O_BINARY
6403 if (!fptr->readconv) {
6404 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6405 }
6406 else {
6407 setmode(fptr->fd, O_BINARY);
6408 }
6409#endif
6410 return io;
6411}
6412
6413static void
6414io_ascii8bit_binmode(rb_io_t *fptr)
6415{
6416 if (fptr->readconv) {
6417 rb_econv_close(fptr->readconv);
6418 fptr->readconv = NULL;
6419 }
6420 if (fptr->writeconv) {
6422 fptr->writeconv = NULL;
6423 }
6424 fptr->mode |= FMODE_BINMODE;
6425 fptr->mode &= ~FMODE_TEXTMODE;
6426 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6427
6428 fptr->encs.enc = rb_ascii8bit_encoding();
6429 fptr->encs.enc2 = NULL;
6430 fptr->encs.ecflags = 0;
6431 fptr->encs.ecopts = Qnil;
6432 clear_codeconv(fptr);
6433}
6434
6435VALUE
6437{
6438 rb_io_t *fptr;
6439
6440 GetOpenFile(io, fptr);
6441 io_ascii8bit_binmode(fptr);
6442
6443 return io;
6444}
6445
6446/*
6447 * call-seq:
6448 * binmode -> self
6449 *
6450 * Sets the stream's data mode as binary
6451 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6452 *
6453 * A stream's data mode may not be changed from binary to text.
6454 *
6455 */
6456
6457static VALUE
6458rb_io_binmode_m(VALUE io)
6459{
6460 VALUE write_io;
6461
6463
6464 write_io = GetWriteIO(io);
6465 if (write_io != io)
6466 rb_io_ascii8bit_binmode(write_io);
6467 return io;
6468}
6469
6470/*
6471 * call-seq:
6472 * binmode? -> true or false
6473 *
6474 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6475 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6476 *
6477 */
6478static VALUE
6479rb_io_binmode_p(VALUE io)
6480{
6481 rb_io_t *fptr;
6482 GetOpenFile(io, fptr);
6483 return RBOOL(fptr->mode & FMODE_BINMODE);
6484}
6485
6486static const char*
6487rb_io_fmode_modestr(enum rb_io_mode fmode)
6488{
6489 if (fmode & FMODE_APPEND) {
6490 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6491 return MODE_BTMODE("a+", "ab+", "at+");
6492 }
6493 return MODE_BTMODE("a", "ab", "at");
6494 }
6495 switch (fmode & FMODE_READWRITE) {
6496 default:
6497 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6498 case FMODE_READABLE:
6499 return MODE_BTMODE("r", "rb", "rt");
6500 case FMODE_WRITABLE:
6501 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6502 case FMODE_READWRITE:
6503 if (fmode & FMODE_CREATE) {
6504 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6505 }
6506 return MODE_BTMODE("r+", "rb+", "rt+");
6507 }
6508}
6509
6510static const char bom_prefix[] = "bom|";
6511static const char utf_prefix[] = "utf-";
6512enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6513enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6514
6515static int
6516io_encname_bom_p(const char *name, long len)
6517{
6518 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6519}
6520
6521enum rb_io_mode
6522rb_io_modestr_fmode(const char *modestr)
6523{
6524 enum rb_io_mode fmode = 0;
6525 const char *m = modestr, *p = NULL;
6526
6527 switch (*m++) {
6528 case 'r':
6529 fmode |= FMODE_READABLE;
6530 break;
6531 case 'w':
6533 break;
6534 case 'a':
6536 break;
6537 default:
6538 goto error;
6539 }
6540
6541 while (*m) {
6542 switch (*m++) {
6543 case 'b':
6544 fmode |= FMODE_BINMODE;
6545 break;
6546 case 't':
6547 fmode |= FMODE_TEXTMODE;
6548 break;
6549 case '+':
6550 fmode |= FMODE_READWRITE;
6551 break;
6552 case 'x':
6553 if (modestr[0] != 'w')
6554 goto error;
6555 fmode |= FMODE_EXCL;
6556 break;
6557 default:
6558 goto error;
6559 case ':':
6560 p = strchr(m, ':');
6561 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6562 fmode |= FMODE_SETENC_BY_BOM;
6563 goto finished;
6564 }
6565 }
6566
6567 finished:
6568 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6569 goto error;
6570
6571 return fmode;
6572
6573 error:
6574 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6576}
6577
6578int
6579rb_io_oflags_fmode(int oflags)
6580{
6581 enum rb_io_mode fmode = 0;
6582
6583 switch (oflags & O_ACCMODE) {
6584 case O_RDONLY:
6585 fmode = FMODE_READABLE;
6586 break;
6587 case O_WRONLY:
6588 fmode = FMODE_WRITABLE;
6589 break;
6590 case O_RDWR:
6591 fmode = FMODE_READWRITE;
6592 break;
6593 }
6594
6595 if (oflags & O_APPEND) {
6596 fmode |= FMODE_APPEND;
6597 }
6598 if (oflags & O_TRUNC) {
6599 fmode |= FMODE_TRUNC;
6600 }
6601 if (oflags & O_CREAT) {
6602 fmode |= FMODE_CREATE;
6603 }
6604 if (oflags & O_EXCL) {
6605 fmode |= FMODE_EXCL;
6606 }
6607#ifdef O_BINARY
6608 if (oflags & O_BINARY) {
6609 fmode |= FMODE_BINMODE;
6610 }
6611#endif
6612
6613 return fmode;
6614}
6615
6616static int
6617rb_io_fmode_oflags(enum rb_io_mode fmode)
6618{
6619 int oflags = 0;
6620
6621 switch (fmode & FMODE_READWRITE) {
6622 case FMODE_READABLE:
6623 oflags |= O_RDONLY;
6624 break;
6625 case FMODE_WRITABLE:
6626 oflags |= O_WRONLY;
6627 break;
6628 case FMODE_READWRITE:
6629 oflags |= O_RDWR;
6630 break;
6631 }
6632
6633 if (fmode & FMODE_APPEND) {
6634 oflags |= O_APPEND;
6635 }
6636 if (fmode & FMODE_TRUNC) {
6637 oflags |= O_TRUNC;
6638 }
6639 if (fmode & FMODE_CREATE) {
6640 oflags |= O_CREAT;
6641 }
6642 if (fmode & FMODE_EXCL) {
6643 oflags |= O_EXCL;
6644 }
6645#ifdef O_BINARY
6646 if (fmode & FMODE_BINMODE) {
6647 oflags |= O_BINARY;
6648 }
6649#endif
6650
6651 return oflags;
6652}
6653
6654int
6655rb_io_modestr_oflags(const char *modestr)
6656{
6657 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6658}
6659
6660static const char*
6661rb_io_oflags_modestr(int oflags)
6662{
6663#ifdef O_BINARY
6664# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6665#else
6666# define MODE_BINARY(a,b) (a)
6667#endif
6668 int accmode;
6669 if (oflags & O_EXCL) {
6670 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6671 }
6672 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6673 if (oflags & O_APPEND) {
6674 if (accmode == O_WRONLY) {
6675 return MODE_BINARY("a", "ab");
6676 }
6677 if (accmode == O_RDWR) {
6678 return MODE_BINARY("a+", "ab+");
6679 }
6680 }
6681 switch (accmode) {
6682 default:
6683 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6684 case O_RDONLY:
6685 return MODE_BINARY("r", "rb");
6686 case O_WRONLY:
6687 return MODE_BINARY("w", "wb");
6688 case O_RDWR:
6689 if (oflags & O_TRUNC) {
6690 return MODE_BINARY("w+", "wb+");
6691 }
6692 return MODE_BINARY("r+", "rb+");
6693 }
6694}
6695
6696/*
6697 * Convert external/internal encodings to enc/enc2
6698 * NULL => use default encoding
6699 * Qnil => no encoding specified (internal only)
6700 */
6701static void
6702rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6703{
6704 int default_ext = 0;
6705
6706 if (ext == NULL) {
6707 ext = rb_default_external_encoding();
6708 default_ext = 1;
6709 }
6710 if (rb_is_ascii8bit_enc(ext)) {
6711 /* If external is ASCII-8BIT, no transcoding */
6712 intern = NULL;
6713 }
6714 else if (intern == NULL) {
6715 intern = rb_default_internal_encoding();
6716 }
6717 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6718 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6719 /* No internal encoding => use external + no transcoding */
6720 *enc = (default_ext && intern != ext) ? NULL : ext;
6721 *enc2 = NULL;
6722 }
6723 else {
6724 *enc = intern;
6725 *enc2 = ext;
6726 }
6727}
6728
6729static void
6730unsupported_encoding(const char *name, rb_encoding *enc)
6731{
6732 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6733}
6734
6735static void
6736parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6737 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6738{
6739 const char *p;
6740 char encname[ENCODING_MAXNAMELEN+1];
6741 int idx, idx2;
6742 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6743 rb_encoding *ext_enc, *int_enc;
6744 long len;
6745
6746 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6747
6748 p = strrchr(estr, ':');
6749 len = p ? (p++ - estr) : (long)strlen(estr);
6750 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6751 estr += bom_prefix_len;
6752 len -= bom_prefix_len;
6753 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6754 fmode |= FMODE_SETENC_BY_BOM;
6755 }
6756 else {
6757 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6758 fmode &= ~FMODE_SETENC_BY_BOM;
6759 }
6760 }
6761 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6762 idx = -1;
6763 }
6764 else {
6765 if (p) {
6766 memcpy(encname, estr, len);
6767 encname[len] = '\0';
6768 estr = encname;
6769 }
6770 idx = rb_enc_find_index(estr);
6771 }
6772 if (fmode_p) *fmode_p = fmode;
6773
6774 if (idx >= 0)
6775 ext_enc = rb_enc_from_index(idx);
6776 else {
6777 if (idx != -2)
6778 unsupported_encoding(estr, estr_enc);
6779 ext_enc = NULL;
6780 }
6781
6782 int_enc = NULL;
6783 if (p) {
6784 if (*p == '-' && *(p+1) == '\0') {
6785 /* Special case - "-" => no transcoding */
6786 int_enc = (rb_encoding *)Qnil;
6787 }
6788 else {
6789 idx2 = rb_enc_find_index(p);
6790 if (idx2 < 0)
6791 unsupported_encoding(p, estr_enc);
6792 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6793 int_enc = (rb_encoding *)Qnil;
6794 }
6795 else
6796 int_enc = rb_enc_from_index(idx2);
6797 }
6798 }
6799
6800 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6801}
6802
6803int
6804rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6805{
6806 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6807 int extracted = 0;
6808 rb_encoding *extencoding = NULL;
6809 rb_encoding *intencoding = NULL;
6810
6811 if (!NIL_P(opt)) {
6812 VALUE v;
6813 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6814 if (v != Qnil) encoding = v;
6815 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6816 if (v != Qnil) extenc = v;
6817 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6818 if (!UNDEF_P(v)) intenc = v;
6819 }
6820 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6821 if (!NIL_P(ruby_verbose)) {
6822 int idx = rb_to_encoding_index(encoding);
6823 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6824 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6825 encoding, UNDEF_P(extenc) ? "internal" : "external");
6826 }
6827 encoding = Qnil;
6828 }
6829 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6830 extencoding = rb_to_encoding(extenc);
6831 }
6832 if (!UNDEF_P(intenc)) {
6833 if (NIL_P(intenc)) {
6834 /* internal_encoding: nil => no transcoding */
6835 intencoding = (rb_encoding *)Qnil;
6836 }
6837 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6838 char *p = StringValueCStr(tmp);
6839
6840 if (*p == '-' && *(p+1) == '\0') {
6841 /* Special case - "-" => no transcoding */
6842 intencoding = (rb_encoding *)Qnil;
6843 }
6844 else {
6845 intencoding = rb_to_encoding(intenc);
6846 }
6847 }
6848 else {
6849 intencoding = rb_to_encoding(intenc);
6850 }
6851 if (extencoding == intencoding) {
6852 intencoding = (rb_encoding *)Qnil;
6853 }
6854 }
6855 if (!NIL_P(encoding)) {
6856 extracted = 1;
6857 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6858 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6859 enc_p, enc2_p, fmode_p);
6860 }
6861 else {
6862 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6863 }
6864 }
6865 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6866 extracted = 1;
6867 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6868 }
6869 return extracted;
6870}
6871
6872static void
6873validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6874{
6875 enum rb_io_mode fmode = *fmode_p;
6876
6877 if ((fmode & FMODE_READABLE) &&
6878 !enc2 &&
6879 !(fmode & FMODE_BINMODE) &&
6880 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6881 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6882
6883 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6884 rb_raise(rb_eArgError, "newline decorator with binary mode");
6885 }
6886 if (!(fmode & FMODE_BINMODE) &&
6887 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6888 fmode |= FMODE_TEXTMODE;
6889 *fmode_p = fmode;
6890 }
6891#if !DEFAULT_TEXTMODE
6892 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6893 fmode &= ~FMODE_TEXTMODE;
6894 *fmode_p = fmode;
6895 }
6896#endif
6897}
6898
6899static void
6900extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6901{
6902 if (!NIL_P(opthash)) {
6903 VALUE v;
6904 v = rb_hash_aref(opthash, sym_textmode);
6905 if (!NIL_P(v)) {
6906 if (*fmode & FMODE_TEXTMODE)
6907 rb_raise(rb_eArgError, "textmode specified twice");
6908 if (*fmode & FMODE_BINMODE)
6909 rb_raise(rb_eArgError, "both textmode and binmode specified");
6910 if (RTEST(v))
6911 *fmode |= FMODE_TEXTMODE;
6912 }
6913 v = rb_hash_aref(opthash, sym_binmode);
6914 if (!NIL_P(v)) {
6915 if (*fmode & FMODE_BINMODE)
6916 rb_raise(rb_eArgError, "binmode specified twice");
6917 if (*fmode & FMODE_TEXTMODE)
6918 rb_raise(rb_eArgError, "both textmode and binmode specified");
6919 if (RTEST(v))
6920 *fmode |= FMODE_BINMODE;
6921 }
6922
6923 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6924 rb_raise(rb_eArgError, "both textmode and binmode specified");
6925 }
6926}
6927
6928void
6929rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6930 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6931{
6932 VALUE vmode;
6933 int oflags;
6934 enum rb_io_mode fmode;
6935 rb_encoding *enc, *enc2;
6936 int ecflags;
6937 VALUE ecopts;
6938 int has_enc = 0, has_vmode = 0;
6939 VALUE intmode;
6940
6941 vmode = *vmode_p;
6942
6943 /* Set to defaults */
6944 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6945
6946 vmode_handle:
6947 if (NIL_P(vmode)) {
6948 fmode = FMODE_READABLE;
6949 oflags = O_RDONLY;
6950 }
6951 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6952 vmode = intmode;
6953 oflags = NUM2INT(intmode);
6954 fmode = rb_io_oflags_fmode(oflags);
6955 }
6956 else {
6957 const char *p;
6958
6959 StringValue(vmode);
6960 p = StringValueCStr(vmode);
6961 fmode = rb_io_modestr_fmode(p);
6962 oflags = rb_io_fmode_oflags(fmode);
6963 p = strchr(p, ':');
6964 if (p) {
6965 has_enc = 1;
6966 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6967 }
6968 else {
6969 rb_encoding *e;
6970
6971 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6972 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6973 }
6974 }
6975
6976 if (NIL_P(opthash)) {
6977 ecflags = (fmode & FMODE_READABLE) ?
6980#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6981 ecflags |= (fmode & FMODE_WRITABLE) ?
6982 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6983 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6984#endif
6985 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6986 ecopts = Qnil;
6987 if (fmode & FMODE_BINMODE) {
6988#ifdef O_BINARY
6989 oflags |= O_BINARY;
6990#endif
6991 if (!has_enc)
6992 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6993 }
6994#if DEFAULT_TEXTMODE
6995 else if (NIL_P(vmode)) {
6996 fmode |= DEFAULT_TEXTMODE;
6997 }
6998#endif
6999 }
7000 else {
7001 VALUE v;
7002 if (!has_vmode) {
7003 v = rb_hash_aref(opthash, sym_mode);
7004 if (!NIL_P(v)) {
7005 if (!NIL_P(vmode)) {
7006 rb_raise(rb_eArgError, "mode specified twice");
7007 }
7008 has_vmode = 1;
7009 vmode = v;
7010 goto vmode_handle;
7011 }
7012 }
7013 v = rb_hash_aref(opthash, sym_flags);
7014 if (!NIL_P(v)) {
7015 v = rb_to_int(v);
7016 oflags |= NUM2INT(v);
7017 vmode = INT2NUM(oflags);
7018 fmode = rb_io_oflags_fmode(oflags);
7019 }
7020 extract_binmode(opthash, &fmode);
7021 if (fmode & FMODE_BINMODE) {
7022#ifdef O_BINARY
7023 oflags |= O_BINARY;
7024#endif
7025 if (!has_enc)
7026 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7027 }
7028#if DEFAULT_TEXTMODE
7029 else if (NIL_P(vmode)) {
7030 fmode |= DEFAULT_TEXTMODE;
7031 }
7032#endif
7033 v = rb_hash_aref(opthash, sym_perm);
7034 if (!NIL_P(v)) {
7035 if (vperm_p) {
7036 if (!NIL_P(*vperm_p)) {
7037 rb_raise(rb_eArgError, "perm specified twice");
7038 }
7039 *vperm_p = v;
7040 }
7041 else {
7042 /* perm no use, just ignore */
7043 }
7044 }
7045 ecflags = (fmode & FMODE_READABLE) ?
7048#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7049 ecflags |= (fmode & FMODE_WRITABLE) ?
7050 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7051 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7052#endif
7053
7054 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7055 if (has_enc) {
7056 rb_raise(rb_eArgError, "encoding specified twice");
7057 }
7058 }
7059 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7060 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7061 }
7062
7063 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7064
7065 *vmode_p = vmode;
7066
7067 *oflags_p = oflags;
7068 *fmode_p = fmode;
7069 convconfig_p->enc = enc;
7070 convconfig_p->enc2 = enc2;
7071 convconfig_p->ecflags = ecflags;
7072 convconfig_p->ecopts = ecopts;
7073}
7074
7076 VALUE fname;
7077 int oflags;
7078 mode_t perm;
7079};
7080
7081static void *
7082sysopen_func(void *ptr)
7083{
7084 const struct sysopen_struct *data = ptr;
7085 const char *fname = RSTRING_PTR(data->fname);
7086 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7087}
7088
7089static inline int
7090rb_sysopen_internal(struct sysopen_struct *data)
7091{
7092 int fd;
7093 do {
7094 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7095 } while (fd < 0 && errno == EINTR);
7096 if (0 <= fd)
7097 rb_update_max_fd(fd);
7098 return fd;
7099}
7100
7101static int
7102rb_sysopen(VALUE fname, int oflags, mode_t perm)
7103{
7104 int fd = -1;
7105 struct sysopen_struct data;
7106
7107 data.fname = rb_str_encode_ospath(fname);
7108 StringValueCStr(data.fname);
7109 data.oflags = oflags;
7110 data.perm = perm;
7111
7112 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7113 rb_syserr_fail_path(first_errno, fname);
7114 }
7115 return fd;
7116}
7117
7118static inline FILE *
7119fdopen_internal(int fd, const char *modestr)
7120{
7121 FILE *file;
7122
7123#if defined(__sun)
7124 errno = 0;
7125#endif
7126 file = fdopen(fd, modestr);
7127 if (!file) {
7128#ifdef _WIN32
7129 if (errno == 0) errno = EINVAL;
7130#elif defined(__sun)
7131 if (errno == 0) errno = EMFILE;
7132#endif
7133 }
7134 return file;
7135}
7136
7137FILE *
7138rb_fdopen(int fd, const char *modestr)
7139{
7140 FILE *file = 0;
7141
7142 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7143 rb_syserr_fail(first_errno, 0);
7144 }
7145
7146 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7147#ifdef USE_SETVBUF
7148 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7149 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7150#endif
7151 return file;
7152}
7153
7154static int
7155io_check_tty(rb_io_t *fptr)
7156{
7157 int t = isatty(fptr->fd);
7158 if (t)
7159 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7160 return t;
7161}
7162
7163static VALUE rb_io_internal_encoding(VALUE);
7164static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7165
7166static int
7167io_strip_bom(VALUE io)
7168{
7169 VALUE b1, b2, b3, b4;
7170 rb_io_t *fptr;
7171
7172 GetOpenFile(io, fptr);
7173 if (!(fptr->mode & FMODE_READABLE)) return 0;
7174 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7175 switch (b1) {
7176 case INT2FIX(0xEF):
7177 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7178 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7179 if (b3 == INT2FIX(0xBF)) {
7180 return rb_utf8_encindex();
7181 }
7182 rb_io_ungetbyte(io, b3);
7183 }
7184 rb_io_ungetbyte(io, b2);
7185 break;
7186
7187 case INT2FIX(0xFE):
7188 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7189 if (b2 == INT2FIX(0xFF)) {
7190 return ENCINDEX_UTF_16BE;
7191 }
7192 rb_io_ungetbyte(io, b2);
7193 break;
7194
7195 case INT2FIX(0xFF):
7196 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7197 if (b2 == INT2FIX(0xFE)) {
7198 b3 = rb_io_getbyte(io);
7199 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7200 if (b4 == INT2FIX(0)) {
7201 return ENCINDEX_UTF_32LE;
7202 }
7203 rb_io_ungetbyte(io, b4);
7204 }
7205 rb_io_ungetbyte(io, b3);
7206 return ENCINDEX_UTF_16LE;
7207 }
7208 rb_io_ungetbyte(io, b2);
7209 break;
7210
7211 case INT2FIX(0):
7212 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7213 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7214 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7215 if (b4 == INT2FIX(0xFF)) {
7216 return ENCINDEX_UTF_32BE;
7217 }
7218 rb_io_ungetbyte(io, b4);
7219 }
7220 rb_io_ungetbyte(io, b3);
7221 }
7222 rb_io_ungetbyte(io, b2);
7223 break;
7224 }
7225 rb_io_ungetbyte(io, b1);
7226 return 0;
7227}
7228
7229static rb_encoding *
7230io_set_encoding_by_bom(VALUE io)
7231{
7232 int idx = io_strip_bom(io);
7233 rb_io_t *fptr;
7234 rb_encoding *extenc = NULL;
7235
7236 GetOpenFile(io, fptr);
7237 if (idx) {
7238 extenc = rb_enc_from_index(idx);
7239 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7240 rb_io_internal_encoding(io), Qnil);
7241 }
7242 else {
7243 fptr->encs.enc2 = NULL;
7244 }
7245 return extenc;
7246}
7247
7248static VALUE
7249rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7250 const struct rb_io_encoding *convconfig, mode_t perm)
7251{
7252 VALUE pathv;
7253 rb_io_t *fptr;
7254 struct rb_io_encoding cc;
7255 if (!convconfig) {
7256 /* Set to default encodings */
7257 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7258 cc.ecflags = 0;
7259 cc.ecopts = Qnil;
7260 convconfig = &cc;
7261 }
7262 validate_enc_binmode(&fmode, convconfig->ecflags,
7263 convconfig->enc, convconfig->enc2);
7264
7265 MakeOpenFile(io, fptr);
7266 fptr->mode = fmode;
7267 fptr->encs = *convconfig;
7268 pathv = rb_str_new_frozen(filename);
7269#ifdef O_TMPFILE
7270 if (!(oflags & O_TMPFILE)) {
7271 fptr->pathv = pathv;
7272 }
7273#else
7274 fptr->pathv = pathv;
7275#endif
7276 fptr->fd = rb_sysopen(pathv, oflags, perm);
7277 io_check_tty(fptr);
7278 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7279
7280 return io;
7281}
7282
7283static VALUE
7284rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7285{
7286 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7287 const char *p = strchr(modestr, ':');
7288 struct rb_io_encoding convconfig;
7289
7290 if (p) {
7291 parse_mode_enc(p+1, rb_usascii_encoding(),
7292 &convconfig.enc, &convconfig.enc2, &fmode);
7293 }
7294 else {
7295 rb_encoding *e;
7296 /* Set to default encodings */
7297
7298 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7299 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7300 }
7301
7302 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7305#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7306 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7307 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7308 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7309#endif
7310 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7311 convconfig.ecopts = Qnil;
7312
7313 return rb_file_open_generic(io, filename,
7314 rb_io_fmode_oflags(fmode),
7315 fmode,
7316 &convconfig,
7317 0666);
7318}
7319
7320VALUE
7321rb_file_open_str(VALUE fname, const char *modestr)
7322{
7323 FilePathValue(fname);
7324 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7325}
7326
7327VALUE
7328rb_file_open(const char *fname, const char *modestr)
7329{
7330 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7331}
7332
7333#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7334static struct pipe_list {
7335 rb_io_t *fptr;
7336 struct pipe_list *next;
7337} *pipe_list;
7338
7339static void
7340pipe_add_fptr(rb_io_t *fptr)
7341{
7342 struct pipe_list *list;
7343
7344 list = ALLOC(struct pipe_list);
7345 list->fptr = fptr;
7346 list->next = pipe_list;
7347 pipe_list = list;
7348}
7349
7350static void
7351pipe_del_fptr(rb_io_t *fptr)
7352{
7353 struct pipe_list **prev = &pipe_list;
7354 struct pipe_list *tmp;
7355
7356 while ((tmp = *prev) != 0) {
7357 if (tmp->fptr == fptr) {
7358 *prev = tmp->next;
7359 free(tmp);
7360 return;
7361 }
7362 prev = &tmp->next;
7363 }
7364}
7365
7366#if defined (_WIN32) || defined(__CYGWIN__)
7367static void
7368pipe_atexit(void)
7369{
7370 struct pipe_list *list = pipe_list;
7371 struct pipe_list *tmp;
7372
7373 while (list) {
7374 tmp = list->next;
7375 rb_io_fptr_finalize(list->fptr);
7376 list = tmp;
7377 }
7378}
7379#endif
7380
7381static void
7382pipe_finalize(rb_io_t *fptr, int noraise)
7383{
7384#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7385 int status = 0;
7386 if (fptr->stdio_file) {
7387 status = pclose(fptr->stdio_file);
7388 }
7389 fptr->fd = -1;
7390 fptr->stdio_file = 0;
7391 rb_last_status_set(status, fptr->pid);
7392#else
7393 fptr_finalize(fptr, noraise);
7394#endif
7395 pipe_del_fptr(fptr);
7396}
7397#endif
7398
7399static void
7400fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7401{
7402#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7403 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7404
7405 if (old_finalize == orig->finalize) return;
7406#endif
7407
7408 fptr->finalize = orig->finalize;
7409
7410#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7411 if (old_finalize != pipe_finalize) {
7412 struct pipe_list *list;
7413 for (list = pipe_list; list; list = list->next) {
7414 if (list->fptr == fptr) break;
7415 }
7416 if (!list) pipe_add_fptr(fptr);
7417 }
7418 else {
7419 pipe_del_fptr(fptr);
7420 }
7421#endif
7422}
7423
7424void
7426{
7428 fptr->mode |= FMODE_SYNC;
7429}
7430
7431void
7432rb_io_unbuffered(rb_io_t *fptr)
7433{
7434 rb_io_synchronized(fptr);
7435}
7436
7437int
7438rb_pipe(int *pipes)
7439{
7440 int ret;
7441 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7442 if (ret == 0) {
7443 rb_update_max_fd(pipes[0]);
7444 rb_update_max_fd(pipes[1]);
7445 }
7446 return ret;
7447}
7448
7449#ifdef _WIN32
7450#define HAVE_SPAWNV 1
7451#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7452#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7453#endif
7454
7455#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7456struct popen_arg {
7457 VALUE execarg_obj;
7458 struct rb_execarg *eargp;
7459 int modef;
7460 int pair[2];
7461 int write_pair[2];
7462};
7463#endif
7464
7465#ifdef HAVE_WORKING_FORK
7466# ifndef __EMSCRIPTEN__
7467static void
7468popen_redirect(struct popen_arg *p)
7469{
7470 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7471 close(p->write_pair[1]);
7472 if (p->write_pair[0] != 0) {
7473 dup2(p->write_pair[0], 0);
7474 close(p->write_pair[0]);
7475 }
7476 close(p->pair[0]);
7477 if (p->pair[1] != 1) {
7478 dup2(p->pair[1], 1);
7479 close(p->pair[1]);
7480 }
7481 }
7482 else if (p->modef & FMODE_READABLE) {
7483 close(p->pair[0]);
7484 if (p->pair[1] != 1) {
7485 dup2(p->pair[1], 1);
7486 close(p->pair[1]);
7487 }
7488 }
7489 else {
7490 close(p->pair[1]);
7491 if (p->pair[0] != 0) {
7492 dup2(p->pair[0], 0);
7493 close(p->pair[0]);
7494 }
7495 }
7496}
7497# endif
7498
7499#if defined(__linux__)
7500/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7501 * Since /proc may not be available, linux_get_maxfd is just a hint.
7502 * This function, linux_get_maxfd, must be async-signal-safe.
7503 * I.e. opendir() is not usable.
7504 *
7505 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7506 * However they are easy to re-implement in async-signal-safe manner.
7507 * (Also note that there is missing/memcmp.c.)
7508 */
7509static int
7510linux_get_maxfd(void)
7511{
7512 int fd;
7513 char buf[4096], *p, *np, *e;
7514 ssize_t ss;
7515 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7516 if (fd < 0) return fd;
7517 ss = read(fd, buf, sizeof(buf));
7518 if (ss < 0) goto err;
7519 p = buf;
7520 e = buf + ss;
7521 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7522 (np = memchr(p, '\n', e-p)) != NULL) {
7523 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7524 int fdsize;
7525 p += sizeof("FDSize:")-1;
7526 *np = '\0';
7527 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7528 close(fd);
7529 return fdsize;
7530 }
7531 p = np+1;
7532 }
7533 /* fall through */
7534
7535 err:
7536 close(fd);
7537 return (int)ss;
7538}
7539#endif
7540
7541/* This function should be async-signal-safe. */
7542void
7543rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7544{
7545#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7546 int fd, ret;
7547 int max = (int)max_file_descriptor;
7548# ifdef F_MAXFD
7549 /* F_MAXFD is available since NetBSD 2.0. */
7550 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7551 if (ret != -1)
7552 maxhint = max = ret;
7553# elif defined(__linux__)
7554 ret = linux_get_maxfd();
7555 if (maxhint < ret)
7556 maxhint = ret;
7557 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7558# endif
7559 if (max < maxhint)
7560 max = maxhint;
7561 for (fd = lowfd; fd <= max; fd++) {
7562 if (!NIL_P(noclose_fds) &&
7563 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7564 continue;
7565 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7566 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7567 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7568 }
7569# define CONTIGUOUS_CLOSED_FDS 20
7570 if (ret != -1) {
7571 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7572 max = fd + CONTIGUOUS_CLOSED_FDS;
7573 }
7574 }
7575#endif
7576}
7577
7578# ifndef __EMSCRIPTEN__
7579static int
7580popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7581{
7582 struct popen_arg *p = (struct popen_arg*)pp;
7583
7584 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7585}
7586# endif
7587#endif
7588
7589#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7590static VALUE
7591rb_execarg_fixup_v(VALUE execarg_obj)
7592{
7593 rb_execarg_parent_start(execarg_obj);
7594 return Qnil;
7595}
7596#else
7597char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7598#endif
7599
7600#ifndef __EMSCRIPTEN__
7601static VALUE
7602pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7603 const struct rb_io_encoding *convconfig)
7604{
7605 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7606 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7607 rb_pid_t pid = 0;
7608 rb_io_t *fptr;
7609 VALUE port;
7610 rb_io_t *write_fptr;
7611 VALUE write_port;
7612#if defined(HAVE_WORKING_FORK)
7613 int status;
7614 char errmsg[80] = { '\0' };
7615#endif
7616#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7617 int state;
7618 struct popen_arg arg;
7619#endif
7620 int e = 0;
7621#if defined(HAVE_SPAWNV)
7622# if defined(HAVE_SPAWNVE)
7623# define DO_SPAWN(cmd, args, envp) ((args) ? \
7624 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7625 spawne(P_NOWAIT, (cmd), (envp)))
7626# else
7627# define DO_SPAWN(cmd, args, envp) ((args) ? \
7628 spawnv(P_NOWAIT, (cmd), (args)) : \
7629 spawn(P_NOWAIT, (cmd)))
7630# endif
7631# if !defined(HAVE_WORKING_FORK)
7632 char **args = NULL;
7633# if defined(HAVE_SPAWNVE)
7634 char **envp = NULL;
7635# endif
7636# endif
7637#endif
7638#if !defined(HAVE_WORKING_FORK)
7639 struct rb_execarg sarg, *sargp = &sarg;
7640#endif
7641 FILE *fp = 0;
7642 int fd = -1;
7643 int write_fd = -1;
7644#if !defined(HAVE_WORKING_FORK)
7645 const char *cmd = 0;
7646
7647 if (prog)
7648 cmd = StringValueCStr(prog);
7649#endif
7650
7651#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7652 arg.execarg_obj = execarg_obj;
7653 arg.eargp = eargp;
7654 arg.modef = fmode;
7655 arg.pair[0] = arg.pair[1] = -1;
7656 arg.write_pair[0] = arg.write_pair[1] = -1;
7657# if !defined(HAVE_WORKING_FORK)
7658 if (eargp && !eargp->use_shell) {
7659 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7660 }
7661# endif
7662 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7664 if (rb_pipe(arg.write_pair) < 0)
7665 rb_sys_fail_str(prog);
7666 if (rb_pipe(arg.pair) < 0) {
7667 e = errno;
7668 close(arg.write_pair[0]);
7669 close(arg.write_pair[1]);
7670 rb_syserr_fail_str(e, prog);
7671 }
7672 if (eargp) {
7673 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7674 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7675 }
7676 break;
7677 case FMODE_READABLE:
7678 if (rb_pipe(arg.pair) < 0)
7679 rb_sys_fail_str(prog);
7680 if (eargp)
7681 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7682 break;
7683 case FMODE_WRITABLE:
7684 if (rb_pipe(arg.pair) < 0)
7685 rb_sys_fail_str(prog);
7686 if (eargp)
7687 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7688 break;
7689 default:
7690 rb_sys_fail_str(prog);
7691 }
7692 if (!NIL_P(execarg_obj)) {
7693 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7694 if (state) {
7695 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7696 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7697 if (0 <= arg.pair[0]) close(arg.pair[0]);
7698 if (0 <= arg.pair[1]) close(arg.pair[1]);
7699 rb_execarg_parent_end(execarg_obj);
7700 rb_jump_tag(state);
7701 }
7702
7703# if defined(HAVE_WORKING_FORK)
7704 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7705# else
7706 rb_execarg_run_options(eargp, sargp, NULL, 0);
7707# if defined(HAVE_SPAWNVE)
7708 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7709# endif
7710 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7711 /* exec failed */
7712 switch (e = errno) {
7713 case EAGAIN:
7714# if EWOULDBLOCK != EAGAIN
7715 case EWOULDBLOCK:
7716# endif
7717 rb_thread_sleep(1);
7718 continue;
7719 }
7720 break;
7721 }
7722 if (eargp)
7723 rb_execarg_run_options(sargp, NULL, NULL, 0);
7724# endif
7725 rb_execarg_parent_end(execarg_obj);
7726 }
7727 else {
7728# if defined(HAVE_WORKING_FORK)
7729 pid = rb_call_proc__fork();
7730 if (pid == 0) { /* child */
7731 popen_redirect(&arg);
7732 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7733 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7734 return Qnil;
7735 }
7736# else
7737 rb_notimplement();
7738# endif
7739 }
7740
7741 /* parent */
7742 if (pid < 0) {
7743# if defined(HAVE_WORKING_FORK)
7744 e = errno;
7745# endif
7746 close(arg.pair[0]);
7747 close(arg.pair[1]);
7749 close(arg.write_pair[0]);
7750 close(arg.write_pair[1]);
7751 }
7752# if defined(HAVE_WORKING_FORK)
7753 if (errmsg[0])
7754 rb_syserr_fail(e, errmsg);
7755# endif
7756 rb_syserr_fail_str(e, prog);
7757 }
7758 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7759 close(arg.pair[1]);
7760 fd = arg.pair[0];
7761 close(arg.write_pair[0]);
7762 write_fd = arg.write_pair[1];
7763 }
7764 else if (fmode & FMODE_READABLE) {
7765 close(arg.pair[1]);
7766 fd = arg.pair[0];
7767 }
7768 else {
7769 close(arg.pair[0]);
7770 fd = arg.pair[1];
7771 }
7772#else
7773 cmd = rb_execarg_commandline(eargp, &prog);
7774 if (!NIL_P(execarg_obj)) {
7775 rb_execarg_parent_start(execarg_obj);
7776 rb_execarg_run_options(eargp, sargp, NULL, 0);
7777 }
7778 fp = popen(cmd, modestr);
7779 e = errno;
7780 if (eargp) {
7781 rb_execarg_parent_end(execarg_obj);
7782 rb_execarg_run_options(sargp, NULL, NULL, 0);
7783 }
7784 if (!fp) rb_syserr_fail_path(e, prog);
7785 fd = fileno(fp);
7786#endif
7787
7788 port = io_alloc(rb_cIO);
7789 MakeOpenFile(port, fptr);
7790 fptr->fd = fd;
7791 fptr->stdio_file = fp;
7792 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7793 if (convconfig) {
7794 fptr->encs = *convconfig;
7795#if RUBY_CRLF_ENVIRONMENT
7798 }
7799#endif
7800 }
7801 else {
7802 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7804 }
7805#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7806 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7807 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7808 }
7809#endif
7810 }
7811 fptr->pid = pid;
7812
7813 if (0 <= write_fd) {
7814 write_port = io_alloc(rb_cIO);
7815 MakeOpenFile(write_port, write_fptr);
7816 write_fptr->fd = write_fd;
7817 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7818 fptr->mode &= ~FMODE_WRITABLE;
7819 fptr->tied_io_for_writing = write_port;
7820 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7821 }
7822
7823#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7824 fptr->finalize = pipe_finalize;
7825 pipe_add_fptr(fptr);
7826#endif
7827 return port;
7828}
7829#else
7830static VALUE
7831pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7832 const struct rb_io_encoding *convconfig)
7833{
7834 rb_raise(rb_eNotImpError, "popen() is not available");
7835}
7836#endif
7837
7838static int
7839is_popen_fork(VALUE prog)
7840{
7841 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7842#if !defined(HAVE_WORKING_FORK)
7843 rb_raise(rb_eNotImpError,
7844 "fork() function is unimplemented on this machine");
7845#else
7846 return TRUE;
7847#endif
7848 }
7849 return FALSE;
7850}
7851
7852static VALUE
7853pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7854 const struct rb_io_encoding *convconfig)
7855{
7856 int argc = 1;
7857 VALUE *argv = &prog;
7858 VALUE execarg_obj = Qnil;
7859
7860 if (!is_popen_fork(prog))
7861 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7862 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7863}
7864
7865static VALUE
7866pipe_close(VALUE io)
7867{
7868 rb_io_t *fptr = io_close_fptr(io);
7869 if (fptr) {
7870 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7871 }
7872 return Qnil;
7873}
7874
7875static VALUE popen_finish(VALUE port, VALUE klass);
7876
7877/*
7878 * call-seq:
7879 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7880 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7881 *
7882 * Executes the given command +cmd+ as a subprocess
7883 * whose $stdin and $stdout are connected to a new stream +io+.
7884 *
7885 * This method has potential security vulnerabilities if called with untrusted input;
7886 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
7887 *
7888 * If no block is given, returns the new stream,
7889 * which depending on given +mode+ may be open for reading, writing, or both.
7890 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7891 *
7892 * If a block is given, the stream is passed to the block
7893 * (again, open for reading, writing, or both);
7894 * when the block exits, the stream is closed,
7895 * the block's value is returned,
7896 * and the global variable <tt>$?</tt> is set to the child's exit status.
7897 *
7898 * Optional argument +mode+ may be any valid \IO mode.
7899 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7900 *
7901 * Required argument +cmd+ determines which of the following occurs:
7902 *
7903 * - The process forks.
7904 * - A specified program runs in a shell.
7905 * - A specified program runs with specified arguments.
7906 * - A specified program runs with specified arguments and a specified +argv0+.
7907 *
7908 * Each of these is detailed below.
7909 *
7910 * The optional hash argument +env+ specifies name/value pairs that are to be added
7911 * to the environment variables for the subprocess:
7912 *
7913 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7914 * pipe.puts 'puts ENV["FOO"]'
7915 * pipe.close_write
7916 * pipe.gets
7917 * end => "bar\n"
7918 *
7919 * Optional keyword arguments +opts+ specify:
7920 *
7921 * - {Open options}[rdoc-ref:IO@Open+Options].
7922 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7923 * - Options for Kernel#spawn.
7924 *
7925 * <b>Forked Process</b>
7926 *
7927 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7928 * IO.popen('-') do |pipe|
7929 * if pipe
7930 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7931 * else
7932 * $stderr.puts "In child, pid is #{$$}\n"
7933 * end
7934 * end
7935 *
7936 * Output:
7937 *
7938 * In parent, child pid is 26253
7939 * In child, pid is 26253
7940 *
7941 * Note that this is not supported on all platforms.
7942 *
7943 * <b>Shell Subprocess</b>
7944 *
7945 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7946 * the program named +cmd+ is run as a shell command:
7947 *
7948 * IO.popen('uname') do |pipe|
7949 * pipe.readlines
7950 * end
7951 *
7952 * Output:
7953 *
7954 * ["Linux\n"]
7955 *
7956 * Another example:
7957 *
7958 * IO.popen('/bin/sh', 'r+') do |pipe|
7959 * pipe.puts('ls')
7960 * pipe.close_write
7961 * $stderr.puts pipe.readlines.size
7962 * end
7963 *
7964 * Output:
7965 *
7966 * 213
7967 *
7968 * <b>Program Subprocess</b>
7969 *
7970 * When argument +cmd+ is an array of strings,
7971 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7972 *
7973 * IO.popen(['du', '..', '.']) do |pipe|
7974 * $stderr.puts pipe.readlines.size
7975 * end
7976 *
7977 * Output:
7978 *
7979 * 1111
7980 *
7981 * <b>Program Subprocess with <tt>argv0</tt></b>
7982 *
7983 * When argument +cmd+ is an array whose first element is a 2-element string array
7984 * and whose remaining elements (if any) are strings:
7985 *
7986 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7987 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7988 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7989 *
7990 * Example (sets <tt>$0</tt> to 'foo'):
7991 *
7992 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7993 *
7994 * <b>Some Special Examples</b>
7995 *
7996 * # Set IO encoding.
7997 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7998 * euc_jp_string = nkf_io.read
7999 * }
8000 *
8001 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
8002 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
8003 * ls_result_with_error = io.read
8004 * end
8005 *
8006 * # Use mixture of spawn options and IO options.
8007 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
8008 * ls_result_with_error = io.read
8009 * end
8010 *
8011 * f = IO.popen("uname")
8012 * p f.readlines
8013 * f.close
8014 * puts "Parent is #{Process.pid}"
8015 * IO.popen("date") {|f| puts f.gets }
8016 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
8017 * p $?
8018 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
8019 * f.puts "bar"; f.close_write; puts f.gets
8020 * }
8021 *
8022 * Output (from last section):
8023 *
8024 * ["Linux\n"]
8025 * Parent is 21346
8026 * Thu Jan 15 22:41:19 JST 2009
8027 * 21346 is here, f is #<IO:fd 3>
8028 * 21352 is here, f is nil
8029 * #<Process::Status: pid 21352 exit 0>
8030 * <foo>bar;zot;
8031 *
8032 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8033 *
8034 */
8035
8036static VALUE
8037rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8038{
8039 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8040
8041 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8042 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8043 switch (argc) {
8044 case 2:
8045 pmode = argv[1];
8046 case 1:
8047 pname = argv[0];
8048 break;
8049 default:
8050 {
8051 int ex = !NIL_P(opt);
8052 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8053 }
8054 }
8055 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8056}
8057
8058VALUE
8059rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8060{
8061 const char *modestr;
8062 VALUE tmp, execarg_obj = Qnil;
8063 int oflags;
8064 enum rb_io_mode fmode;
8065 struct rb_io_encoding convconfig;
8066
8067 tmp = rb_check_array_type(pname);
8068 if (!NIL_P(tmp)) {
8069 long len = RARRAY_LEN(tmp);
8070#if SIZEOF_LONG > SIZEOF_INT
8071 if (len > INT_MAX) {
8072 rb_raise(rb_eArgError, "too many arguments");
8073 }
8074#endif
8075 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8076 RB_GC_GUARD(tmp);
8077 }
8078 else {
8079 StringValue(pname);
8080 execarg_obj = Qnil;
8081 if (!is_popen_fork(pname))
8082 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8083 }
8084 if (!NIL_P(execarg_obj)) {
8085 if (!NIL_P(opt))
8086 opt = rb_execarg_extract_options(execarg_obj, opt);
8087 if (!NIL_P(env))
8088 rb_execarg_setenv(execarg_obj, env);
8089 }
8090 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8091 modestr = rb_io_oflags_modestr(oflags);
8092
8093 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8094}
8095
8096static VALUE
8097popen_finish(VALUE port, VALUE klass)
8098{
8099 if (NIL_P(port)) {
8100 /* child */
8101 if (rb_block_given_p()) {
8102 rb_protect(rb_yield, Qnil, NULL);
8103 rb_io_flush(rb_ractor_stdout());
8104 rb_io_flush(rb_ractor_stderr());
8105 _exit(EXIT_SUCCESS);
8106 }
8107 return Qnil;
8108 }
8109 RBASIC_SET_CLASS(port, klass);
8110 if (rb_block_given_p()) {
8111 return rb_ensure(rb_yield, port, pipe_close, port);
8112 }
8113 return port;
8114}
8115
8116#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8117struct popen_writer_arg {
8118 char *const *argv;
8119 struct popen_arg popen;
8120};
8121
8122static int
8123exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8124{
8125 struct popen_writer_arg *pw = arg;
8126 pw->popen.modef = FMODE_WRITABLE;
8127 popen_redirect(&pw->popen);
8128 execv(pw->argv[0], pw->argv);
8129 strlcpy(errmsg, strerror(errno), buflen);
8130 return -1;
8131}
8132#endif
8133
8134FILE *
8135ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8136{
8137#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8138# ifdef HAVE_WORKING_FORK
8139 struct popen_writer_arg pw;
8140 int *const write_pair = pw.popen.pair;
8141# else
8142 int write_pair[2];
8143# endif
8144
8145#ifdef HAVE_PIPE2
8146 int result = pipe2(write_pair, O_CLOEXEC);
8147#else
8148 int result = pipe(write_pair);
8149#endif
8150
8151 *pid = -1;
8152 if (result == 0) {
8153# ifdef HAVE_WORKING_FORK
8154 pw.argv = argv;
8155 int status;
8156 char errmsg[80] = {'\0'};
8157 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8158# else
8159 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8160 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8161# endif
8162 close(write_pair[0]);
8163 if (*pid < 0) {
8164 close(write_pair[1]);
8165 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8166 }
8167 else {
8168 return fdopen(write_pair[1], "w");
8169 }
8170 }
8171#endif
8172 return NULL;
8173}
8174
8175static VALUE
8176rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8177{
8178 int oflags;
8179 enum rb_io_mode fmode;
8180 struct rb_io_encoding convconfig;
8181 mode_t perm;
8182
8183 FilePathValue(fname);
8184
8185 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8186 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8187
8188 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8189
8190 return io;
8191}
8192
8193/*
8194 * Document-method: File::open
8195 *
8196 * call-seq:
8197 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8198 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8199 *
8200 * Creates a new File object, via File.new with the given arguments.
8201 *
8202 * With no block given, returns the File object.
8203 *
8204 * With a block given, calls the block with the File object
8205 * and returns the block's value.
8206 *
8207 */
8208
8209/*
8210 * Document-method: IO::open
8211 *
8212 * call-seq:
8213 * IO.open(fd, mode = 'r', **opts) -> io
8214 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8215 *
8216 * Creates a new \IO object, via IO.new with the given arguments.
8217 *
8218 * With no block given, returns the \IO object.
8219 *
8220 * With a block given, calls the block with the \IO object
8221 * and returns the block's value.
8222 *
8223 */
8224
8225static VALUE
8226rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8227{
8229
8230 if (rb_block_given_p()) {
8231 return rb_ensure(rb_yield, io, io_close, io);
8232 }
8233
8234 return io;
8235}
8236
8237/*
8238 * call-seq:
8239 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8240 *
8241 * Opens the file at the given path with the given mode and permissions;
8242 * returns the integer file descriptor.
8243 *
8244 * If the file is to be readable, it must exist;
8245 * if the file is to be writable and does not exist,
8246 * it is created with the given permissions:
8247 *
8248 * File.write('t.tmp', '') # => 0
8249 * IO.sysopen('t.tmp') # => 8
8250 * IO.sysopen('t.tmp', 'w') # => 9
8251 *
8252 *
8253 */
8254
8255static VALUE
8256rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8257{
8258 VALUE fname, vmode, vperm;
8259 VALUE intmode;
8260 int oflags, fd;
8261 mode_t perm;
8262
8263 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8264 FilePathValue(fname);
8265
8266 if (NIL_P(vmode))
8267 oflags = O_RDONLY;
8268 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8269 oflags = NUM2INT(intmode);
8270 else {
8271 StringValue(vmode);
8272 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8273 }
8274 if (NIL_P(vperm)) perm = 0666;
8275 else perm = NUM2MODET(vperm);
8276
8277 RB_GC_GUARD(fname) = rb_str_new4(fname);
8278 fd = rb_sysopen(fname, oflags, perm);
8279 return INT2NUM(fd);
8280}
8281
8282/*
8283 * call-seq:
8284 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8285 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8286 *
8287 * Creates an IO object connected to the given file.
8288 *
8289 * With no block given, file stream is returned:
8290 *
8291 * open('t.txt') # => #<File:t.txt>
8292 *
8293 * With a block given, calls the block with the open file stream,
8294 * then closes the stream:
8295 *
8296 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8297 *
8298 * Output:
8299 *
8300 * #<File:t.txt>
8301 *
8302 * See File.open for details.
8303 *
8304 */
8305
8306static VALUE
8307rb_f_open(int argc, VALUE *argv, VALUE _)
8308{
8309 ID to_open = 0;
8310 int redirect = FALSE;
8311
8312 if (argc >= 1) {
8313 CONST_ID(to_open, "to_open");
8314 if (rb_respond_to(argv[0], to_open)) {
8315 redirect = TRUE;
8316 }
8317 else {
8318 VALUE tmp = argv[0];
8319 FilePathValue(tmp);
8320 if (NIL_P(tmp)) {
8321 redirect = TRUE;
8322 }
8323 else {
8324 argv[0] = tmp;
8325 }
8326 }
8327 }
8328 if (redirect) {
8329 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8330
8331 if (rb_block_given_p()) {
8332 return rb_ensure(rb_yield, io, io_close, io);
8333 }
8334 return io;
8335 }
8336 return rb_io_s_open(argc, argv, rb_cFile);
8337}
8338
8339static VALUE
8340rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8341 const struct rb_io_encoding *convconfig, mode_t perm)
8342{
8343 return rb_file_open_generic(io_alloc(klass), filename,
8344 oflags, fmode, convconfig, perm);
8345}
8346
8347static VALUE
8348rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8349{
8350 int oflags;
8351 enum rb_io_mode fmode;
8352 struct rb_io_encoding convconfig;
8353 mode_t perm;
8354
8355 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8356 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8357 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8358}
8359
8360static VALUE
8361io_reopen(VALUE io, VALUE nfile)
8362{
8363 rb_io_t *fptr, *orig;
8364 int fd, fd2;
8365 rb_off_t pos = 0;
8366
8367 nfile = rb_io_get_io(nfile);
8368 GetOpenFile(io, fptr);
8369 GetOpenFile(nfile, orig);
8370
8371 if (fptr == orig) return io;
8372 if (RUBY_IO_EXTERNAL_P(fptr)) {
8373 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8374 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8375 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8376 rb_raise(rb_eArgError,
8377 "%s can't change access mode from \"%s\" to \"%s\"",
8378 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8379 rb_io_fmode_modestr(orig->mode));
8380 }
8381 }
8382 flush_before_seek(fptr, true);
8383 /* in flush_before_seek, clear_codeconv called only if rbuf is filled */
8384 clear_codeconv(fptr);
8385 if (orig->mode & FMODE_READABLE) {
8386 pos = io_tell(orig);
8387 }
8388 if (orig->mode & FMODE_WRITABLE) {
8389 if (io_fflush(orig) < 0)
8390 rb_sys_fail_on_write(fptr);
8391 }
8392
8393 /* copy rb_io_t structure */
8394 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8395 fptr->encs = orig->encs;
8396 fptr->pid = orig->pid;
8397 fptr->lineno = orig->lineno;
8398 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8399 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8400 fptr_copy_finalizer(fptr, orig);
8401
8402 fd = fptr->fd;
8403 fd2 = orig->fd;
8404 if (fd != fd2) {
8405 // Interrupt all usage of the old file descriptor:
8406 rb_thread_io_close_interrupt(fptr);
8407 rb_thread_io_close_wait(fptr);
8408
8409 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8410 /* need to keep FILE objects of stdin, stdout and stderr */
8411 if (rb_cloexec_dup2(fd2, fd) < 0)
8412 rb_sys_fail_path(orig->pathv);
8413 rb_update_max_fd(fd);
8414 }
8415 else {
8416 fclose(fptr->stdio_file);
8417 fptr->stdio_file = 0;
8418 fptr->fd = -1;
8419 if (rb_cloexec_dup2(fd2, fd) < 0)
8420 rb_sys_fail_path(orig->pathv);
8421 rb_update_max_fd(fd);
8422 fptr->fd = fd;
8423 }
8424
8425 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8426 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8427 rb_sys_fail_path(fptr->pathv);
8428 }
8429 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8430 rb_sys_fail_path(orig->pathv);
8431 }
8432 }
8433 }
8434
8435 if (fptr->mode & FMODE_BINMODE) {
8436 rb_io_binmode(io);
8437 }
8438
8439 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8440 return io;
8441}
8442
8443#ifdef _WIN32
8444int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8445#else
8446static int
8447rb_freopen(VALUE fname, const char *mode, FILE *fp)
8448{
8449 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8450 RB_GC_GUARD(fname);
8451 return errno;
8452 }
8453 return 0;
8454}
8455#endif
8456
8457/*
8458 * call-seq:
8459 * reopen(other_io) -> self
8460 * reopen(path, mode = 'r', **opts) -> self
8461 *
8462 * Reassociates the stream with another stream,
8463 * which may be of a different class.
8464 * This method may be used to redirect an existing stream
8465 * to a new destination.
8466 *
8467 * With argument +other_io+ given, reassociates with that stream:
8468 *
8469 * # Redirect $stdin from a file.
8470 * f = File.open('t.txt')
8471 * $stdin.reopen(f)
8472 * f.close
8473 *
8474 * # Redirect $stdout to a file.
8475 * f = File.open('t.tmp', 'w')
8476 * $stdout.reopen(f)
8477 * f.close
8478 *
8479 * With argument +path+ given, reassociates with a new stream to that file path:
8480 *
8481 * $stdin.reopen('t.txt')
8482 * $stdout.reopen('t.tmp', 'w')
8483 *
8484 * Optional keyword arguments +opts+ specify:
8485 *
8486 * - {Open Options}[rdoc-ref:IO@Open+Options].
8487 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8488 *
8489 */
8490
8491static VALUE
8492rb_io_reopen(int argc, VALUE *argv, VALUE file)
8493{
8494 VALUE fname, nmode, opt;
8495 int oflags;
8496 rb_io_t *fptr;
8497
8498 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8499 VALUE tmp = rb_io_check_io(fname);
8500 if (!NIL_P(tmp)) {
8501 return io_reopen(file, tmp);
8502 }
8503 }
8504
8505 FilePathValue(fname);
8506 rb_io_taint_check(file);
8507 fptr = RFILE(file)->fptr;
8508 if (!fptr) {
8509 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8510 }
8511
8512 if (!NIL_P(nmode) || !NIL_P(opt)) {
8513 enum rb_io_mode fmode;
8514 struct rb_io_encoding convconfig;
8515
8516 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8517 if (RUBY_IO_EXTERNAL_P(fptr) &&
8518 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8519 (fptr->mode & FMODE_READWRITE)) {
8520 rb_raise(rb_eArgError,
8521 "%s can't change access mode from \"%s\" to \"%s\"",
8522 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8523 rb_io_fmode_modestr(fmode));
8524 }
8525 fptr->mode = fmode;
8526 fptr->encs = convconfig;
8527 }
8528 else {
8529 oflags = rb_io_fmode_oflags(fptr->mode);
8530 }
8531
8532 fptr->pathv = fname;
8533 if (fptr->fd < 0) {
8534 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8535 fptr->stdio_file = 0;
8536 return file;
8537 }
8538
8539 if (fptr->mode & FMODE_WRITABLE) {
8540 if (io_fflush(fptr) < 0)
8541 rb_sys_fail_on_write(fptr);
8542 }
8543 fptr->rbuf.off = fptr->rbuf.len = 0;
8544 clear_codeconv(fptr);
8545
8546 if (fptr->stdio_file) {
8547 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8548 rb_io_oflags_modestr(oflags),
8549 fptr->stdio_file);
8550 if (e) rb_syserr_fail_path(e, fptr->pathv);
8551 fptr->fd = fileno(fptr->stdio_file);
8552 rb_fd_fix_cloexec(fptr->fd);
8553#ifdef USE_SETVBUF
8554 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8555 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8556#endif
8557 if (fptr->stdio_file == stderr) {
8558 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8559 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8560 }
8561 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8562 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8563 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8564 }
8565 }
8566 else {
8567 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8568 int err = 0;
8569 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8570 err = errno;
8571 (void)close(tmpfd);
8572 if (err) {
8573 rb_syserr_fail_path(err, fptr->pathv);
8574 }
8575 }
8576
8577 return file;
8578}
8579
8580/* :nodoc: */
8581static VALUE
8582rb_io_init_copy(VALUE dest, VALUE io)
8583{
8584 rb_io_t *fptr, *orig;
8585 int fd;
8586 VALUE write_io;
8587 rb_off_t pos;
8588
8589 io = rb_io_get_io(io);
8590 if (!OBJ_INIT_COPY(dest, io)) return dest;
8591 GetOpenFile(io, orig);
8592 MakeOpenFile(dest, fptr);
8593
8594 rb_io_flush(io);
8595
8596 /* copy rb_io_t structure */
8597 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8598 fptr->encs = orig->encs;
8599 fptr->pid = orig->pid;
8600 fptr->lineno = orig->lineno;
8601 fptr->timeout = orig->timeout;
8602
8603 ccan_list_head_init(&fptr->blocking_operations);
8604 fptr->closing_ec = NULL;
8605 fptr->wakeup_mutex = Qnil;
8606 fptr->fork_generation = GET_VM()->fork_gen;
8607
8608 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8609 fptr_copy_finalizer(fptr, orig);
8610
8611 fd = ruby_dup(orig->fd);
8612 fptr->fd = fd;
8613 pos = io_tell(orig);
8614 if (0 <= pos)
8615 io_seek(fptr, pos, SEEK_SET);
8616 if (fptr->mode & FMODE_BINMODE) {
8617 rb_io_binmode(dest);
8618 }
8619
8620 write_io = GetWriteIO(io);
8621 if (io != write_io) {
8622 write_io = rb_obj_dup(write_io);
8623 fptr->tied_io_for_writing = write_io;
8624 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8625 }
8626
8627 return dest;
8628}
8629
8630/*
8631 * call-seq:
8632 * printf(format_string, *objects) -> nil
8633 *
8634 * Formats and writes +objects+ to the stream.
8635 *
8636 * For details on +format_string+, see
8637 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8638 *
8639 */
8640
8641VALUE
8642rb_io_printf(int argc, const VALUE *argv, VALUE out)
8643{
8644 rb_io_write(out, rb_f_sprintf(argc, argv));
8645 return Qnil;
8646}
8647
8648/*
8649 * call-seq:
8650 * printf(format_string, *objects) -> nil
8651 * printf(io, format_string, *objects) -> nil
8652 *
8653 * Equivalent to:
8654 *
8655 * io.write(sprintf(format_string, *objects))
8656 *
8657 * For details on +format_string+, see
8658 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8659 *
8660 * With the single argument +format_string+, formats +objects+ into the string,
8661 * then writes the formatted string to $stdout:
8662 *
8663 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8664 *
8665 * Output (on $stdout):
8666 *
8667 * 0024 24 24.00#
8668 *
8669 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8670 * then writes the formatted string to +io+:
8671 *
8672 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8673 *
8674 * Output (on $stderr):
8675 *
8676 * 0024 24 24.00# => nil
8677 *
8678 * With no arguments, does nothing.
8679 *
8680 */
8681
8682static VALUE
8683rb_f_printf(int argc, VALUE *argv, VALUE _)
8684{
8685 VALUE out;
8686
8687 if (argc == 0) return Qnil;
8688 if (RB_TYPE_P(argv[0], T_STRING)) {
8689 out = rb_ractor_stdout();
8690 }
8691 else {
8692 out = argv[0];
8693 argv++;
8694 argc--;
8695 }
8696 rb_io_write(out, rb_f_sprintf(argc, argv));
8697
8698 return Qnil;
8699}
8700
8701extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8702
8703static void
8704deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8705{
8706 rb_deprecated_str_setter(val, id, &val);
8707 if (!NIL_P(val)) {
8708 if (rb_str_equal(val, rb_default_rs)) {
8709 val = rb_default_rs;
8710 }
8711 else {
8712 val = rb_str_frozen_bare_string(val);
8713 }
8714 }
8715 *var = val;
8716}
8717
8718/*
8719 * call-seq:
8720 * print(*objects) -> nil
8721 *
8722 * Writes the given objects to the stream; returns +nil+.
8723 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8724 * (<tt>$\</tt>), if it is not +nil+.
8725 * See {Line IO}[rdoc-ref:IO@Line+IO].
8726 *
8727 * With argument +objects+ given, for each object:
8728 *
8729 * - Converts via its method +to_s+ if not a string.
8730 * - Writes to the stream.
8731 * - If not the last object, writes the output field separator
8732 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8733 *
8734 * With default separators:
8735 *
8736 * f = File.open('t.tmp', 'w+')
8737 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8738 * p $OUTPUT_RECORD_SEPARATOR
8739 * p $OUTPUT_FIELD_SEPARATOR
8740 * f.print(*objects)
8741 * f.rewind
8742 * p f.read
8743 * f.close
8744 *
8745 * Output:
8746 *
8747 * nil
8748 * nil
8749 * "00.00/10+0izerozero"
8750 *
8751 * With specified separators:
8752 *
8753 * $\ = "\n"
8754 * $, = ','
8755 * f.rewind
8756 * f.print(*objects)
8757 * f.rewind
8758 * p f.read
8759 *
8760 * Output:
8761 *
8762 * "0,0.0,0/1,0+0i,zero,zero\n"
8763 *
8764 * With no argument given, writes the content of <tt>$_</tt>
8765 * (which is usually the most recent user input):
8766 *
8767 * f = File.open('t.tmp', 'w+')
8768 * gets # Sets $_ to the most recent user input.
8769 * f.print
8770 * f.close
8771 *
8772 */
8773
8774VALUE
8775rb_io_print(int argc, const VALUE *argv, VALUE out)
8776{
8777 int i;
8778 VALUE line;
8779
8780 /* if no argument given, print `$_' */
8781 if (argc == 0) {
8782 argc = 1;
8783 line = rb_lastline_get();
8784 argv = &line;
8785 }
8786 if (argc > 1 && !NIL_P(rb_output_fs)) {
8787 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8788 }
8789 for (i=0; i<argc; i++) {
8790 if (!NIL_P(rb_output_fs) && i>0) {
8791 rb_io_write(out, rb_output_fs);
8792 }
8793 rb_io_write(out, argv[i]);
8794 }
8795 if (argc > 0 && !NIL_P(rb_output_rs)) {
8796 rb_io_write(out, rb_output_rs);
8797 }
8798
8799 return Qnil;
8800}
8801
8802/*
8803 * call-seq:
8804 * print(*objects) -> nil
8805 *
8806 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8807 * this method is the straightforward way to write to <tt>$stdout</tt>.
8808 *
8809 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8810 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8811 * (<tt>$\</tt>), if it is not +nil+.
8812 *
8813 * With argument +objects+ given, for each object:
8814 *
8815 * - Converts via its method +to_s+ if not a string.
8816 * - Writes to <tt>stdout</tt>.
8817 * - If not the last object, writes the output field separator
8818 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8819 *
8820 * With default separators:
8821 *
8822 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8823 * $OUTPUT_RECORD_SEPARATOR
8824 * $OUTPUT_FIELD_SEPARATOR
8825 * print(*objects)
8826 *
8827 * Output:
8828 *
8829 * nil
8830 * nil
8831 * 00.00/10+0izerozero
8832 *
8833 * With specified separators:
8834 *
8835 * $OUTPUT_RECORD_SEPARATOR = "\n"
8836 * $OUTPUT_FIELD_SEPARATOR = ','
8837 * print(*objects)
8838 *
8839 * Output:
8840 *
8841 * 0,0.0,0/1,0+0i,zero,zero
8842 *
8843 * With no argument given, writes the content of <tt>$_</tt>
8844 * (which is usually the most recent user input):
8845 *
8846 * gets # Sets $_ to the most recent user input.
8847 * print # Prints $_.
8848 *
8849 */
8850
8851static VALUE
8852rb_f_print(int argc, const VALUE *argv, VALUE _)
8853{
8854 rb_io_print(argc, argv, rb_ractor_stdout());
8855 return Qnil;
8856}
8857
8858/*
8859 * call-seq:
8860 * putc(object) -> object
8861 *
8862 * Writes a character to the stream.
8863 * See {Character IO}[rdoc-ref:IO@Character+IO].
8864 *
8865 * If +object+ is numeric, converts to integer if necessary,
8866 * then writes the character whose code is the
8867 * least significant byte;
8868 * if +object+ is a string, writes the first character:
8869 *
8870 * $stdout.putc "A"
8871 * $stdout.putc 65
8872 *
8873 * Output:
8874 *
8875 * AA
8876 *
8877 */
8878
8879static VALUE
8880rb_io_putc(VALUE io, VALUE ch)
8881{
8882 VALUE str;
8883 if (RB_TYPE_P(ch, T_STRING)) {
8884 str = rb_str_substr(ch, 0, 1);
8885 }
8886 else {
8887 char c = NUM2CHR(ch);
8888 str = rb_str_new(&c, 1);
8889 }
8890 rb_io_write(io, str);
8891 return ch;
8892}
8893
8894#define forward(obj, id, argc, argv) \
8895 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8896#define forward_public(obj, id, argc, argv) \
8897 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8898#define forward_current(id, argc, argv) \
8899 forward_public(ARGF.current_file, id, argc, argv)
8900
8901/*
8902 * call-seq:
8903 * putc(int) -> int
8904 *
8905 * Equivalent to:
8906 *
8907 * $stdout.putc(int)
8908 *
8909 * See IO#putc for important information regarding multi-byte characters.
8910 *
8911 */
8912
8913static VALUE
8914rb_f_putc(VALUE recv, VALUE ch)
8915{
8916 VALUE r_stdout = rb_ractor_stdout();
8917 if (recv == r_stdout) {
8918 return rb_io_putc(recv, ch);
8919 }
8920 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8921}
8922
8923
8924int
8925rb_str_end_with_asciichar(VALUE str, int c)
8926{
8927 long len = RSTRING_LEN(str);
8928 const char *ptr = RSTRING_PTR(str);
8929 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8930 int n;
8931
8932 if (len == 0) return 0;
8933 if ((n = rb_enc_mbminlen(enc)) == 1) {
8934 return ptr[len - 1] == c;
8935 }
8936 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8937}
8938
8939static VALUE
8940io_puts_ary(VALUE ary, VALUE out, int recur)
8941{
8942 VALUE tmp;
8943 long i;
8944
8945 if (recur) {
8946 tmp = rb_str_new2("[...]");
8947 rb_io_puts(1, &tmp, out);
8948 return Qtrue;
8949 }
8950 ary = rb_check_array_type(ary);
8951 if (NIL_P(ary)) return Qfalse;
8952 for (i=0; i<RARRAY_LEN(ary); i++) {
8953 tmp = RARRAY_AREF(ary, i);
8954 rb_io_puts(1, &tmp, out);
8955 }
8956 return Qtrue;
8957}
8958
8959/*
8960 * call-seq:
8961 * puts(*objects) -> nil
8962 *
8963 * Writes the given +objects+ to the stream, which must be open for writing;
8964 * returns +nil+.\
8965 * Writes a newline after each that does not already end with a newline sequence.
8966 * If called without arguments, writes a newline.
8967 * See {Line IO}[rdoc-ref:IO@Line+IO].
8968 *
8969 * Note that each added newline is the character <tt>"\n"</tt>,
8970 * not the output record separator (<tt>$\</tt>).
8971 *
8972 * Treatment for each object:
8973 *
8974 * - String: writes the string.
8975 * - Neither string nor array: writes <tt>object.to_s</tt>.
8976 * - Array: writes each element of the array; arrays may be nested.
8977 *
8978 * To keep these examples brief, we define this helper method:
8979 *
8980 * def show(*objects)
8981 * # Puts objects to file.
8982 * f = File.new('t.tmp', 'w+')
8983 * f.puts(objects)
8984 * # Return file content.
8985 * f.rewind
8986 * p f.read
8987 * f.close
8988 * end
8989 *
8990 * # Strings without newlines.
8991 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8992 * # Strings, some with newlines.
8993 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8994 *
8995 * # Neither strings nor arrays:
8996 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8997 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8998 *
8999 * # Array of strings.
9000 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
9001 * # Nested arrays.
9002 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
9003 *
9004 */
9005
9006VALUE
9007rb_io_puts(int argc, const VALUE *argv, VALUE out)
9008{
9009 VALUE line, args[2];
9010
9011 /* if no argument given, print newline. */
9012 if (argc == 0) {
9013 rb_io_write(out, rb_default_rs);
9014 return Qnil;
9015 }
9016 for (int i = 0; i < argc; i++) {
9017 // Convert the argument to a string:
9018 if (RB_TYPE_P(argv[i], T_STRING)) {
9019 line = argv[i];
9020 }
9021 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9022 continue;
9023 }
9024 else {
9025 line = rb_obj_as_string(argv[i]);
9026 }
9027
9028 // Write the line:
9029 int n = 0;
9030 if (RSTRING_LEN(line) == 0) {
9031 args[n++] = rb_default_rs;
9032 }
9033 else {
9034 args[n++] = line;
9035 if (!rb_str_end_with_asciichar(line, '\n')) {
9036 args[n++] = rb_default_rs;
9037 }
9038 }
9039
9040 rb_io_writev(out, n, args);
9041 }
9042
9043 return Qnil;
9044}
9045
9046/*
9047 * call-seq:
9048 * puts(*objects) -> nil
9049 *
9050 * Equivalent to
9051 *
9052 * $stdout.puts(objects)
9053 */
9054
9055static VALUE
9056rb_f_puts(int argc, VALUE *argv, VALUE recv)
9057{
9058 VALUE r_stdout = rb_ractor_stdout();
9059 if (recv == r_stdout) {
9060 return rb_io_puts(argc, argv, recv);
9061 }
9062 return forward(r_stdout, rb_intern("puts"), argc, argv);
9063}
9064
9065static VALUE
9066rb_p_write(VALUE str)
9067{
9068 VALUE args[2];
9069 args[0] = str;
9070 args[1] = rb_default_rs;
9071 VALUE r_stdout = rb_ractor_stdout();
9072 if (RB_TYPE_P(r_stdout, T_FILE) &&
9073 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9074 io_writev(2, args, r_stdout);
9075 }
9076 else {
9077 rb_io_writev(r_stdout, 2, args);
9078 }
9079 return Qnil;
9080}
9081
9082void
9083rb_p(VALUE obj) /* for debug print within C code */
9084{
9085 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9086}
9087
9088static VALUE
9089rb_p_result(int argc, const VALUE *argv)
9090{
9091 VALUE ret = Qnil;
9092
9093 if (argc == 1) {
9094 ret = argv[0];
9095 }
9096 else if (argc > 1) {
9097 ret = rb_ary_new4(argc, argv);
9098 }
9099 VALUE r_stdout = rb_ractor_stdout();
9100 if (RB_TYPE_P(r_stdout, T_FILE)) {
9101 rb_uninterruptible(rb_io_flush, r_stdout);
9102 }
9103 return ret;
9104}
9105
9106/*
9107 * call-seq:
9108 * p(object) -> obj
9109 * p(*objects) -> array of objects
9110 * p -> nil
9111 *
9112 * For each object +obj+, executes:
9113 *
9114 * $stdout.write(obj.inspect, "\n")
9115 *
9116 * With one object given, returns the object;
9117 * with multiple objects given, returns an array containing the objects;
9118 * with no object given, returns +nil+.
9119 *
9120 * Examples:
9121 *
9122 * r = Range.new(0, 4)
9123 * p r # => 0..4
9124 * p [r, r, r] # => [0..4, 0..4, 0..4]
9125 * p # => nil
9126 *
9127 * Output:
9128 *
9129 * 0..4
9130 * [0..4, 0..4, 0..4]
9131 *
9132 * Kernel#p is designed for debugging purposes.
9133 * Ruby implementations may define Kernel#p to be uninterruptible
9134 * in whole or in part.
9135 * On CRuby, Kernel#p's writing of data is uninterruptible.
9136 */
9137
9138static VALUE
9139rb_f_p(int argc, VALUE *argv, VALUE self)
9140{
9141 int i;
9142 for (i=0; i<argc; i++) {
9143 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9144 rb_uninterruptible(rb_p_write, inspected);
9145 }
9146 return rb_p_result(argc, argv);
9147}
9148
9149/*
9150 * call-seq:
9151 * display(port = $>) -> nil
9152 *
9153 * Writes +self+ on the given port:
9154 *
9155 * 1.display
9156 * "cat".display
9157 * [ 4, 5, 6 ].display
9158 * puts
9159 *
9160 * Output:
9161 *
9162 * 1cat[4, 5, 6]
9163 *
9164 */
9165
9166static VALUE
9167rb_obj_display(int argc, VALUE *argv, VALUE self)
9168{
9169 VALUE out;
9170
9171 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9172 rb_io_write(out, self);
9173
9174 return Qnil;
9175}
9176
9177static int
9178rb_stderr_to_original_p(VALUE err)
9179{
9180 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9181}
9182
9183void
9184rb_write_error2(const char *mesg, long len)
9185{
9186 VALUE out = rb_ractor_stderr();
9187 if (rb_stderr_to_original_p(out)) {
9188#ifdef _WIN32
9189 if (isatty(fileno(stderr))) {
9190 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9191 }
9192#endif
9193 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9194 /* failed to write to stderr, what can we do? */
9195 return;
9196 }
9197 }
9198 else {
9199 rb_io_write(out, rb_str_new(mesg, len));
9200 }
9201}
9202
9203void
9204rb_write_error(const char *mesg)
9205{
9206 rb_write_error2(mesg, strlen(mesg));
9207}
9208
9209void
9210rb_write_error_str(VALUE mesg)
9211{
9212 VALUE out = rb_ractor_stderr();
9213 /* a stopgap measure for the time being */
9214 if (rb_stderr_to_original_p(out)) {
9215 size_t len = (size_t)RSTRING_LEN(mesg);
9216#ifdef _WIN32
9217 if (isatty(fileno(stderr))) {
9218 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9219 }
9220#endif
9221 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9222 RB_GC_GUARD(mesg);
9223 return;
9224 }
9225 }
9226 else {
9227 /* may unlock GVL, and */
9228 rb_io_write(out, mesg);
9229 }
9230}
9231
9232int
9233rb_stderr_tty_p(void)
9234{
9235 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9236 return isatty(fileno(stderr));
9237 return 0;
9238}
9239
9240static void
9241must_respond_to(ID mid, VALUE val, ID id)
9242{
9243 if (!rb_respond_to(val, mid)) {
9244 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9245 rb_id2str(id), rb_id2str(mid),
9246 rb_obj_class(val));
9247 }
9248}
9249
9250static void
9251stdin_setter(VALUE val, ID id, VALUE *ptr)
9252{
9254}
9255
9256static VALUE
9257stdin_getter(ID id, VALUE *ptr)
9258{
9259 return rb_ractor_stdin();
9260}
9261
9262static void
9263stdout_setter(VALUE val, ID id, VALUE *ptr)
9264{
9265 must_respond_to(id_write, val, id);
9267}
9268
9269static VALUE
9270stdout_getter(ID id, VALUE *ptr)
9271{
9272 return rb_ractor_stdout();
9273}
9274
9275static void
9276stderr_setter(VALUE val, ID id, VALUE *ptr)
9277{
9278 must_respond_to(id_write, val, id);
9280}
9281
9282static VALUE
9283stderr_getter(ID id, VALUE *ptr)
9284{
9285 return rb_ractor_stderr();
9286}
9287
9288static VALUE
9289allocate_and_open_new_file(VALUE klass)
9290{
9291 VALUE self = io_alloc(klass);
9292 rb_io_make_open_file(self);
9293 return self;
9294}
9295
9296VALUE
9297rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9298{
9299 int state;
9300 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9301 if (state) {
9302 /* if we raised an exception allocating an IO object, but the caller
9303 intended to transfer ownership of this FD to us, close the fd before
9304 raising the exception. Otherwise, we would leak a FD - the caller
9305 expects GC to close the file, but we never got around to assigning
9306 it to a rb_io. */
9307 if (!(mode & FMODE_EXTERNAL)) {
9308 maygvl_close(descriptor, 0);
9309 }
9310 rb_jump_tag(state);
9311 }
9312
9313
9314 rb_io_t *io = RFILE(self)->fptr;
9315 io->self = self;
9316 io->fd = descriptor;
9317 io->mode = mode;
9318
9319 /* At this point, Ruby fully owns the descriptor, and will close it when
9320 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9321 in the rest of this method. */
9322
9323 if (NIL_P(path)) {
9324 io->pathv = Qnil;
9325 }
9326 else {
9327 StringValue(path);
9328 io->pathv = rb_str_new_frozen(path);
9329 }
9330
9331 io->timeout = timeout;
9332
9333 ccan_list_head_init(&io->blocking_operations);
9334 io->closing_ec = NULL;
9335 io->wakeup_mutex = Qnil;
9336 io->fork_generation = GET_VM()->fork_gen;
9337
9338 if (encoding) {
9339 io->encs = *encoding;
9340 }
9341
9342 rb_update_max_fd(descriptor);
9343
9344 return self;
9345}
9346
9347static VALUE
9348prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9349{
9350 VALUE path_value = Qnil;
9351 rb_encoding *e;
9352 struct rb_io_encoding convconfig;
9353
9354 if (path) {
9355 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9356 }
9357
9358 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9359 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9360 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9363#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9364 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9365 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9366 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9367#endif
9368 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9369 convconfig.ecopts = Qnil;
9370
9371 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9372 rb_io_t*io = RFILE(self)->fptr;
9373
9374 if (!io_check_tty(io)) {
9375#ifdef __CYGWIN__
9376 io->mode |= FMODE_BINMODE;
9377 setmode(fd, O_BINARY);
9378#endif
9379 }
9380
9381 return self;
9382}
9383
9384VALUE
9385rb_io_fdopen(int fd, int oflags, const char *path)
9386{
9387 VALUE klass = rb_cIO;
9388
9389 if (path && strcmp(path, "-")) klass = rb_cFile;
9390 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9391}
9392
9393static VALUE
9394prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9395{
9396 rb_io_t *fptr;
9397 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9398
9399 GetOpenFile(io, fptr);
9401#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9402 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9403 if (fmode & FMODE_READABLE) {
9405 }
9406#endif
9407 fptr->stdio_file = f;
9408
9409 return io;
9410}
9411
9412VALUE
9413rb_io_prep_stdin(void)
9414{
9415 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9416}
9417
9418VALUE
9419rb_io_prep_stdout(void)
9420{
9421 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9422}
9423
9424VALUE
9425rb_io_prep_stderr(void)
9426{
9427 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9428}
9429
9430FILE *
9432{
9433 if (!fptr->stdio_file) {
9434 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9435 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9436 }
9437 return fptr->stdio_file;
9438}
9439
9440static inline void
9441rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9442{
9443 buf->ptr = NULL;
9444 buf->off = 0;
9445 buf->len = 0;
9446 buf->capa = 0;
9447}
9448
9449static inline rb_io_t *
9450rb_io_fptr_new(void)
9451{
9452 rb_io_t *fp = ALLOC(rb_io_t);
9453 fp->self = Qnil;
9454 fp->fd = -1;
9455 fp->stdio_file = NULL;
9456 fp->mode = 0;
9457 fp->pid = 0;
9458 fp->lineno = 0;
9459 fp->pathv = Qnil;
9460 fp->finalize = 0;
9461 rb_io_buffer_init(&fp->wbuf);
9462 rb_io_buffer_init(&fp->rbuf);
9463 rb_io_buffer_init(&fp->cbuf);
9464 fp->readconv = NULL;
9465 fp->writeconv = NULL;
9467 fp->writeconv_pre_ecflags = 0;
9469 fp->writeconv_initialized = 0;
9470 fp->tied_io_for_writing = 0;
9471 fp->encs.enc = NULL;
9472 fp->encs.enc2 = NULL;
9473 fp->encs.ecflags = 0;
9474 fp->encs.ecopts = Qnil;
9475 fp->write_lock = Qnil;
9476 fp->timeout = Qnil;
9477 ccan_list_head_init(&fp->blocking_operations);
9478 fp->closing_ec = NULL;
9479 fp->wakeup_mutex = Qnil;
9480 fp->fork_generation = GET_VM()->fork_gen;
9481 return fp;
9482}
9483
9484rb_io_t *
9485rb_io_make_open_file(VALUE obj)
9486{
9487 rb_io_t *fp = 0;
9488
9489 Check_Type(obj, T_FILE);
9490 if (RFILE(obj)->fptr) {
9491 rb_io_close(obj);
9492 rb_io_fptr_finalize(RFILE(obj)->fptr);
9493 RFILE(obj)->fptr = 0;
9494 }
9495 fp = rb_io_fptr_new();
9496 fp->self = obj;
9497 RFILE(obj)->fptr = fp;
9498 return fp;
9499}
9500
9501static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9502
9503/*
9504 * call-seq:
9505 * IO.new(fd, mode = 'r', **opts) -> io
9506 *
9507 * Creates and returns a new \IO object (file stream) from a file descriptor.
9508 *
9509 * \IO.new may be useful for interaction with low-level libraries.
9510 * For higher-level interactions, it may be simpler to create
9511 * the file stream using File.open.
9512 *
9513 * Argument +fd+ must be a valid file descriptor (integer):
9514 *
9515 * path = 't.tmp'
9516 * fd = IO.sysopen(path) # => 3
9517 * IO.new(fd) # => #<IO:fd 3>
9518 *
9519 * The new \IO object does not inherit encoding
9520 * (because the integer file descriptor does not have an encoding):
9521 *
9522 * File.read('t.ja') # => "こんにちは"
9523 * fd = IO.sysopen('t.ja', 'rb')
9524 * io = IO.new(fd)
9525 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9526 *
9527 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9528 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9529 *
9530 * IO.new(fd, 'w') # => #<IO:fd 3>
9531 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9532 *
9533 * Optional keyword arguments +opts+ specify:
9534 *
9535 * - {Open Options}[rdoc-ref:IO@Open+Options].
9536 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9537 *
9538 * Examples:
9539 *
9540 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9541 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9542 *
9543 */
9544
9545static VALUE
9546rb_io_initialize(int argc, VALUE *argv, VALUE io)
9547{
9548 VALUE fnum, vmode;
9549 VALUE opt;
9550
9551 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9552 return io_initialize(io, fnum, vmode, opt);
9553}
9554
9555static VALUE
9556io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9557{
9558 rb_io_t *fp;
9559 int fd, oflags = O_RDONLY;
9560 enum rb_io_mode fmode;
9561 struct rb_io_encoding convconfig;
9562#if defined(HAVE_FCNTL) && defined(F_GETFL)
9563 int ofmode;
9564#else
9565 struct stat st;
9566#endif
9567
9568 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9569
9570 fd = NUM2INT(fnum);
9571 if (rb_reserved_fd_p(fd)) {
9572 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9573 }
9574#if defined(HAVE_FCNTL) && defined(F_GETFL)
9575 oflags = fcntl(fd, F_GETFL);
9576 if (oflags == -1) rb_sys_fail(0);
9577#else
9578 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9579#endif
9580 rb_update_max_fd(fd);
9581#if defined(HAVE_FCNTL) && defined(F_GETFL)
9582 ofmode = rb_io_oflags_fmode(oflags);
9583 if (NIL_P(vmode)) {
9584 fmode = ofmode;
9585 }
9586 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9587 VALUE error = INT2FIX(EINVAL);
9589 }
9590#endif
9591 VALUE path = Qnil;
9592
9593 if (!NIL_P(opt)) {
9594 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9595 fmode |= FMODE_EXTERNAL;
9596 }
9597
9598 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9599 if (!NIL_P(path)) {
9600 StringValue(path);
9601 path = rb_str_new_frozen(path);
9602 }
9603 }
9604
9605 MakeOpenFile(io, fp);
9606 fp->self = io;
9607 fp->fd = fd;
9608 fp->mode = fmode;
9609 fp->encs = convconfig;
9610 fp->pathv = path;
9611 fp->timeout = Qnil;
9612 ccan_list_head_init(&fp->blocking_operations);
9613 fp->closing_ec = NULL;
9614 fp->wakeup_mutex = Qnil;
9615 fp->fork_generation = GET_VM()->fork_gen;
9616 clear_codeconv(fp);
9617 io_check_tty(fp);
9618 if (fileno(stdin) == fd)
9619 fp->stdio_file = stdin;
9620 else if (fileno(stdout) == fd)
9621 fp->stdio_file = stdout;
9622 else if (fileno(stderr) == fd)
9623 fp->stdio_file = stderr;
9624
9625 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9626 return io;
9627}
9628
9629/*
9630 * call-seq:
9631 * set_encoding_by_bom -> encoding or nil
9632 *
9633 * If the stream begins with a BOM
9634 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9635 * consumes the BOM and sets the external encoding accordingly;
9636 * returns the result encoding if found, or +nil+ otherwise:
9637 *
9638 * File.write('t.tmp', "\u{FEFF}abc")
9639 * io = File.open('t.tmp', 'rb')
9640 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9641 * io.close
9642 *
9643 * File.write('t.tmp', 'abc')
9644 * io = File.open('t.tmp', 'rb')
9645 * io.set_encoding_by_bom # => nil
9646 * io.close
9647 *
9648 * Raises an exception if the stream is not binmode
9649 * or its encoding has already been set.
9650 *
9651 */
9652
9653static VALUE
9654rb_io_set_encoding_by_bom(VALUE io)
9655{
9656 rb_io_t *fptr;
9657
9658 GetOpenFile(io, fptr);
9659 if (!(fptr->mode & FMODE_BINMODE)) {
9660 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9661 }
9662 if (fptr->encs.enc2) {
9663 rb_raise(rb_eArgError, "encoding conversion is set");
9664 }
9665 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9666 rb_raise(rb_eArgError, "encoding is set to %s already",
9667 rb_enc_name(fptr->encs.enc));
9668 }
9669 if (!io_set_encoding_by_bom(io)) return Qnil;
9670 return rb_enc_from_encoding(fptr->encs.enc);
9671}
9672
9673/*
9674 * call-seq:
9675 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9676 *
9677 * Opens the file at the given +path+ according to the given +mode+;
9678 * creates and returns a new File object for that file.
9679 *
9680 * The new File object is buffered mode (or non-sync mode), unless
9681 * +filename+ is a tty.
9682 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9683 *
9684 * Argument +path+ must be a valid file path:
9685 *
9686 * f = File.new('/etc/fstab')
9687 * f.close
9688 * f = File.new('t.txt')
9689 * f.close
9690 *
9691 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9692 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9693 *
9694 * f = File.new('t.tmp', 'w')
9695 * f.close
9696 * f = File.new('t.tmp', File::RDONLY)
9697 * f.close
9698 *
9699 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9700 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9701 *
9702 * f = File.new('t.tmp', File::CREAT, 0644)
9703 * f.close
9704 * f = File.new('t.tmp', File::CREAT, 0444)
9705 * f.close
9706 *
9707 * Optional keyword arguments +opts+ specify:
9708 *
9709 * - {Open Options}[rdoc-ref:IO@Open+Options].
9710 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9711 *
9712 */
9713
9714static VALUE
9715rb_file_initialize(int argc, VALUE *argv, VALUE io)
9716{
9717 if (RFILE(io)->fptr) {
9718 rb_raise(rb_eRuntimeError, "reinitializing File");
9719 }
9720 VALUE fname, vmode, vperm, opt;
9721 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9722 if (posargc < 3) { /* perm is File only */
9723 VALUE fd = rb_check_to_int(fname);
9724
9725 if (!NIL_P(fd)) {
9726 return io_initialize(io, fd, vmode, opt);
9727 }
9728 }
9729 return rb_open_file(io, fname, vmode, vperm, opt);
9730}
9731
9732/* :nodoc: */
9733static VALUE
9734rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9735{
9736 if (rb_block_given_p()) {
9737 VALUE cname = rb_obj_as_string(klass);
9738
9739 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9740 cname, cname);
9741 }
9742 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9743}
9744
9745
9746/*
9747 * call-seq:
9748 * IO.for_fd(fd, mode = 'r', **opts) -> io
9749 *
9750 * Synonym for IO.new.
9751 *
9752 */
9753
9754static VALUE
9755rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9756{
9757 VALUE io = rb_obj_alloc(klass);
9758 rb_io_initialize(argc, argv, io);
9759 return io;
9760}
9761
9762/*
9763 * call-seq:
9764 * ios.autoclose? -> true or false
9765 *
9766 * Returns +true+ if the underlying file descriptor of _ios_ will be
9767 * closed at its finalization or at calling #close, otherwise +false+.
9768 */
9769
9770static VALUE
9771rb_io_autoclose_p(VALUE io)
9772{
9773 rb_io_t *fptr = RFILE(io)->fptr;
9774 rb_io_check_closed(fptr);
9775 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9776}
9777
9778/*
9779 * call-seq:
9780 * io.autoclose = bool -> true or false
9781 *
9782 * Sets auto-close flag.
9783 *
9784 * f = File.open(File::NULL)
9785 * IO.for_fd(f.fileno).close
9786 * f.gets # raises Errno::EBADF
9787 *
9788 * f = File.open(File::NULL)
9789 * g = IO.for_fd(f.fileno)
9790 * g.autoclose = false
9791 * g.close
9792 * f.gets # won't cause Errno::EBADF
9793 */
9794
9795static VALUE
9796rb_io_set_autoclose(VALUE io, VALUE autoclose)
9797{
9798 rb_io_t *fptr;
9799 GetOpenFile(io, fptr);
9800 if (!RTEST(autoclose))
9801 fptr->mode |= FMODE_EXTERNAL;
9802 else
9803 fptr->mode &= ~FMODE_EXTERNAL;
9804 return autoclose;
9805}
9806
9807static VALUE
9808io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9809{
9810 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9811
9812 if (!RB_TEST(result)) {
9813 return Qnil;
9814 }
9815
9816 int mask = RB_NUM2INT(result);
9817
9818 if (mask & event) {
9819 if (return_io)
9820 return io;
9821 else
9822 return result;
9823 }
9824 else {
9825 return Qfalse;
9826 }
9827}
9828
9829/*
9830 * call-seq:
9831 * io.wait_readable -> truthy or falsy
9832 * io.wait_readable(timeout) -> truthy or falsy
9833 *
9834 * Waits until IO is readable and returns a truthy value, or a falsy
9835 * value when times out. Returns a truthy value immediately when
9836 * buffered data is available.
9837 */
9838
9839static VALUE
9840io_wait_readable(int argc, VALUE *argv, VALUE io)
9841{
9842 rb_io_t *fptr;
9843
9844 RB_IO_POINTER(io, fptr);
9846
9847 if (rb_io_read_pending(fptr)) return Qtrue;
9848
9849 rb_check_arity(argc, 0, 1);
9850 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9851
9852 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9853}
9854
9855/*
9856 * call-seq:
9857 * io.wait_writable -> truthy or falsy
9858 * io.wait_writable(timeout) -> truthy or falsy
9859 *
9860 * Waits until IO is writable and returns a truthy value or a falsy
9861 * value when times out.
9862 */
9863static VALUE
9864io_wait_writable(int argc, VALUE *argv, VALUE io)
9865{
9866 rb_io_t *fptr;
9867
9868 RB_IO_POINTER(io, fptr);
9870
9871 rb_check_arity(argc, 0, 1);
9872 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9873
9874 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9875}
9876
9877/*
9878 * call-seq:
9879 * io.wait_priority -> truthy or falsy
9880 * io.wait_priority(timeout) -> truthy or falsy
9881 *
9882 * Waits until IO is priority and returns a truthy value or a falsy
9883 * value when times out. Priority data is sent and received using
9884 * the Socket::MSG_OOB flag and is typically limited to streams.
9885 */
9886static VALUE
9887io_wait_priority(int argc, VALUE *argv, VALUE io)
9888{
9889 rb_io_t *fptr = NULL;
9890
9891 RB_IO_POINTER(io, fptr);
9893
9894 if (rb_io_read_pending(fptr)) return Qtrue;
9895
9896 rb_check_arity(argc, 0, 1);
9897 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9898
9899 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9900}
9901
9902static int
9903wait_mode_sym(VALUE mode)
9904{
9905 if (mode == ID2SYM(rb_intern("r"))) {
9906 return RB_WAITFD_IN;
9907 }
9908 if (mode == ID2SYM(rb_intern("read"))) {
9909 return RB_WAITFD_IN;
9910 }
9911 if (mode == ID2SYM(rb_intern("readable"))) {
9912 return RB_WAITFD_IN;
9913 }
9914 if (mode == ID2SYM(rb_intern("w"))) {
9915 return RB_WAITFD_OUT;
9916 }
9917 if (mode == ID2SYM(rb_intern("write"))) {
9918 return RB_WAITFD_OUT;
9919 }
9920 if (mode == ID2SYM(rb_intern("writable"))) {
9921 return RB_WAITFD_OUT;
9922 }
9923 if (mode == ID2SYM(rb_intern("rw"))) {
9924 return RB_WAITFD_IN|RB_WAITFD_OUT;
9925 }
9926 if (mode == ID2SYM(rb_intern("read_write"))) {
9927 return RB_WAITFD_IN|RB_WAITFD_OUT;
9928 }
9929 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9930 return RB_WAITFD_IN|RB_WAITFD_OUT;
9931 }
9932
9933 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9934}
9935
9936static inline enum rb_io_event
9937io_event_from_value(VALUE value)
9938{
9939 int events = RB_NUM2INT(value);
9940
9941 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9942
9943 return events;
9944}
9945
9946/*
9947 * call-seq:
9948 * io.wait(events, timeout) -> event mask, false or nil
9949 * io.wait(*event_symbols[, timeout]) -> self, true, or false
9950 *
9951 * Waits until the IO becomes ready for the specified events and returns the
9952 * subset of events that become ready, or a falsy value when times out.
9953 *
9954 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9955 * +IO::PRIORITY+.
9956 *
9957 * Returns an event mask (truthy value) immediately when buffered data is
9958 * available.
9959 *
9960 * The second form: if one or more event symbols (+:read+, +:write+, or
9961 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
9962 * corresponding to those symbols. In this form, +timeout+ is optional, the
9963 * order of the arguments is arbitrary, and returns +io+ if any of the
9964 * events is ready.
9965 */
9966
9967static VALUE
9968io_wait(int argc, VALUE *argv, VALUE io)
9969{
9970 VALUE timeout = Qundef;
9971 enum rb_io_event events = 0;
9972 int return_io = 0;
9973
9974 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9975 // We'd prefer to return the actual mask, but this form would return the io itself:
9976 return_io = 1;
9977
9978 // Slow/messy path:
9979 for (int i = 0; i < argc; i += 1) {
9980 if (RB_SYMBOL_P(argv[i])) {
9981 events |= wait_mode_sym(argv[i]);
9982 }
9983 else if (UNDEF_P(timeout)) {
9984 rb_time_interval(timeout = argv[i]);
9985 }
9986 else {
9987 rb_raise(rb_eArgError, "timeout given more than once");
9988 }
9989 }
9990
9991 if (UNDEF_P(timeout)) timeout = Qnil;
9992
9993 if (events == 0) {
9994 events = RUBY_IO_READABLE;
9995 }
9996 }
9997 else /* argc == 2 and neither are symbols */ {
9998 // This is the fast path:
9999 events = io_event_from_value(argv[0]);
10000 timeout = argv[1];
10001 }
10002
10003 if (events & RUBY_IO_READABLE) {
10004 rb_io_t *fptr = NULL;
10005 RB_IO_POINTER(io, fptr);
10006
10007 if (rb_io_read_pending(fptr)) {
10008 // This was the original behaviour:
10009 if (return_io) return Qtrue;
10010 // New behaviour always returns an event mask:
10011 else return RB_INT2NUM(RUBY_IO_READABLE);
10012 }
10013 }
10014
10015 return io_wait_event(io, events, timeout, return_io);
10016}
10017
10018static void
10019argf_mark_and_move(void *ptr)
10020{
10021 struct argf *p = ptr;
10022 rb_gc_mark_and_move(&p->filename);
10023 rb_gc_mark_and_move(&p->current_file);
10024 rb_gc_mark_and_move(&p->argv);
10025 rb_gc_mark_and_move(&p->inplace);
10026 rb_gc_mark_and_move(&p->encs.ecopts);
10027}
10028
10029static size_t
10030argf_memsize(const void *ptr)
10031{
10032 const struct argf *p = ptr;
10033 size_t size = sizeof(*p);
10034 return size;
10035}
10036
10037static const rb_data_type_t argf_type = {
10038 "ARGF",
10039 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10040 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10041};
10042
10043static inline void
10044argf_init(VALUE argf, struct argf *p, VALUE v)
10045{
10046 p->filename = Qnil;
10047 p->current_file = Qnil;
10048 p->lineno = 0;
10049 RB_OBJ_WRITE(argf, &p->argv, v);
10050}
10051
10052static VALUE
10053argf_alloc(VALUE klass)
10054{
10055 struct argf *p;
10056 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10057
10058 argf_init(argf, p, Qnil);
10059 return argf;
10060}
10061
10062#undef rb_argv
10063
10064/* :nodoc: */
10065static VALUE
10066argf_initialize(VALUE argf, VALUE argv)
10067{
10068 memset(&ARGF, 0, sizeof(ARGF));
10069 argf_init(argf, &ARGF, argv);
10070
10071 return argf;
10072}
10073
10074/* :nodoc: */
10075static VALUE
10076argf_initialize_copy(VALUE argf, VALUE orig)
10077{
10078 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10079 ARGF = argf_of(orig);
10080 rb_gc_writebarrier_remember(argf);
10081 ARGF_SET(argv, rb_obj_dup(ARGF.argv));
10082 return argf;
10083}
10084
10085/*
10086 * call-seq:
10087 * ARGF.lineno = integer -> integer
10088 *
10089 * Sets the line number of ARGF as a whole to the given Integer.
10090 *
10091 * ARGF sets the line number automatically as you read data, so normally
10092 * you will not need to set it explicitly. To access the current line number
10093 * use ARGF.lineno.
10094 *
10095 * For example:
10096 *
10097 * ARGF.lineno #=> 0
10098 * ARGF.readline #=> "This is line 1\n"
10099 * ARGF.lineno #=> 1
10100 * ARGF.lineno = 0 #=> 0
10101 * ARGF.lineno #=> 0
10102 */
10103static VALUE
10104argf_set_lineno(VALUE argf, VALUE val)
10105{
10106 ARGF.lineno = NUM2INT(val);
10107 ARGF.last_lineno = ARGF.lineno;
10108 return val;
10109}
10110
10111/*
10112 * call-seq:
10113 * ARGF.lineno -> integer
10114 *
10115 * Returns the current line number of ARGF as a whole. This value
10116 * can be set manually with ARGF.lineno=.
10117 *
10118 * For example:
10119 *
10120 * ARGF.lineno #=> 0
10121 * ARGF.readline #=> "This is line 1\n"
10122 * ARGF.lineno #=> 1
10123 */
10124static VALUE
10125argf_lineno(VALUE argf)
10126{
10127 return INT2FIX(ARGF.lineno);
10128}
10129
10130static VALUE
10131argf_forward(int argc, VALUE *argv, VALUE argf)
10132{
10133 return forward_current(rb_frame_this_func(), argc, argv);
10134}
10135
10136#define next_argv() argf_next_argv(argf)
10137#define ARGF_GENERIC_INPUT_P() \
10138 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10139#define ARGF_FORWARD(argc, argv) do {\
10140 if (ARGF_GENERIC_INPUT_P())\
10141 return argf_forward((argc), (argv), argf);\
10142} while (0)
10143#define NEXT_ARGF_FORWARD(argc, argv) do {\
10144 if (!next_argv()) return Qnil;\
10145 ARGF_FORWARD((argc), (argv));\
10146} while (0)
10147
10148static void
10149argf_close(VALUE argf)
10150{
10151 VALUE file = ARGF.current_file;
10152 if (file == rb_stdin) return;
10153 if (RB_TYPE_P(file, T_FILE)) {
10154 rb_io_set_write_io(file, Qnil);
10155 }
10156 io_close(file);
10157 ARGF.init_p = -1;
10158}
10159
10160static int
10161argf_next_argv(VALUE argf)
10162{
10163 char *fn;
10164 rb_io_t *fptr;
10165 int stdout_binmode = 0;
10166 enum rb_io_mode fmode;
10167
10168 VALUE r_stdout = rb_ractor_stdout();
10169
10170 if (RB_TYPE_P(r_stdout, T_FILE)) {
10171 GetOpenFile(r_stdout, fptr);
10172 if (fptr->mode & FMODE_BINMODE)
10173 stdout_binmode = 1;
10174 }
10175
10176 if (ARGF.init_p == 0) {
10177 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10178 ARGF.next_p = 1;
10179 }
10180 else {
10181 ARGF.next_p = -1;
10182 }
10183 ARGF.init_p = 1;
10184 }
10185 else {
10186 if (NIL_P(ARGF.argv)) {
10187 ARGF.next_p = -1;
10188 }
10189 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10190 ARGF.next_p = 1;
10191 }
10192 }
10193
10194 if (ARGF.next_p == 1) {
10195 if (ARGF.init_p == 1) argf_close(argf);
10196 retry:
10197 if (RARRAY_LEN(ARGF.argv) > 0) {
10198 VALUE filename = rb_ary_shift(ARGF.argv);
10199 FilePathValue(filename);
10200 ARGF_SET(filename, filename);
10201 filename = rb_str_encode_ospath(filename);
10202 fn = StringValueCStr(filename);
10203 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10204 ARGF_SET(current_file, rb_stdin);
10205 if (ARGF.inplace) {
10206 rb_warn("Can't do inplace edit for stdio; skipping");
10207 goto retry;
10208 }
10209 }
10210 else {
10211 VALUE write_io = Qnil;
10212 int fr = rb_sysopen(filename, O_RDONLY, 0);
10213
10214 if (ARGF.inplace) {
10215 struct stat st;
10216#ifndef NO_SAFE_RENAME
10217 struct stat st2;
10218#endif
10219 VALUE str;
10220 int fw;
10221
10222 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10223 rb_io_close(r_stdout);
10224 }
10225 fstat(fr, &st);
10226 str = filename;
10227 if (!NIL_P(ARGF.inplace)) {
10228 VALUE suffix = ARGF.inplace;
10229 str = rb_str_dup(str);
10230 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10231 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10232 rb_enc_get(suffix), 0, Qnil))) {
10233 rb_str_append(str, suffix);
10234 }
10235#ifdef NO_SAFE_RENAME
10236 (void)close(fr);
10237 (void)unlink(RSTRING_PTR(str));
10238 if (rename(fn, RSTRING_PTR(str)) < 0) {
10239 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10240 filename, str, strerror(errno));
10241 goto retry;
10242 }
10243 fr = rb_sysopen(str, O_RDONLY, 0);
10244#else
10245 if (rename(fn, RSTRING_PTR(str)) < 0) {
10246 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10247 filename, str, strerror(errno));
10248 close(fr);
10249 goto retry;
10250 }
10251#endif
10252 }
10253 else {
10254#ifdef NO_SAFE_RENAME
10255 rb_fatal("Can't do inplace edit without backup");
10256#else
10257 if (unlink(fn) < 0) {
10258 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10259 filename, strerror(errno));
10260 close(fr);
10261 goto retry;
10262 }
10263#endif
10264 }
10265 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10266#ifndef NO_SAFE_RENAME
10267 fstat(fw, &st2);
10268#ifdef HAVE_FCHMOD
10269 fchmod(fw, st.st_mode);
10270#else
10271 chmod(fn, st.st_mode);
10272#endif
10273 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10274 int err;
10275#ifdef HAVE_FCHOWN
10276 err = fchown(fw, st.st_uid, st.st_gid);
10277#else
10278 err = chown(fn, st.st_uid, st.st_gid);
10279#endif
10280 if (err && getuid() == 0 && st2.st_uid == 0) {
10281 const char *wkfn = RSTRING_PTR(filename);
10282 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10283 filename, str, strerror(errno));
10284 (void)close(fr);
10285 (void)close(fw);
10286 (void)unlink(wkfn);
10287 goto retry;
10288 }
10289 }
10290#endif
10291 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10292 rb_ractor_stdout_set(write_io);
10293 if (stdout_binmode) rb_io_binmode(rb_stdout);
10294 }
10295 fmode = FMODE_READABLE;
10296 if (!ARGF.binmode) {
10297 fmode |= DEFAULT_TEXTMODE;
10298 }
10299 ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
10300 if (!NIL_P(write_io)) {
10301 rb_io_set_write_io(ARGF.current_file, write_io);
10302 }
10303 RB_GC_GUARD(filename);
10304 }
10305 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10306 GetOpenFile(ARGF.current_file, fptr);
10307 if (ARGF.encs.enc) {
10308 fptr->encs = ARGF.encs;
10309 clear_codeconv(fptr);
10310 }
10311 else {
10312 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10313 if (!ARGF.binmode) {
10315#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10316 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10317#endif
10318 }
10319 }
10320 ARGF.next_p = 0;
10321 }
10322 else {
10323 ARGF.next_p = 1;
10324 return FALSE;
10325 }
10326 }
10327 else if (ARGF.next_p == -1) {
10328 ARGF_SET(current_file, rb_stdin);
10329 ARGF_SET(filename, rb_str_new2("-"));
10330 if (ARGF.inplace) {
10331 rb_warn("Can't do inplace edit for stdio");
10332 rb_ractor_stdout_set(orig_stdout);
10333 }
10334 }
10335 if (ARGF.init_p == -1) ARGF.init_p = 1;
10336 return TRUE;
10337}
10338
10339static VALUE
10340argf_getline(int argc, VALUE *argv, VALUE argf)
10341{
10342 VALUE line;
10343 long lineno = ARGF.lineno;
10344
10345 retry:
10346 if (!next_argv()) return Qnil;
10347 if (ARGF_GENERIC_INPUT_P()) {
10348 line = forward_current(idGets, argc, argv);
10349 }
10350 else {
10351 if (argc == 0 && rb_rs == rb_default_rs) {
10352 line = rb_io_gets(ARGF.current_file);
10353 }
10354 else {
10355 line = rb_io_getline(argc, argv, ARGF.current_file);
10356 }
10357 if (NIL_P(line) && ARGF.next_p != -1) {
10358 argf_close(argf);
10359 ARGF.next_p = 1;
10360 goto retry;
10361 }
10362 }
10363 if (!NIL_P(line)) {
10364 ARGF.lineno = ++lineno;
10365 ARGF.last_lineno = ARGF.lineno;
10366 }
10367 return line;
10368}
10369
10370static VALUE
10371argf_lineno_getter(ID id, VALUE *var)
10372{
10373 VALUE argf = *var;
10374 return INT2FIX(ARGF.last_lineno);
10375}
10376
10377static void
10378argf_lineno_setter(VALUE val, ID id, VALUE *var)
10379{
10380 VALUE argf = *var;
10381 int n = NUM2INT(val);
10382 ARGF.last_lineno = ARGF.lineno = n;
10383}
10384
10385void
10386rb_reset_argf_lineno(long n)
10387{
10388 ARGF.last_lineno = ARGF.lineno = n;
10389}
10390
10391static VALUE argf_gets(int, VALUE *, VALUE);
10392
10393/*
10394 * call-seq:
10395 * gets(sep=$/ [, getline_args]) -> string or nil
10396 * gets(limit [, getline_args]) -> string or nil
10397 * gets(sep, limit [, getline_args]) -> string or nil
10398 *
10399 * Returns (and assigns to <code>$_</code>) the next line from the list
10400 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10401 * no files are present on the command line. Returns +nil+ at end of
10402 * file. The optional argument specifies the record separator. The
10403 * separator is included with the contents of each record. A separator
10404 * of +nil+ reads the entire contents, and a zero-length separator
10405 * reads the input one paragraph at a time, where paragraphs are
10406 * divided by two consecutive newlines. If the first argument is an
10407 * integer, or optional second argument is given, the returning string
10408 * would not be longer than the given value in bytes. If multiple
10409 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10410 * the contents one file at a time.
10411 *
10412 * ARGV << "testfile"
10413 * print while gets
10414 *
10415 * <em>produces:</em>
10416 *
10417 * This is line one
10418 * This is line two
10419 * This is line three
10420 * And so on...
10421 *
10422 * The style of programming using <code>$_</code> as an implicit
10423 * parameter is gradually losing favor in the Ruby community.
10424 */
10425
10426static VALUE
10427rb_f_gets(int argc, VALUE *argv, VALUE recv)
10428{
10429 if (recv == argf) {
10430 return argf_gets(argc, argv, argf);
10431 }
10432 return forward(argf, idGets, argc, argv);
10433}
10434
10435/*
10436 * call-seq:
10437 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10438 * ARGF.gets(limit [, getline_args]) -> string or nil
10439 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10440 *
10441 * Returns the next line from the current file in ARGF.
10442 *
10443 * By default lines are assumed to be separated by <code>$/</code>;
10444 * to use a different character as a separator, supply it as a String
10445 * for the _sep_ argument.
10446 *
10447 * The optional _limit_ argument specifies how many characters of each line
10448 * to return. By default all characters are returned.
10449 *
10450 * See IO.readlines for details about getline_args.
10451 *
10452 */
10453static VALUE
10454argf_gets(int argc, VALUE *argv, VALUE argf)
10455{
10456 VALUE line;
10457
10458 line = argf_getline(argc, argv, argf);
10459 rb_lastline_set(line);
10460
10461 return line;
10462}
10463
10464VALUE
10466{
10467 VALUE line;
10468
10469 if (rb_rs != rb_default_rs) {
10470 return rb_f_gets(0, 0, argf);
10471 }
10472
10473 retry:
10474 if (!next_argv()) return Qnil;
10475 line = rb_io_gets(ARGF.current_file);
10476 if (NIL_P(line) && ARGF.next_p != -1) {
10477 rb_io_close(ARGF.current_file);
10478 ARGF.next_p = 1;
10479 goto retry;
10480 }
10481 rb_lastline_set(line);
10482 if (!NIL_P(line)) {
10483 ARGF.lineno++;
10484 ARGF.last_lineno = ARGF.lineno;
10485 }
10486
10487 return line;
10488}
10489
10490static VALUE argf_readline(int, VALUE *, VALUE);
10491
10492/*
10493 * call-seq:
10494 * readline(sep = $/, chomp: false) -> string
10495 * readline(limit, chomp: false) -> string
10496 * readline(sep, limit, chomp: false) -> string
10497 *
10498 * Equivalent to method Kernel#gets, except that it raises an exception
10499 * if called at end-of-stream:
10500 *
10501 * $ cat t.txt | ruby -e "p readlines; readline"
10502 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10503 * in `readline': end of file reached (EOFError)
10504 *
10505 * Optional keyword argument +chomp+ specifies whether line separators
10506 * are to be omitted.
10507 */
10508
10509static VALUE
10510rb_f_readline(int argc, VALUE *argv, VALUE recv)
10511{
10512 if (recv == argf) {
10513 return argf_readline(argc, argv, argf);
10514 }
10515 return forward(argf, rb_intern("readline"), argc, argv);
10516}
10517
10518
10519/*
10520 * call-seq:
10521 * ARGF.readline(sep=$/) -> string
10522 * ARGF.readline(limit) -> string
10523 * ARGF.readline(sep, limit) -> string
10524 *
10525 * Returns the next line from the current file in ARGF.
10526 *
10527 * By default lines are assumed to be separated by <code>$/</code>;
10528 * to use a different character as a separator, supply it as a String
10529 * for the _sep_ argument.
10530 *
10531 * The optional _limit_ argument specifies how many characters of each line
10532 * to return. By default all characters are returned.
10533 *
10534 * An EOFError is raised at the end of the file.
10535 */
10536static VALUE
10537argf_readline(int argc, VALUE *argv, VALUE argf)
10538{
10539 VALUE line;
10540
10541 if (!next_argv()) rb_eof_error();
10542 ARGF_FORWARD(argc, argv);
10543 line = argf_gets(argc, argv, argf);
10544 if (NIL_P(line)) {
10545 rb_eof_error();
10546 }
10547
10548 return line;
10549}
10550
10551static VALUE argf_readlines(int, VALUE *, VALUE);
10552
10553/*
10554 * call-seq:
10555 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10556 * readlines(limit, chomp: false, **enc_opts) -> array
10557 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10558 *
10559 * Returns an array containing the lines returned by calling
10560 * Kernel#gets until the end-of-stream is reached;
10561 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10562 *
10563 * With only string argument +sep+ given,
10564 * returns the remaining lines as determined by line separator +sep+,
10565 * or +nil+ if none;
10566 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10567 *
10568 * # Default separator.
10569 * $ cat t.txt | ruby -e "p readlines"
10570 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10571 *
10572 * # Specified separator.
10573 * $ cat t.txt | ruby -e "p readlines 'li'"
10574 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10575 *
10576 * # Get-all separator.
10577 * $ cat t.txt | ruby -e "p readlines nil"
10578 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10579 *
10580 * # Get-paragraph separator.
10581 * $ cat t.txt | ruby -e "p readlines ''"
10582 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10583 *
10584 * With only integer argument +limit+ given,
10585 * limits the number of bytes in the line;
10586 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10587 *
10588 * $cat t.txt | ruby -e "p readlines 10"
10589 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10590 *
10591 * $cat t.txt | ruby -e "p readlines 11"
10592 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10593 *
10594 * $cat t.txt | ruby -e "p readlines 12"
10595 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10596 *
10597 * With arguments +sep+ and +limit+ given,
10598 * combines the two behaviors
10599 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10600 *
10601 * Optional keyword argument +chomp+ specifies whether line separators
10602 * are to be omitted:
10603 *
10604 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10605 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10606 *
10607 * Optional keyword arguments +enc_opts+ specify encoding options;
10608 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10609 *
10610 */
10611
10612static VALUE
10613rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10614{
10615 if (recv == argf) {
10616 return argf_readlines(argc, argv, argf);
10617 }
10618 return forward(argf, rb_intern("readlines"), argc, argv);
10619}
10620
10621/*
10622 * call-seq:
10623 * ARGF.readlines(sep = $/, chomp: false) -> array
10624 * ARGF.readlines(limit, chomp: false) -> array
10625 * ARGF.readlines(sep, limit, chomp: false) -> array
10626 *
10627 * ARGF.to_a(sep = $/, chomp: false) -> array
10628 * ARGF.to_a(limit, chomp: false) -> array
10629 * ARGF.to_a(sep, limit, chomp: false) -> array
10630 *
10631 * Reads each file in ARGF in its entirety, returning an Array containing
10632 * lines from the files. Lines are assumed to be separated by _sep_.
10633 *
10634 * lines = ARGF.readlines
10635 * lines[0] #=> "This is line one\n"
10636 *
10637 * See +IO.readlines+ for a full description of all options.
10638 */
10639static VALUE
10640argf_readlines(int argc, VALUE *argv, VALUE argf)
10641{
10642 long lineno = ARGF.lineno;
10643 VALUE lines, ary;
10644
10645 ary = rb_ary_new();
10646 while (next_argv()) {
10647 if (ARGF_GENERIC_INPUT_P()) {
10648 lines = forward_current(rb_intern("readlines"), argc, argv);
10649 }
10650 else {
10651 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10652 argf_close(argf);
10653 }
10654 ARGF.next_p = 1;
10655 rb_ary_concat(ary, lines);
10656 ARGF.lineno = lineno + RARRAY_LEN(ary);
10657 ARGF.last_lineno = ARGF.lineno;
10658 }
10659 ARGF.init_p = 0;
10660 return ary;
10661}
10662
10663/*
10664 * call-seq:
10665 * `command` -> string
10666 *
10667 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10668 * sets global variable <tt>$?</tt> to the process status.
10669 *
10670 * This method has potential security vulnerabilities if called with untrusted input;
10671 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10672 *
10673 * Examples:
10674 *
10675 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10676 * $ `echo oops && exit 99` # => "oops\n"
10677 * $ $? # => #<Process::Status: pid 17088 exit 99>
10678 * $ $?.exitstatus # => 99
10679 *
10680 * The built-in syntax <tt>%x{...}</tt> uses this method.
10681 *
10682 */
10683
10684static VALUE
10685rb_f_backquote(VALUE obj, VALUE str)
10686{
10687 VALUE port;
10688 VALUE result;
10689 rb_io_t *fptr;
10690
10691 StringValue(str);
10692 rb_last_status_clear();
10693 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10694 if (NIL_P(port)) return rb_str_new(0,0);
10695
10696 GetOpenFile(port, fptr);
10697 result = read_all(fptr, remain_size(fptr), Qnil);
10698 rb_io_close(port);
10699 rb_io_fptr_cleanup_all(fptr);
10700 RB_GC_GUARD(port);
10701
10702 return result;
10703}
10704
10705#ifdef HAVE_SYS_SELECT_H
10706#include <sys/select.h>
10707#endif
10708
10709static VALUE
10710select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10711{
10712 VALUE res, list;
10713 rb_fdset_t *rp, *wp, *ep;
10714 rb_io_t *fptr;
10715 long i;
10716 int max = 0, n;
10717 int pending = 0;
10718 struct timeval timerec;
10719
10720 if (!NIL_P(read)) {
10721 Check_Type(read, T_ARRAY);
10722 for (i=0; i<RARRAY_LEN(read); i++) {
10723 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10724 rb_fd_set(fptr->fd, &fds[0]);
10725 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10726 pending++;
10727 rb_fd_set(fptr->fd, &fds[3]);
10728 }
10729 if (max < fptr->fd) max = fptr->fd;
10730 }
10731 if (pending) { /* no blocking if there's buffered data */
10732 timerec.tv_sec = timerec.tv_usec = 0;
10733 tp = &timerec;
10734 }
10735 rp = &fds[0];
10736 }
10737 else
10738 rp = 0;
10739
10740 if (!NIL_P(write)) {
10741 Check_Type(write, T_ARRAY);
10742 for (i=0; i<RARRAY_LEN(write); i++) {
10743 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10744 GetOpenFile(write_io, fptr);
10745 rb_fd_set(fptr->fd, &fds[1]);
10746 if (max < fptr->fd) max = fptr->fd;
10747 }
10748 wp = &fds[1];
10749 }
10750 else
10751 wp = 0;
10752
10753 if (!NIL_P(except)) {
10754 Check_Type(except, T_ARRAY);
10755 for (i=0; i<RARRAY_LEN(except); i++) {
10756 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10757 VALUE write_io = GetWriteIO(io);
10758 GetOpenFile(io, fptr);
10759 rb_fd_set(fptr->fd, &fds[2]);
10760 if (max < fptr->fd) max = fptr->fd;
10761 if (io != write_io) {
10762 GetOpenFile(write_io, fptr);
10763 rb_fd_set(fptr->fd, &fds[2]);
10764 if (max < fptr->fd) max = fptr->fd;
10765 }
10766 }
10767 ep = &fds[2];
10768 }
10769 else {
10770 ep = 0;
10771 }
10772
10773 max++;
10774
10775 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10776 if (n < 0) {
10777 rb_sys_fail(0);
10778 }
10779 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10780
10781 res = rb_ary_new2(3);
10782 rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
10783 rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
10784 rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
10785
10786 if (rp) {
10787 list = RARRAY_AREF(res, 0);
10788 for (i=0; i< RARRAY_LEN(read); i++) {
10789 VALUE obj = rb_ary_entry(read, i);
10790 VALUE io = rb_io_get_io(obj);
10791 GetOpenFile(io, fptr);
10792 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10793 rb_fd_isset(fptr->fd, &fds[3])) {
10794 rb_ary_push(list, obj);
10795 }
10796 }
10797 }
10798
10799 if (wp) {
10800 list = RARRAY_AREF(res, 1);
10801 for (i=0; i< RARRAY_LEN(write); i++) {
10802 VALUE obj = rb_ary_entry(write, i);
10803 VALUE io = rb_io_get_io(obj);
10804 VALUE write_io = GetWriteIO(io);
10805 GetOpenFile(write_io, fptr);
10806 if (rb_fd_isset(fptr->fd, &fds[1])) {
10807 rb_ary_push(list, obj);
10808 }
10809 }
10810 }
10811
10812 if (ep) {
10813 list = RARRAY_AREF(res, 2);
10814 for (i=0; i< RARRAY_LEN(except); i++) {
10815 VALUE obj = rb_ary_entry(except, i);
10816 VALUE io = rb_io_get_io(obj);
10817 VALUE write_io = GetWriteIO(io);
10818 GetOpenFile(io, fptr);
10819 if (rb_fd_isset(fptr->fd, &fds[2])) {
10820 rb_ary_push(list, obj);
10821 }
10822 else if (io != write_io) {
10823 GetOpenFile(write_io, fptr);
10824 if (rb_fd_isset(fptr->fd, &fds[2])) {
10825 rb_ary_push(list, obj);
10826 }
10827 }
10828 }
10829 }
10830
10831 return res; /* returns an empty array on interrupt */
10832}
10833
10835 VALUE read, write, except;
10836 struct timeval *timeout;
10837 rb_fdset_t fdsets[4];
10838};
10839
10840static VALUE
10841select_call(VALUE arg)
10842{
10843 struct select_args *p = (struct select_args *)arg;
10844
10845 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10846}
10847
10848static VALUE
10849select_end(VALUE arg)
10850{
10851 struct select_args *p = (struct select_args *)arg;
10852 int i;
10853
10854 for (i = 0; i < numberof(p->fdsets); ++i)
10855 rb_fd_term(&p->fdsets[i]);
10856 return Qnil;
10857}
10858
10859static VALUE sym_normal, sym_sequential, sym_random,
10860 sym_willneed, sym_dontneed, sym_noreuse;
10861
10862#ifdef HAVE_POSIX_FADVISE
10863struct io_advise_struct {
10864 int fd;
10865 int advice;
10866 rb_off_t offset;
10867 rb_off_t len;
10868};
10869
10870static VALUE
10871io_advise_internal(void *arg)
10872{
10873 struct io_advise_struct *ptr = arg;
10874 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10875}
10876
10877static VALUE
10878io_advise_sym_to_const(VALUE sym)
10879{
10880#ifdef POSIX_FADV_NORMAL
10881 if (sym == sym_normal)
10882 return INT2NUM(POSIX_FADV_NORMAL);
10883#endif
10884
10885#ifdef POSIX_FADV_RANDOM
10886 if (sym == sym_random)
10887 return INT2NUM(POSIX_FADV_RANDOM);
10888#endif
10889
10890#ifdef POSIX_FADV_SEQUENTIAL
10891 if (sym == sym_sequential)
10892 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10893#endif
10894
10895#ifdef POSIX_FADV_WILLNEED
10896 if (sym == sym_willneed)
10897 return INT2NUM(POSIX_FADV_WILLNEED);
10898#endif
10899
10900#ifdef POSIX_FADV_DONTNEED
10901 if (sym == sym_dontneed)
10902 return INT2NUM(POSIX_FADV_DONTNEED);
10903#endif
10904
10905#ifdef POSIX_FADV_NOREUSE
10906 if (sym == sym_noreuse)
10907 return INT2NUM(POSIX_FADV_NOREUSE);
10908#endif
10909
10910 return Qnil;
10911}
10912
10913static VALUE
10914do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10915{
10916 int rv;
10917 struct io_advise_struct ias;
10918 VALUE num_adv;
10919
10920 num_adv = io_advise_sym_to_const(advice);
10921
10922 /*
10923 * The platform doesn't support this hint. We don't raise exception, instead
10924 * silently ignore it. Because IO::advise is only hint.
10925 */
10926 if (NIL_P(num_adv))
10927 return Qnil;
10928
10929 ias.fd = fptr->fd;
10930 ias.advice = NUM2INT(num_adv);
10931 ias.offset = offset;
10932 ias.len = len;
10933
10934 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10935 if (rv && rv != ENOSYS) {
10936 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10937 it returns the error code. */
10938 VALUE message = rb_sprintf("%"PRIsVALUE" "
10939 "(%"PRI_OFFT_PREFIX"d, "
10940 "%"PRI_OFFT_PREFIX"d, "
10941 "%"PRIsVALUE")",
10942 fptr->pathv, offset, len, advice);
10943 rb_syserr_fail_str(rv, message);
10944 }
10945
10946 return Qnil;
10947}
10948
10949#endif /* HAVE_POSIX_FADVISE */
10950
10951static void
10952advice_arg_check(VALUE advice)
10953{
10954 if (!SYMBOL_P(advice))
10955 rb_raise(rb_eTypeError, "advice must be a Symbol");
10956
10957 if (advice != sym_normal &&
10958 advice != sym_sequential &&
10959 advice != sym_random &&
10960 advice != sym_willneed &&
10961 advice != sym_dontneed &&
10962 advice != sym_noreuse) {
10963 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10964 }
10965}
10966
10967/*
10968 * call-seq:
10969 * advise(advice, offset = 0, len = 0) -> nil
10970 *
10971 * Invokes Posix system call
10972 * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
10973 * which announces an intention to access data from the current file
10974 * in a particular manner.
10975 *
10976 * The arguments and results are platform-dependent.
10977 *
10978 * The relevant data is specified by:
10979 *
10980 * - +offset+: The offset of the first byte of data.
10981 * - +len+: The number of bytes to be accessed;
10982 * if +len+ is zero, or is larger than the number of bytes remaining,
10983 * all remaining bytes will be accessed.
10984 *
10985 * Argument +advice+ is one of the following symbols:
10986 *
10987 * - +:normal+: The application has no advice to give
10988 * about its access pattern for the specified data.
10989 * If no advice is given for an open file, this is the default assumption.
10990 * - +:sequential+: The application expects to access the specified data sequentially
10991 * (with lower offsets read before higher ones).
10992 * - +:random+: The specified data will be accessed in random order.
10993 * - +:noreuse+: The specified data will be accessed only once.
10994 * - +:willneed+: The specified data will be accessed in the near future.
10995 * - +:dontneed+: The specified data will not be accessed in the near future.
10996 *
10997 * Not implemented on all platforms.
10998 *
10999 */
11000static VALUE
11001rb_io_advise(int argc, VALUE *argv, VALUE io)
11002{
11003 VALUE advice, offset, len;
11004 rb_off_t off, l;
11005 rb_io_t *fptr;
11006
11007 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
11008 advice_arg_check(advice);
11009
11010 io = GetWriteIO(io);
11011 GetOpenFile(io, fptr);
11012
11013 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11014 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11015
11016#ifdef HAVE_POSIX_FADVISE
11017 return do_io_advise(fptr, advice, off, l);
11018#else
11019 ((void)off, (void)l); /* Ignore all hint */
11020 return Qnil;
11021#endif
11022}
11023
11024static int
11025is_pos_inf(VALUE x)
11026{
11027 double f;
11028 if (!RB_FLOAT_TYPE_P(x))
11029 return 0;
11030 f = RFLOAT_VALUE(x);
11031 return isinf(f) && 0 < f;
11032}
11033
11034/*
11035 * call-seq:
11036 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11037 *
11038 * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
11039 * which monitors multiple file descriptors,
11040 * waiting until one or more of the file descriptors
11041 * becomes ready for some class of I/O operation.
11042 *
11043 * Not implemented on all platforms.
11044 *
11045 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11046 * is an array of IO objects.
11047 *
11048 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11049 * interval in seconds.
11050 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11051 * +nil+ and +Float::INFINITY+ means no timeout.
11052 *
11053 * The method monitors the \IO objects given in all three arrays,
11054 * waiting for some to be ready;
11055 * returns a 3-element array whose elements are:
11056 *
11057 * - An array of the objects in +read_ios+ that are ready for reading.
11058 * - An array of the objects in +write_ios+ that are ready for writing.
11059 * - An array of the objects in +error_ios+ have pending exceptions.
11060 *
11061 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11062 *
11063 * \IO.select peeks the buffer of \IO objects for testing readability.
11064 * If the \IO buffer is not empty, \IO.select immediately notifies
11065 * readability. This "peek" only happens for \IO objects. It does not
11066 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11067 *
11068 * The best way to use \IO.select is invoking it after non-blocking
11069 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11070 * raise an exception which is extended by IO::WaitReadable or
11071 * IO::WaitWritable. The modules notify how the caller should wait
11072 * with \IO.select. If IO::WaitReadable is raised, the caller should
11073 * wait for reading. If IO::WaitWritable is raised, the caller should
11074 * wait for writing.
11075 *
11076 * So, blocking read (#readpartial) can be emulated using
11077 * #read_nonblock and \IO.select as follows:
11078 *
11079 * begin
11080 * result = io_like.read_nonblock(maxlen)
11081 * rescue IO::WaitReadable
11082 * IO.select([io_like])
11083 * retry
11084 * rescue IO::WaitWritable
11085 * IO.select(nil, [io_like])
11086 * retry
11087 * end
11088 *
11089 * Especially, the combination of non-blocking methods and \IO.select is
11090 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11091 * has #to_io method to return underlying IO object. IO.select calls
11092 * #to_io to obtain the file descriptor to wait.
11093 *
11094 * This means that readability notified by \IO.select doesn't mean
11095 * readability from OpenSSL::SSL::SSLSocket object.
11096 *
11097 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11098 * some data. \IO.select doesn't see the buffer. So \IO.select can
11099 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11100 *
11101 * However, several more complicated situations exist.
11102 *
11103 * SSL is a protocol which is sequence of records.
11104 * The record consists of multiple bytes.
11105 * So, the remote side of SSL sends a partial record, IO.select
11106 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11107 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11108 *
11109 * Also, the remote side can request SSL renegotiation which forces
11110 * the local SSL engine to write some data.
11111 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11112 * system call and it can block.
11113 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11114 * IO::WaitWritable instead of blocking.
11115 * So, the caller should wait for ready for writability as above
11116 * example.
11117 *
11118 * The combination of non-blocking methods and \IO.select is also useful
11119 * for streams such as tty, pipe socket socket when multiple processes
11120 * read from a stream.
11121 *
11122 * Finally, Linux kernel developers don't guarantee that
11123 * readability of select(2) means readability of following read(2) even
11124 * for a single process;
11125 * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
11126 *
11127 * Invoking \IO.select before IO#readpartial works well as usual.
11128 * However it is not the best way to use \IO.select.
11129 *
11130 * The writability notified by select(2) doesn't show
11131 * how many bytes are writable.
11132 * IO#write method blocks until given whole string is written.
11133 * So, <tt>IO#write(two or more bytes)</tt> can block after
11134 * writability is notified by \IO.select. IO#write_nonblock is required
11135 * to avoid the blocking.
11136 *
11137 * Blocking write (#write) can be emulated using #write_nonblock and
11138 * IO.select as follows: IO::WaitReadable should also be rescued for
11139 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11140 *
11141 * while 0 < string.bytesize
11142 * begin
11143 * written = io_like.write_nonblock(string)
11144 * rescue IO::WaitReadable
11145 * IO.select([io_like])
11146 * retry
11147 * rescue IO::WaitWritable
11148 * IO.select(nil, [io_like])
11149 * retry
11150 * end
11151 * string = string.byteslice(written..-1)
11152 * end
11153 *
11154 * Example:
11155 *
11156 * rp, wp = IO.pipe
11157 * mesg = "ping "
11158 * 100.times {
11159 * # IO.select follows IO#read. Not the best way to use IO.select.
11160 * rs, ws, = IO.select([rp], [wp])
11161 * if r = rs[0]
11162 * ret = r.read(5)
11163 * print ret
11164 * case ret
11165 * when /ping/
11166 * mesg = "pong\n"
11167 * when /pong/
11168 * mesg = "ping "
11169 * end
11170 * end
11171 * if w = ws[0]
11172 * w.write(mesg)
11173 * end
11174 * }
11175 *
11176 * Output:
11177 *
11178 * ping pong
11179 * ping pong
11180 * ping pong
11181 * (snipped)
11182 * ping
11183 *
11184 */
11185
11186static VALUE
11187rb_f_select(int argc, VALUE *argv, VALUE obj)
11188{
11189 VALUE scheduler = rb_fiber_scheduler_current();
11190 if (scheduler != Qnil) {
11191 // It's optionally supported.
11192 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11193 if (!UNDEF_P(result)) return result;
11194 }
11195
11196 VALUE timeout;
11197 struct select_args args;
11198 struct timeval timerec;
11199 int i;
11200
11201 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11202 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11203 args.timeout = 0;
11204 }
11205 else {
11206 timerec = rb_time_interval(timeout);
11207 args.timeout = &timerec;
11208 }
11209
11210 for (i = 0; i < numberof(args.fdsets); ++i)
11211 rb_fd_init(&args.fdsets[i]);
11212
11213 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11214}
11215
11216#ifdef IOCTL_REQ_TYPE
11217 typedef IOCTL_REQ_TYPE ioctl_req_t;
11218#else
11219 typedef int ioctl_req_t;
11220# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11221#endif
11222
11223#ifdef HAVE_IOCTL
11224struct ioctl_arg {
11225 int fd;
11226 ioctl_req_t cmd;
11227 long narg;
11228};
11229
11230static VALUE
11231nogvl_ioctl(void *ptr)
11232{
11233 struct ioctl_arg *arg = ptr;
11234
11235 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11236}
11237
11238static int
11239do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11240{
11241 int retval;
11242 struct ioctl_arg arg;
11243
11244 arg.fd = io->fd;
11245 arg.cmd = cmd;
11246 arg.narg = narg;
11247
11248 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11249
11250 return retval;
11251}
11252#endif
11253
11254#define DEFAULT_IOCTL_NARG_LEN (256)
11255
11256#if defined(__linux__) && defined(_IOC_SIZE)
11257static long
11258linux_iocparm_len(ioctl_req_t cmd)
11259{
11260 long len;
11261
11262 if ((cmd & 0xFFFF0000) == 0) {
11263 /* legacy and unstructured ioctl number. */
11264 return DEFAULT_IOCTL_NARG_LEN;
11265 }
11266
11267 len = _IOC_SIZE(cmd);
11268
11269 /* paranoia check for silly drivers which don't keep ioctl convention */
11270 if (len < DEFAULT_IOCTL_NARG_LEN)
11271 len = DEFAULT_IOCTL_NARG_LEN;
11272
11273 return len;
11274}
11275#endif
11276
11277#ifdef HAVE_IOCTL
11278static long
11279ioctl_narg_len(ioctl_req_t cmd)
11280{
11281 long len;
11282
11283#ifdef IOCPARM_MASK
11284#ifndef IOCPARM_LEN
11285#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11286#endif
11287#endif
11288#ifdef IOCPARM_LEN
11289 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11290#elif defined(__linux__) && defined(_IOC_SIZE)
11291 len = linux_iocparm_len(cmd);
11292#else
11293 /* otherwise guess at what's safe */
11294 len = DEFAULT_IOCTL_NARG_LEN;
11295#endif
11296
11297 return len;
11298}
11299#endif
11300
11301#ifdef HAVE_FCNTL
11302#ifdef __linux__
11303typedef long fcntl_arg_t;
11304#else
11305/* posix */
11306typedef int fcntl_arg_t;
11307#endif
11308
11309static long
11310fcntl_narg_len(ioctl_req_t cmd)
11311{
11312 long len;
11313
11314 switch (cmd) {
11315#ifdef F_DUPFD
11316 case F_DUPFD:
11317 len = sizeof(fcntl_arg_t);
11318 break;
11319#endif
11320#ifdef F_DUP2FD /* bsd specific */
11321 case F_DUP2FD:
11322 len = sizeof(int);
11323 break;
11324#endif
11325#ifdef F_DUPFD_CLOEXEC /* linux specific */
11326 case F_DUPFD_CLOEXEC:
11327 len = sizeof(fcntl_arg_t);
11328 break;
11329#endif
11330#ifdef F_GETFD
11331 case F_GETFD:
11332 len = 1;
11333 break;
11334#endif
11335#ifdef F_SETFD
11336 case F_SETFD:
11337 len = sizeof(fcntl_arg_t);
11338 break;
11339#endif
11340#ifdef F_GETFL
11341 case F_GETFL:
11342 len = 1;
11343 break;
11344#endif
11345#ifdef F_SETFL
11346 case F_SETFL:
11347 len = sizeof(fcntl_arg_t);
11348 break;
11349#endif
11350#ifdef F_GETOWN
11351 case F_GETOWN:
11352 len = 1;
11353 break;
11354#endif
11355#ifdef F_SETOWN
11356 case F_SETOWN:
11357 len = sizeof(fcntl_arg_t);
11358 break;
11359#endif
11360#ifdef F_GETOWN_EX /* linux specific */
11361 case F_GETOWN_EX:
11362 len = sizeof(struct f_owner_ex);
11363 break;
11364#endif
11365#ifdef F_SETOWN_EX /* linux specific */
11366 case F_SETOWN_EX:
11367 len = sizeof(struct f_owner_ex);
11368 break;
11369#endif
11370#ifdef F_GETLK
11371 case F_GETLK:
11372 len = sizeof(struct flock);
11373 break;
11374#endif
11375#ifdef F_SETLK
11376 case F_SETLK:
11377 len = sizeof(struct flock);
11378 break;
11379#endif
11380#ifdef F_SETLKW
11381 case F_SETLKW:
11382 len = sizeof(struct flock);
11383 break;
11384#endif
11385#ifdef F_READAHEAD /* bsd specific */
11386 case F_READAHEAD:
11387 len = sizeof(int);
11388 break;
11389#endif
11390#ifdef F_RDAHEAD /* Darwin specific */
11391 case F_RDAHEAD:
11392 len = sizeof(int);
11393 break;
11394#endif
11395#ifdef F_GETSIG /* linux specific */
11396 case F_GETSIG:
11397 len = 1;
11398 break;
11399#endif
11400#ifdef F_SETSIG /* linux specific */
11401 case F_SETSIG:
11402 len = sizeof(fcntl_arg_t);
11403 break;
11404#endif
11405#ifdef F_GETLEASE /* linux specific */
11406 case F_GETLEASE:
11407 len = 1;
11408 break;
11409#endif
11410#ifdef F_SETLEASE /* linux specific */
11411 case F_SETLEASE:
11412 len = sizeof(fcntl_arg_t);
11413 break;
11414#endif
11415#ifdef F_NOTIFY /* linux specific */
11416 case F_NOTIFY:
11417 len = sizeof(fcntl_arg_t);
11418 break;
11419#endif
11420
11421 default:
11422 len = 256;
11423 break;
11424 }
11425
11426 return len;
11427}
11428#else /* HAVE_FCNTL */
11429static long
11430fcntl_narg_len(ioctl_req_t cmd)
11431{
11432 return 0;
11433}
11434#endif /* HAVE_FCNTL */
11435
11436#define NARG_SENTINEL 17
11437
11438static long
11439setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11440{
11441 long narg = 0;
11442 VALUE arg = *argp;
11443
11444 if (!RTEST(arg)) {
11445 narg = 0;
11446 }
11447 else if (FIXNUM_P(arg)) {
11448 narg = FIX2LONG(arg);
11449 }
11450 else if (arg == Qtrue) {
11451 narg = 1;
11452 }
11453 else {
11454 VALUE tmp = rb_check_string_type(arg);
11455
11456 if (NIL_P(tmp)) {
11457 narg = NUM2LONG(arg);
11458 }
11459 else {
11460 char *ptr;
11461 long len, slen;
11462
11463 *argp = arg = tmp;
11464 len = narg_len(cmd);
11465 rb_str_modify(arg);
11466
11467 slen = RSTRING_LEN(arg);
11468 /* expand for data + sentinel. */
11469 if (slen < len+1) {
11470 rb_str_resize(arg, len+1);
11471 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11472 slen = len+1;
11473 }
11474 /* a little sanity check here */
11475 ptr = RSTRING_PTR(arg);
11476 ptr[slen - 1] = NARG_SENTINEL;
11477 narg = (long)(SIGNED_VALUE)ptr;
11478 }
11479 }
11480
11481 return narg;
11482}
11483
11484static VALUE
11485finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11486{
11487 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11488 if (RB_TYPE_P(arg, T_STRING)) {
11489 char *ptr;
11490 long slen;
11491 RSTRING_GETMEM(arg, ptr, slen);
11492 if (ptr[slen-1] != NARG_SENTINEL)
11493 rb_raise(rb_eArgError, "return value overflowed string");
11494 ptr[slen-1] = '\0';
11495 }
11496
11497 return INT2NUM(retval);
11498}
11499
11500#ifdef HAVE_IOCTL
11501static VALUE
11502rb_ioctl(VALUE io, VALUE req, VALUE arg)
11503{
11504 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11505 rb_io_t *fptr;
11506 long narg;
11507 int retval;
11508
11509 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11510 GetOpenFile(io, fptr);
11511 retval = do_ioctl(fptr, cmd, narg);
11512 return finish_narg(retval, arg, fptr);
11513}
11514
11515/*
11516 * call-seq:
11517 * ioctl(integer_cmd, argument) -> integer
11518 *
11519 * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
11520 * which issues a low-level command to an I/O device.
11521 *
11522 * Issues a low-level command to an I/O device.
11523 * The arguments and returned value are platform-dependent.
11524 * The effect of the call is platform-dependent.
11525 *
11526 * If argument +argument+ is an integer, it is passed directly;
11527 * if it is a string, it is interpreted as a binary sequence of bytes.
11528 *
11529 * Not implemented on all platforms.
11530 *
11531 */
11532
11533static VALUE
11534rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11535{
11536 VALUE req, arg;
11537
11538 rb_scan_args(argc, argv, "11", &req, &arg);
11539 return rb_ioctl(io, req, arg);
11540}
11541#else
11542#define rb_io_ioctl rb_f_notimplement
11543#endif
11544
11545#ifdef HAVE_FCNTL
11546struct fcntl_arg {
11547 int fd;
11548 int cmd;
11549 long narg;
11550};
11551
11552static VALUE
11553nogvl_fcntl(void *ptr)
11554{
11555 struct fcntl_arg *arg = ptr;
11556
11557#if defined(F_DUPFD)
11558 if (arg->cmd == F_DUPFD)
11559 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11560#endif
11561 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11562}
11563
11564static int
11565do_fcntl(struct rb_io *io, int cmd, long narg)
11566{
11567 int retval;
11568 struct fcntl_arg arg;
11569
11570 arg.fd = io->fd;
11571 arg.cmd = cmd;
11572 arg.narg = narg;
11573
11574 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11575 if (retval != -1) {
11576 switch (cmd) {
11577#if defined(F_DUPFD)
11578 case F_DUPFD:
11579#endif
11580#if defined(F_DUPFD_CLOEXEC)
11581 case F_DUPFD_CLOEXEC:
11582#endif
11583 rb_update_max_fd(retval);
11584 }
11585 }
11586
11587 return retval;
11588}
11589
11590static VALUE
11591rb_fcntl(VALUE io, VALUE req, VALUE arg)
11592{
11593 int cmd = NUM2INT(req);
11594 rb_io_t *fptr;
11595 long narg;
11596 int retval;
11597
11598 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11599 GetOpenFile(io, fptr);
11600 retval = do_fcntl(fptr, cmd, narg);
11601 return finish_narg(retval, arg, fptr);
11602}
11603
11604/*
11605 * call-seq:
11606 * fcntl(integer_cmd, argument) -> integer
11607 *
11608 * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
11609 * which provides a mechanism for issuing low-level commands to control or query
11610 * a file-oriented I/O stream. Arguments and results are platform
11611 * dependent.
11612 *
11613 * If +argument+ is a number, its value is passed directly;
11614 * if it is a string, it is interpreted as a binary sequence of bytes.
11615 * (Array#pack might be a useful way to build this string.)
11616 *
11617 * Not implemented on all platforms.
11618 *
11619 */
11620
11621static VALUE
11622rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11623{
11624 VALUE req, arg;
11625
11626 rb_scan_args(argc, argv, "11", &req, &arg);
11627 return rb_fcntl(io, req, arg);
11628}
11629#else
11630#define rb_io_fcntl rb_f_notimplement
11631#endif
11632
11633#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11634/*
11635 * call-seq:
11636 * syscall(integer_callno, *arguments) -> integer
11637 *
11638 * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
11639 * which calls a specified function.
11640 *
11641 * Calls the operating system function identified by +integer_callno+;
11642 * returns the result of the function or raises SystemCallError if it failed.
11643 * The effect of the call is platform-dependent.
11644 * The arguments and returned value are platform-dependent.
11645 *
11646 * For each of +arguments+: if it is an integer, it is passed directly;
11647 * if it is a string, it is interpreted as a binary sequence of bytes.
11648 * There may be as many as nine such arguments.
11649 *
11650 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11651 * are platform-dependent.
11652 *
11653 * Note: Method +syscall+ is essentially unsafe and unportable.
11654 * The DL (Fiddle) library is preferred for safer and a bit
11655 * more portable programming.
11656 *
11657 * Not implemented on all platforms.
11658 *
11659 */
11660
11661static VALUE
11662rb_f_syscall(int argc, VALUE *argv, VALUE _)
11663{
11664 VALUE arg[8];
11665#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11666# define SYSCALL __syscall
11667# define NUM2SYSCALLID(x) NUM2LONG(x)
11668# define RETVAL2NUM(x) LONG2NUM(x)
11669# if SIZEOF_LONG == 8
11670 long num, retval = -1;
11671# elif SIZEOF_LONG_LONG == 8
11672 long long num, retval = -1;
11673# else
11674# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11675# endif
11676#elif defined(__linux__)
11677# define SYSCALL syscall
11678# define NUM2SYSCALLID(x) NUM2LONG(x)
11679# define RETVAL2NUM(x) LONG2NUM(x)
11680 /*
11681 * Linux man page says, syscall(2) function prototype is below.
11682 *
11683 * int syscall(int number, ...);
11684 *
11685 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11686 */
11687 long num, retval = -1;
11688#else
11689# define SYSCALL syscall
11690# define NUM2SYSCALLID(x) NUM2INT(x)
11691# define RETVAL2NUM(x) INT2NUM(x)
11692 int num, retval = -1;
11693#endif
11694 int i;
11695
11696 if (RTEST(ruby_verbose)) {
11698 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11699 }
11700
11701 if (argc == 0)
11702 rb_raise(rb_eArgError, "too few arguments for syscall");
11703 if (argc > numberof(arg))
11704 rb_raise(rb_eArgError, "too many arguments for syscall");
11705 num = NUM2SYSCALLID(argv[0]); ++argv;
11706 for (i = argc - 1; i--; ) {
11707 VALUE v = rb_check_string_type(argv[i]);
11708
11709 if (!NIL_P(v)) {
11710 StringValue(v);
11711 rb_str_modify(v);
11712 arg[i] = (VALUE)StringValueCStr(v);
11713 }
11714 else {
11715 arg[i] = (VALUE)NUM2LONG(argv[i]);
11716 }
11717 }
11718
11719 switch (argc) {
11720 case 1:
11721 retval = SYSCALL(num);
11722 break;
11723 case 2:
11724 retval = SYSCALL(num, arg[0]);
11725 break;
11726 case 3:
11727 retval = SYSCALL(num, arg[0],arg[1]);
11728 break;
11729 case 4:
11730 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11731 break;
11732 case 5:
11733 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11734 break;
11735 case 6:
11736 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11737 break;
11738 case 7:
11739 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11740 break;
11741 case 8:
11742 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11743 break;
11744 }
11745
11746 if (retval == -1)
11747 rb_sys_fail(0);
11748 return RETVAL2NUM(retval);
11749#undef SYSCALL
11750#undef NUM2SYSCALLID
11751#undef RETVAL2NUM
11752}
11753#else
11754#define rb_f_syscall rb_f_notimplement
11755#endif
11756
11757static VALUE
11758io_new_instance(VALUE args)
11759{
11760 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11761}
11762
11763static rb_encoding *
11764find_encoding(VALUE v)
11765{
11766 rb_encoding *enc = rb_find_encoding(v);
11767 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11768 return enc;
11769}
11770
11771static void
11772io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11773{
11774 rb_encoding *enc, *enc2;
11775 int ecflags = fptr->encs.ecflags;
11776 VALUE ecopts, tmp;
11777
11778 if (!NIL_P(v2)) {
11779 enc2 = find_encoding(v1);
11780 tmp = rb_check_string_type(v2);
11781 if (!NIL_P(tmp)) {
11782 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11783 /* Special case - "-" => no transcoding */
11784 enc = enc2;
11785 enc2 = NULL;
11786 }
11787 else
11788 enc = find_encoding(v2);
11789 if (enc == enc2) {
11790 /* Special case - "-" => no transcoding */
11791 enc2 = NULL;
11792 }
11793 }
11794 else {
11795 enc = find_encoding(v2);
11796 if (enc == enc2) {
11797 /* Special case - "-" => no transcoding */
11798 enc2 = NULL;
11799 }
11800 }
11801 if (enc2 == rb_ascii8bit_encoding()) {
11802 /* If external is ASCII-8BIT, no transcoding */
11803 enc = enc2;
11804 enc2 = NULL;
11805 }
11806 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11807 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11808 }
11809 else {
11810 if (NIL_P(v1)) {
11811 /* Set to default encodings */
11812 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11813 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11814 ecopts = Qnil;
11815 }
11816 else {
11817 tmp = rb_check_string_type(v1);
11818 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11819 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11820 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11821 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11822 }
11823 else {
11824 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11825 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11826 ecopts = Qnil;
11827 }
11828 }
11829 }
11830 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11831 fptr->encs.enc = enc;
11832 fptr->encs.enc2 = enc2;
11833 fptr->encs.ecflags = ecflags;
11834 fptr->encs.ecopts = ecopts;
11835 clear_codeconv(fptr);
11836
11837}
11838
11840 rb_io_t *fptr;
11841 VALUE v1;
11842 VALUE v2;
11843 VALUE opt;
11844};
11845
11846static VALUE
11847io_encoding_set_v(VALUE v)
11848{
11849 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11850 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11851 return Qnil;
11852}
11853
11854static VALUE
11855pipe_pair_close(VALUE rw)
11856{
11857 VALUE *rwp = (VALUE *)rw;
11858 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11859}
11860
11861/*
11862 * call-seq:
11863 * IO.pipe(**opts) -> [read_io, write_io]
11864 * IO.pipe(enc, **opts) -> [read_io, write_io]
11865 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11866 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11867 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11868 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11869 *
11870 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11871 * connected to each other.
11872 *
11873 * If argument +enc_string+ is given, it must be a string containing one of:
11874 *
11875 * - The name of the encoding to be used as the external encoding.
11876 * - The colon-separated names of two encodings to be used as the external
11877 * and internal encodings.
11878 *
11879 * If argument +int_enc+ is given, it must be an Encoding object
11880 * or encoding name string that specifies the internal encoding to be used;
11881 * if argument +ext_enc+ is also given, it must be an Encoding object
11882 * or encoding name string that specifies the external encoding to be used.
11883 *
11884 * The string read from +read_io+ is tagged with the external encoding;
11885 * if an internal encoding is also specified, the string is converted
11886 * to, and tagged with, that encoding.
11887 *
11888 * If any encoding is specified,
11889 * optional hash arguments specify the conversion option.
11890 *
11891 * Optional keyword arguments +opts+ specify:
11892 *
11893 * - {Open Options}[rdoc-ref:IO@Open+Options].
11894 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11895 *
11896 * With no block given, returns the two endpoints in an array:
11897 *
11898 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11899 *
11900 * With a block given, calls the block with the two endpoints;
11901 * closes both endpoints and returns the value of the block:
11902 *
11903 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11904 *
11905 * Output:
11906 *
11907 * #<IO:fd 6>
11908 * #<IO:fd 7>
11909 *
11910 * Not available on all platforms.
11911 *
11912 * In the example below, the two processes close the ends of the pipe
11913 * that they are not using. This is not just a cosmetic nicety. The
11914 * read end of a pipe will not generate an end of file condition if
11915 * there are any writers with the pipe still open. In the case of the
11916 * parent process, the <tt>rd.read</tt> will never return if it
11917 * does not first issue a <tt>wr.close</tt>:
11918 *
11919 * rd, wr = IO.pipe
11920 *
11921 * if fork
11922 * wr.close
11923 * puts "Parent got: <#{rd.read}>"
11924 * rd.close
11925 * Process.wait
11926 * else
11927 * rd.close
11928 * puts 'Sending message to parent'
11929 * wr.write "Hi Dad"
11930 * wr.close
11931 * end
11932 *
11933 * <em>produces:</em>
11934 *
11935 * Sending message to parent
11936 * Parent got: <Hi Dad>
11937 *
11938 */
11939
11940static VALUE
11941rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11942{
11943 int pipes[2], state;
11944 VALUE r, w, args[3], v1, v2;
11945 VALUE opt;
11946 rb_io_t *fptr, *fptr2;
11947 struct io_encoding_set_args ies_args;
11948 enum rb_io_mode fmode = 0;
11949 VALUE ret;
11950
11951 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11952 if (rb_pipe(pipes) < 0)
11953 rb_sys_fail(0);
11954
11955 args[0] = klass;
11956 args[1] = INT2NUM(pipes[0]);
11957 args[2] = INT2FIX(O_RDONLY);
11958 r = rb_protect(io_new_instance, (VALUE)args, &state);
11959 if (state) {
11960 close(pipes[0]);
11961 close(pipes[1]);
11962 rb_jump_tag(state);
11963 }
11964 GetOpenFile(r, fptr);
11965
11966 ies_args.fptr = fptr;
11967 ies_args.v1 = v1;
11968 ies_args.v2 = v2;
11969 ies_args.opt = opt;
11970 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11971 if (state) {
11972 close(pipes[1]);
11973 io_close(r);
11974 rb_jump_tag(state);
11975 }
11976
11977 args[1] = INT2NUM(pipes[1]);
11978 args[2] = INT2FIX(O_WRONLY);
11979 w = rb_protect(io_new_instance, (VALUE)args, &state);
11980 if (state) {
11981 close(pipes[1]);
11982 if (!NIL_P(r)) rb_io_close(r);
11983 rb_jump_tag(state);
11984 }
11985 GetOpenFile(w, fptr2);
11986 rb_io_synchronized(fptr2);
11987
11988 extract_binmode(opt, &fmode);
11989
11990 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11993 }
11994
11995#if DEFAULT_TEXTMODE
11996 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11997 fptr->mode &= ~FMODE_TEXTMODE;
11998 setmode(fptr->fd, O_BINARY);
11999 }
12000#if RUBY_CRLF_ENVIRONMENT
12003 }
12004#endif
12005#endif
12006 fptr->mode |= fmode;
12007#if DEFAULT_TEXTMODE
12008 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12009 fptr2->mode &= ~FMODE_TEXTMODE;
12010 setmode(fptr2->fd, O_BINARY);
12011 }
12012#endif
12013 fptr2->mode |= fmode;
12014
12015 ret = rb_assoc_new(r, w);
12016 if (rb_block_given_p()) {
12017 VALUE rw[2];
12018 rw[0] = r;
12019 rw[1] = w;
12020 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12021 }
12022 return ret;
12023}
12024
12026 int argc;
12027 VALUE *argv;
12028 VALUE io;
12029};
12030
12031static void
12032open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12033{
12034 VALUE path, v;
12035 VALUE vmode = Qnil, vperm = Qnil;
12036
12037 path = *argv++;
12038 argc--;
12039 FilePathValue(path);
12040 arg->io = 0;
12041 arg->argc = argc;
12042 arg->argv = argv;
12043 if (NIL_P(opt)) {
12044 vmode = INT2NUM(O_RDONLY);
12045 vperm = INT2FIX(0666);
12046 }
12047 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12048 int n;
12049
12050 v = rb_to_array_type(v);
12051 n = RARRAY_LENINT(v);
12052 rb_check_arity(n, 0, 3); /* rb_io_open */
12053 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12054 }
12055 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12056}
12057
12058static VALUE
12059io_s_foreach(VALUE v)
12060{
12061 struct getline_arg *arg = (void *)v;
12062 VALUE str;
12063
12064 if (arg->limit == 0)
12065 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12066 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12067 rb_lastline_set(str);
12068 rb_yield(str);
12069 }
12071 return Qnil;
12072}
12073
12074/*
12075 * call-seq:
12076 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12077 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12078 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12079 * IO.foreach(...) -> an_enumerator
12080 *
12081 * Calls the block with each successive line read from the stream.
12082 *
12083 * The first argument must be a string that is the path to a file.
12084 *
12085 * With only argument +path+ given, parses lines from the file at the given +path+,
12086 * as determined by the default line separator,
12087 * and calls the block with each successive line:
12088 *
12089 * File.foreach('t.txt') {|line| p line }
12090 *
12091 * Output: the same as above.
12092 *
12093 * For both forms, command and path, the remaining arguments are the same.
12094 *
12095 * With argument +sep+ given, parses lines as determined by that line separator
12096 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12097 *
12098 * File.foreach('t.txt', 'li') {|line| p line }
12099 *
12100 * Output:
12101 *
12102 * "First li"
12103 * "ne\nSecond li"
12104 * "ne\n\nThird li"
12105 * "ne\nFourth li"
12106 * "ne\n"
12107 *
12108 * Each paragraph:
12109 *
12110 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12111 *
12112 * Output:
12113 *
12114 * "First line\nSecond line\n\n"
12115 * "Third line\nFourth line\n"
12116 *
12117 * With argument +limit+ given, parses lines as determined by the default
12118 * line separator and the given line-length limit
12119 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12120 *
12121 * File.foreach('t.txt', 7) {|line| p line }
12122 *
12123 * Output:
12124 *
12125 * "First l"
12126 * "ine\n"
12127 * "Second "
12128 * "line\n"
12129 * "\n"
12130 * "Third l"
12131 * "ine\n"
12132 * "Fourth l"
12133 * "line\n"
12134 *
12135 * With arguments +sep+ and +limit+ given,
12136 * combines the two behaviors
12137 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12138 *
12139 * Optional keyword arguments +opts+ specify:
12140 *
12141 * - {Open Options}[rdoc-ref:IO@Open+Options].
12142 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12143 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12144 *
12145 * Returns an Enumerator if no block is given.
12146 *
12147 */
12148
12149static VALUE
12150rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12151{
12152 VALUE opt;
12153 int orig_argc = argc;
12154 struct foreach_arg arg;
12155 struct getline_arg garg;
12156
12157 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12158 RETURN_ENUMERATOR(self, orig_argc, argv);
12159 extract_getline_args(argc-1, argv+1, &garg);
12160 open_key_args(self, argc, argv, opt, &arg);
12161 if (NIL_P(arg.io)) return Qnil;
12162 extract_getline_opts(opt, &garg);
12163 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12164 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12165}
12166
12167static VALUE
12168io_s_readlines(VALUE v)
12169{
12170 struct getline_arg *arg = (void *)v;
12171 return io_readlines(arg, arg->io);
12172}
12173
12174/*
12175 * call-seq:
12176 * IO.readlines(path, sep = $/, **opts) -> array
12177 * IO.readlines(path, limit, **opts) -> array
12178 * IO.readlines(path, sep, limit, **opts) -> array
12179 *
12180 * Returns an array of all lines read from the stream.
12181 *
12182 * The first argument must be a string that is the path to a file.
12183 *
12184 * With only argument +path+ given, parses lines from the file at the given +path+,
12185 * as determined by the default line separator,
12186 * and returns those lines in an array:
12187 *
12188 * IO.readlines('t.txt')
12189 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12190 *
12191 * With argument +sep+ given, parses lines as determined by that line separator
12192 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12193 *
12194 * # Ordinary separator.
12195 * IO.readlines('t.txt', 'li')
12196 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12197 * # Get-paragraphs separator.
12198 * IO.readlines('t.txt', '')
12199 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12200 * # Get-all separator.
12201 * IO.readlines('t.txt', nil)
12202 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12203 *
12204 * With argument +limit+ given, parses lines as determined by the default
12205 * line separator and the given line-length limit
12206 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12207 *
12208 * IO.readlines('t.txt', 7)
12209 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12210 *
12211 * With arguments +sep+ and +limit+ given,
12212 * combines the two behaviors
12213 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12214 *
12215 * Optional keyword arguments +opts+ specify:
12216 *
12217 * - {Open Options}[rdoc-ref:IO@Open+Options].
12218 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12219 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12220 *
12221 */
12222
12223static VALUE
12224rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12225{
12226 VALUE opt;
12227 struct foreach_arg arg;
12228 struct getline_arg garg;
12229
12230 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12231 extract_getline_args(argc-1, argv+1, &garg);
12232 open_key_args(io, argc, argv, opt, &arg);
12233 if (NIL_P(arg.io)) return Qnil;
12234 extract_getline_opts(opt, &garg);
12235 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12236 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12237}
12238
12239static VALUE
12240io_s_read(VALUE v)
12241{
12242 struct foreach_arg *arg = (void *)v;
12243 return io_read(arg->argc, arg->argv, arg->io);
12244}
12245
12246struct seek_arg {
12247 VALUE io;
12248 VALUE offset;
12249 int mode;
12250};
12251
12252static VALUE
12253seek_before_access(VALUE argp)
12254{
12255 struct seek_arg *arg = (struct seek_arg *)argp;
12256 rb_io_binmode(arg->io);
12257 return rb_io_seek(arg->io, arg->offset, arg->mode);
12258}
12259
12260/*
12261 * call-seq:
12262 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12263 *
12264 * Opens the stream, reads and returns some or all of its content,
12265 * and closes the stream; returns +nil+ if no bytes were read.
12266 *
12267 * The first argument must be a string that is the path to a file.
12268 *
12269 * With only argument +path+ given, reads in text mode and returns the entire content
12270 * of the file at the given path:
12271 *
12272 * File.read('t.txt')
12273 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
12274 * File.read('t.ja')
12275 * # => "こんにちは"
12276 * File.read('t.dat')
12277 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12278 *
12279 * On Windows, text mode can terminate reading and leave bytes in the file
12280 * unread when encountering certain special bytes. Consider using
12281 * IO.binread if all bytes in the file should be read.
12282 *
12283 * With argument +length+, returns +length+ bytes if available:
12284 *
12285 * File.read('t.txt', 7)
12286 * # => "First l"
12287 * File.read('t.ja', 7)
12288 * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
12289 * File.read('t.dat', 7)
12290 * # => "\xFE\xFF\x99\x90\x99\x91\x99"
12291 *
12292 * Returns all bytes if +length+ is larger than the files size:
12293 *
12294 * File.read('t.txt', 700)
12295 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12296 * File.read('t.ja', 700)
12297 * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
12298 * File.read('t.dat', 700)
12299 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12300 *
12301 * With arguments +length+ and +offset+, returns +length+ bytes
12302 * if available, beginning at the given +offset+:
12303 *
12304 * File.read('t.txt', 10, 2)
12305 * # => "rst line\r\n"
12306 * File.read('t.ja', 10, 2)
12307 * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
12308 * File.read('t.dat', 10, 2)
12309 * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12310 *
12311 * Returns +nil+ if +offset+ is past the end of the stream:
12312 *
12313 * File.read('t.txt', 10, 200)
12314 * # => nil
12315 *
12316 * Optional keyword arguments +opts+ specify:
12317 *
12318 * - {Open Options}[rdoc-ref:IO@Open+Options].
12319 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12320 *
12321 */
12322
12323static VALUE
12324rb_io_s_read(int argc, VALUE *argv, VALUE io)
12325{
12326 VALUE opt, offset;
12327 long off;
12328 struct foreach_arg arg;
12329
12330 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12331 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12332 rb_raise(rb_eArgError, "negative offset %ld given", off);
12333 }
12334 open_key_args(io, argc, argv, opt, &arg);
12335 if (NIL_P(arg.io)) return Qnil;
12336 if (!NIL_P(offset)) {
12337 struct seek_arg sarg;
12338 int state = 0;
12339 sarg.io = arg.io;
12340 sarg.offset = offset;
12341 sarg.mode = SEEK_SET;
12342 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12343 if (state) {
12344 rb_io_close(arg.io);
12345 rb_jump_tag(state);
12346 }
12347 if (arg.argc == 2) arg.argc = 1;
12348 }
12349 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12350}
12351
12352/*
12353 * call-seq:
12354 * IO.binread(path, length = nil, offset = 0) -> string or nil
12355 *
12356 * Behaves like IO.read, except that the stream is opened in binary mode
12357 * with ASCII-8BIT encoding.
12358 *
12359 */
12360
12361static VALUE
12362rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12363{
12364 VALUE offset;
12365 struct foreach_arg arg;
12366 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12367 enum {
12368 oflags = O_RDONLY
12369#ifdef O_BINARY
12370 |O_BINARY
12371#endif
12372 };
12373 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12374
12375 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12376 FilePathValue(argv[0]);
12377 convconfig.enc = rb_ascii8bit_encoding();
12378 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12379 if (NIL_P(arg.io)) return Qnil;
12380 arg.argv = argv+1;
12381 arg.argc = (argc > 1) ? 1 : 0;
12382 if (!NIL_P(offset)) {
12383 struct seek_arg sarg;
12384 int state = 0;
12385 sarg.io = arg.io;
12386 sarg.offset = offset;
12387 sarg.mode = SEEK_SET;
12388 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12389 if (state) {
12390 rb_io_close(arg.io);
12391 rb_jump_tag(state);
12392 }
12393 }
12394 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12395}
12396
12397static VALUE
12398io_s_write0(VALUE v)
12399{
12400 struct write_arg *arg = (void *)v;
12401 return io_write(arg->io,arg->str,arg->nosync);
12402}
12403
12404static VALUE
12405io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12406{
12407 VALUE string, offset, opt;
12408 struct foreach_arg arg;
12409 struct write_arg warg;
12410
12411 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12412
12413 if (NIL_P(opt)) opt = rb_hash_new();
12414 else opt = rb_hash_dup(opt);
12415
12416
12417 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12418 int mode = O_WRONLY|O_CREAT;
12419#ifdef O_BINARY
12420 if (binary) mode |= O_BINARY;
12421#endif
12422 if (NIL_P(offset)) mode |= O_TRUNC;
12423 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12424 }
12425 open_key_args(klass, argc, argv, opt, &arg);
12426
12427#ifndef O_BINARY
12428 if (binary) rb_io_binmode_m(arg.io);
12429#endif
12430
12431 if (NIL_P(arg.io)) return Qnil;
12432 if (!NIL_P(offset)) {
12433 struct seek_arg sarg;
12434 int state = 0;
12435 sarg.io = arg.io;
12436 sarg.offset = offset;
12437 sarg.mode = SEEK_SET;
12438 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12439 if (state) {
12440 rb_io_close(arg.io);
12441 rb_jump_tag(state);
12442 }
12443 }
12444
12445 warg.io = arg.io;
12446 warg.str = string;
12447 warg.nosync = 0;
12448
12449 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12450}
12451
12452/*
12453 * call-seq:
12454 * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
12455 *
12456 * Opens the stream, writes the given +data+ to it,
12457 * and closes the stream; returns the number of bytes written.
12458 *
12459 * The first argument must be a string that is the path to a file.
12460 *
12461 * With only arguments +path+ and +data+ given,
12462 * writes the given data to the file at that path:
12463 *
12464 * path = 't.tmp'
12465 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
12466 * File.write(path, 'こんにちは') # => 15
12467 * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
12468 *
12469 * When +offset+ is zero (the default), the entire file content is overwritten:
12470 *
12471 * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12472 * File.write(path, 'foo')
12473 * File.read(path) # => "foo"
12474 *
12475 * When +offset+ in within the file content, the file content is partly overwritten,
12476 * beginning at byte +offset+:
12477 *
12478 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12479 * File.write(path, 'LINE', 6)
12480 * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
12481 *
12482 * When the file contains multi-byte characters,
12483 * the effect of writing may disturb some characters:
12484 *
12485 * File.write(path, "こんにちは")
12486 * File.write(path, 'FOO', 3) # Replace one 3-byte character.
12487 * File.read(path) # => "こFOOにちは"
12488 * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
12489 * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
12490 *
12491 * If +offset+ is outside the file content,
12492 * the file is padded with null characters <tt>"\u0000"</tt>:
12493 *
12494 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12495 * File.write(path, 'FOO', 55)
12496 * File.read(path)
12497 * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
12498 *
12499 * Optional keyword arguments +opts+ specify:
12500 *
12501 * - {Open Options}[rdoc-ref:IO@Open+Options].
12502 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12503 *
12504 */
12505
12506static VALUE
12507rb_io_s_write(int argc, VALUE *argv, VALUE io)
12508{
12509 return io_s_write(argc, argv, io, 0);
12510}
12511
12512/*
12513 * call-seq:
12514 * IO.binwrite(path, string, offset = 0, **opts) -> integer
12515 *
12516 * Behaves like IO.write, except that the stream is opened in binary mode
12517 * with ASCII-8BIT encoding.
12518 *
12519 */
12520
12521static VALUE
12522rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12523{
12524 return io_s_write(argc, argv, io, 1);
12525}
12526
12528 VALUE src;
12529 VALUE dst;
12530 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12531 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12532
12533 rb_io_t *src_fptr;
12534 rb_io_t *dst_fptr;
12535 unsigned close_src : 1;
12536 unsigned close_dst : 1;
12537 int error_no;
12538 rb_off_t total;
12539 const char *syserr;
12540 const char *notimp;
12541 VALUE th;
12542 struct stat src_stat;
12543 struct stat dst_stat;
12544#ifdef HAVE_FCOPYFILE
12545 copyfile_state_t copyfile_state;
12546#endif
12547};
12548
12549static void *
12550exec_interrupts(void *arg)
12551{
12552 VALUE th = (VALUE)arg;
12553 rb_thread_execute_interrupts(th);
12554 return NULL;
12555}
12556
12557/*
12558 * returns TRUE if the preceding system call was interrupted
12559 * so we can continue. If the thread was interrupted, we
12560 * reacquire the GVL to execute interrupts before continuing.
12561 */
12562static int
12563maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12564{
12565 switch (errno) {
12566 case EINTR:
12567#if defined(ERESTART)
12568 case ERESTART:
12569#endif
12570 if (rb_thread_interrupted(stp->th)) {
12571 if (has_gvl)
12572 rb_thread_execute_interrupts(stp->th);
12573 else
12574 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12575 }
12576 return TRUE;
12577 }
12578 return FALSE;
12579}
12580
12582 VALUE scheduler;
12583
12584 rb_io_t *fptr;
12585 short events;
12586
12587 VALUE result;
12588};
12589
12590static void *
12591fiber_scheduler_wait_for(void * _arguments)
12592{
12593 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12594
12595 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12596
12597 return NULL;
12598}
12599
12600#if USE_POLL
12601# define IOWAIT_SYSCALL "poll"
12602STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12603STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12604static int
12605nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12606{
12608 if (scheduler != Qnil) {
12609 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12610 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12611 return RTEST(args.result);
12612 }
12613
12614 int fd = fptr->fd;
12615 if (fd == -1) return 0;
12616
12617 struct pollfd fds;
12618
12619 fds.fd = fd;
12620 fds.events = events;
12621
12622 int timeout_milliseconds = -1;
12623
12624 if (timeout) {
12625 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12626 }
12627
12628 return poll(&fds, 1, timeout_milliseconds);
12629}
12630#else /* !USE_POLL */
12631# define IOWAIT_SYSCALL "select"
12632static int
12633nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12634{
12636 if (scheduler != Qnil) {
12637 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12638 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12639 return RTEST(args.result);
12640 }
12641
12642 int fd = fptr->fd;
12643
12644 if (fd == -1) {
12645 errno = EBADF;
12646 return -1;
12647 }
12648
12649 rb_fdset_t fds;
12650 int ret;
12651
12652 rb_fd_init(&fds);
12653 rb_fd_set(fd, &fds);
12654
12655 switch (events) {
12656 case RB_WAITFD_IN:
12657 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12658 break;
12659 case RB_WAITFD_OUT:
12660 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12661 break;
12662 default:
12663 VM_UNREACHABLE(nogvl_wait_for);
12664 }
12665
12666 rb_fd_term(&fds);
12667
12668 // On timeout, this returns 0.
12669 return ret;
12670}
12671#endif /* !USE_POLL */
12672
12673static int
12674maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12675{
12676 int ret;
12677
12678 do {
12679 if (has_gvl) {
12681 }
12682 else {
12683 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12684 }
12685 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12686
12687 if (ret < 0) {
12688 stp->syserr = IOWAIT_SYSCALL;
12689 stp->error_no = errno;
12690 return ret;
12691 }
12692 return 0;
12693}
12694
12695static int
12696nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12697{
12698 int ret;
12699
12700 do {
12701 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12702 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12703
12704 if (ret < 0) {
12705 stp->syserr = IOWAIT_SYSCALL;
12706 stp->error_no = errno;
12707 return ret;
12708 }
12709 return 0;
12710}
12711
12712#ifdef USE_COPY_FILE_RANGE
12713
12714static ssize_t
12715simple_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)
12716{
12717#ifdef HAVE_COPY_FILE_RANGE
12718 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12719#else
12720 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12721#endif
12722}
12723
12724static int
12725nogvl_copy_file_range(struct copy_stream_struct *stp)
12726{
12727 ssize_t ss;
12728 rb_off_t src_size;
12729 rb_off_t copy_length, src_offset, *src_offset_ptr;
12730
12731 if (!S_ISREG(stp->src_stat.st_mode))
12732 return 0;
12733
12734 src_size = stp->src_stat.st_size;
12735 src_offset = stp->src_offset;
12736 if (src_offset >= (rb_off_t)0) {
12737 src_offset_ptr = &src_offset;
12738 }
12739 else {
12740 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12741 }
12742
12743 copy_length = stp->copy_length;
12744 if (copy_length < (rb_off_t)0) {
12745 if (src_offset < (rb_off_t)0) {
12746 rb_off_t current_offset;
12747 errno = 0;
12748 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12749 if (current_offset < (rb_off_t)0 && errno) {
12750 stp->syserr = "lseek";
12751 stp->error_no = errno;
12752 return (int)current_offset;
12753 }
12754 copy_length = src_size - current_offset;
12755 }
12756 else {
12757 copy_length = src_size - src_offset;
12758 }
12759 }
12760
12761 retry_copy_file_range:
12762# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12763 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12764 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12765# else
12766 ss = (ssize_t)copy_length;
12767# endif
12768 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12769 if (0 < ss) {
12770 stp->total += ss;
12771 copy_length -= ss;
12772 if (0 < copy_length) {
12773 goto retry_copy_file_range;
12774 }
12775 }
12776 if (ss < 0) {
12777 if (maygvl_copy_stream_continue_p(0, stp)) {
12778 goto retry_copy_file_range;
12779 }
12780 switch (errno) {
12781 case EINVAL:
12782 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12783 docker container) */
12784#ifdef ENOSYS
12785 case ENOSYS:
12786#endif
12787#ifdef EXDEV
12788 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12789#endif
12790 return 0;
12791 case EAGAIN:
12792#if EWOULDBLOCK != EAGAIN
12793 case EWOULDBLOCK:
12794#endif
12795 {
12796 int ret = nogvl_copy_stream_wait_write(stp);
12797 if (ret < 0) return ret;
12798 }
12799 goto retry_copy_file_range;
12800 case EBADF:
12801 {
12802 int e = errno;
12803 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12804
12805 if (flags != -1 && flags & O_APPEND) {
12806 return 0;
12807 }
12808 errno = e;
12809 }
12810 }
12811 stp->syserr = "copy_file_range";
12812 stp->error_no = errno;
12813 return (int)ss;
12814 }
12815 return 1;
12816}
12817#endif
12818
12819#ifdef HAVE_FCOPYFILE
12820static int
12821nogvl_fcopyfile(struct copy_stream_struct *stp)
12822{
12823 rb_off_t cur, ss = 0;
12824 const rb_off_t src_offset = stp->src_offset;
12825 int ret;
12826
12827 if (stp->copy_length >= (rb_off_t)0) {
12828 /* copy_length can't be specified in fcopyfile(3) */
12829 return 0;
12830 }
12831
12832 if (!S_ISREG(stp->src_stat.st_mode))
12833 return 0;
12834
12835 if (!S_ISREG(stp->dst_stat.st_mode))
12836 return 0;
12837 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12838 return 0;
12839 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12840 /* fcopyfile(3) appends src IO to dst IO and then truncates
12841 * dst IO to src IO's original size. */
12842 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12843 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12844 if (end > (rb_off_t)0) return 0;
12845 }
12846
12847 if (src_offset > (rb_off_t)0) {
12848 rb_off_t r;
12849
12850 /* get current offset */
12851 errno = 0;
12852 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12853 if (cur < (rb_off_t)0 && errno) {
12854 stp->error_no = errno;
12855 return 1;
12856 }
12857
12858 errno = 0;
12859 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12860 if (r < (rb_off_t)0 && errno) {
12861 stp->error_no = errno;
12862 return 1;
12863 }
12864 }
12865
12866 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12867 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12868 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12869
12870 if (ret == 0) { /* success */
12871 stp->total = ss;
12872 if (src_offset > (rb_off_t)0) {
12873 rb_off_t r;
12874 errno = 0;
12875 /* reset offset */
12876 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12877 if (r < (rb_off_t)0 && errno) {
12878 stp->error_no = errno;
12879 return 1;
12880 }
12881 }
12882 }
12883 else {
12884 switch (errno) {
12885 case ENOTSUP:
12886 case EPERM:
12887 case EINVAL:
12888 return 0;
12889 }
12890 stp->syserr = "fcopyfile";
12891 stp->error_no = errno;
12892 return (int)ret;
12893 }
12894 return 1;
12895}
12896#endif
12897
12898#ifdef HAVE_SENDFILE
12899
12900# ifdef __linux__
12901# define USE_SENDFILE
12902
12903# ifdef HAVE_SYS_SENDFILE_H
12904# include <sys/sendfile.h>
12905# endif
12906
12907static ssize_t
12908simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12909{
12910 return sendfile(out_fd, in_fd, offset, (size_t)count);
12911}
12912
12913# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12914/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12915 * without cpuset -l 0.
12916 */
12917# define USE_SENDFILE
12918
12919static ssize_t
12920simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12921{
12922 int r;
12923 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12924 rb_off_t sbytes;
12925# ifdef __APPLE__
12926 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12927 sbytes = count;
12928# else
12929 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12930# endif
12931 if (r != 0 && sbytes == 0) return r;
12932 if (offset) {
12933 *offset += sbytes;
12934 }
12935 else {
12936 lseek(in_fd, sbytes, SEEK_CUR);
12937 }
12938 return (ssize_t)sbytes;
12939}
12940
12941# endif
12942
12943#endif
12944
12945#ifdef USE_SENDFILE
12946static int
12947nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12948{
12949 ssize_t ss;
12950 rb_off_t src_size;
12951 rb_off_t copy_length;
12952 rb_off_t src_offset;
12953 int use_pread;
12954
12955 if (!S_ISREG(stp->src_stat.st_mode))
12956 return 0;
12957
12958 src_size = stp->src_stat.st_size;
12959#ifndef __linux__
12960 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12961 return 0;
12962#endif
12963
12964 src_offset = stp->src_offset;
12965 use_pread = src_offset >= (rb_off_t)0;
12966
12967 copy_length = stp->copy_length;
12968 if (copy_length < (rb_off_t)0) {
12969 if (use_pread)
12970 copy_length = src_size - src_offset;
12971 else {
12972 rb_off_t cur;
12973 errno = 0;
12974 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12975 if (cur < (rb_off_t)0 && errno) {
12976 stp->syserr = "lseek";
12977 stp->error_no = errno;
12978 return (int)cur;
12979 }
12980 copy_length = src_size - cur;
12981 }
12982 }
12983
12984 retry_sendfile:
12985# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12986 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12987 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12988# else
12989 ss = (ssize_t)copy_length;
12990# endif
12991 if (use_pread) {
12992 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12993 }
12994 else {
12995 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12996 }
12997 if (0 < ss) {
12998 stp->total += ss;
12999 copy_length -= ss;
13000 if (0 < copy_length) {
13001 goto retry_sendfile;
13002 }
13003 }
13004 if (ss < 0) {
13005 if (maygvl_copy_stream_continue_p(0, stp))
13006 goto retry_sendfile;
13007 switch (errno) {
13008 case EINVAL:
13009#ifdef ENOSYS
13010 case ENOSYS:
13011#endif
13012#ifdef EOPNOTSUP
13013 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
13014 see also: [Feature #16965] */
13015 case EOPNOTSUP:
13016#endif
13017 return 0;
13018 case EAGAIN:
13019#if EWOULDBLOCK != EAGAIN
13020 case EWOULDBLOCK:
13021#endif
13022 {
13023 int ret;
13024#ifndef __linux__
13025 /*
13026 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13027 * select() reports regular files to always be "ready", so
13028 * there is no need to select() on it.
13029 * Other OSes may have the same limitation for sendfile() which
13030 * allow us to bypass maygvl_copy_stream_wait_read()...
13031 */
13032 ret = maygvl_copy_stream_wait_read(0, stp);
13033 if (ret < 0) return ret;
13034#endif
13035 ret = nogvl_copy_stream_wait_write(stp);
13036 if (ret < 0) return ret;
13037 }
13038 goto retry_sendfile;
13039 }
13040 stp->syserr = "sendfile";
13041 stp->error_no = errno;
13042 return (int)ss;
13043 }
13044 return 1;
13045}
13046#endif
13047
13048static ssize_t
13049maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13050{
13051 if (has_gvl)
13052 return rb_io_read_memory(fptr, buf, count);
13053 else
13054 return read(fptr->fd, buf, count);
13055}
13056
13057static ssize_t
13058maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13059{
13060 ssize_t ss;
13061 retry_read:
13062 if (offset < (rb_off_t)0) {
13063 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13064 }
13065 else {
13066 ss = pread(stp->src_fptr->fd, buf, len, offset);
13067 }
13068 if (ss == 0) {
13069 return 0;
13070 }
13071 if (ss < 0) {
13072 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13073 goto retry_read;
13074 switch (errno) {
13075 case EAGAIN:
13076#if EWOULDBLOCK != EAGAIN
13077 case EWOULDBLOCK:
13078#endif
13079 {
13080 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13081 if (ret < 0) return ret;
13082 }
13083 goto retry_read;
13084#ifdef ENOSYS
13085 case ENOSYS:
13086 stp->notimp = "pread";
13087 return ss;
13088#endif
13089 }
13090 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13091 stp->error_no = errno;
13092 }
13093 return ss;
13094}
13095
13096static int
13097nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13098{
13099 ssize_t ss;
13100 int off = 0;
13101 while (len) {
13102 ss = write(stp->dst_fptr->fd, buf+off, len);
13103 if (ss < 0) {
13104 if (maygvl_copy_stream_continue_p(0, stp))
13105 continue;
13106 if (io_again_p(errno)) {
13107 int ret = nogvl_copy_stream_wait_write(stp);
13108 if (ret < 0) return ret;
13109 continue;
13110 }
13111 stp->syserr = "write";
13112 stp->error_no = errno;
13113 return (int)ss;
13114 }
13115 off += (int)ss;
13116 len -= (int)ss;
13117 stp->total += ss;
13118 }
13119 return 0;
13120}
13121
13122static void
13123nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13124{
13125 char buf[1024*16];
13126 size_t len;
13127 ssize_t ss;
13128 int ret;
13129 rb_off_t copy_length;
13130 rb_off_t src_offset;
13131 int use_eof;
13132 int use_pread;
13133
13134 copy_length = stp->copy_length;
13135 use_eof = copy_length < (rb_off_t)0;
13136 src_offset = stp->src_offset;
13137 use_pread = src_offset >= (rb_off_t)0;
13138
13139 if (use_pread && stp->close_src) {
13140 rb_off_t r;
13141 errno = 0;
13142 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13143 if (r < (rb_off_t)0 && errno) {
13144 stp->syserr = "lseek";
13145 stp->error_no = errno;
13146 return;
13147 }
13148 src_offset = (rb_off_t)-1;
13149 use_pread = 0;
13150 }
13151
13152 while (use_eof || 0 < copy_length) {
13153 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13154 len = (size_t)copy_length;
13155 }
13156 else {
13157 len = sizeof(buf);
13158 }
13159 if (use_pread) {
13160 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13161 if (0 < ss)
13162 src_offset += ss;
13163 }
13164 else {
13165 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13166 }
13167 if (ss <= 0) /* EOF or error */
13168 return;
13169
13170 ret = nogvl_copy_stream_write(stp, buf, ss);
13171 if (ret < 0)
13172 return;
13173
13174 if (!use_eof)
13175 copy_length -= ss;
13176 }
13177}
13178
13179static void *
13180nogvl_copy_stream_func(void *arg)
13181{
13182 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13183#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13184 int ret;
13185#endif
13186
13187#ifdef USE_COPY_FILE_RANGE
13188 ret = nogvl_copy_file_range(stp);
13189 if (ret != 0)
13190 goto finish; /* error or success */
13191#endif
13192
13193#ifdef HAVE_FCOPYFILE
13194 ret = nogvl_fcopyfile(stp);
13195 if (ret != 0)
13196 goto finish; /* error or success */
13197#endif
13198
13199#ifdef USE_SENDFILE
13200 ret = nogvl_copy_stream_sendfile(stp);
13201 if (ret != 0)
13202 goto finish; /* error or success */
13203#endif
13204
13205 nogvl_copy_stream_read_write(stp);
13206
13207#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13208 finish:
13209#endif
13210 return 0;
13211}
13212
13213static VALUE
13214copy_stream_fallback_body(VALUE arg)
13215{
13216 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13217 const int buflen = 16*1024;
13218 VALUE n;
13219 VALUE buf = rb_str_buf_new(buflen);
13220 rb_off_t rest = stp->copy_length;
13221 rb_off_t off = stp->src_offset;
13222 ID read_method = id_readpartial;
13223
13224 if (!stp->src_fptr) {
13225 if (!rb_respond_to(stp->src, read_method)) {
13226 read_method = id_read;
13227 }
13228 }
13229
13230 while (1) {
13231 long numwrote;
13232 long l;
13233 rb_str_make_independent(buf);
13234 if (stp->copy_length < (rb_off_t)0) {
13235 l = buflen;
13236 }
13237 else {
13238 if (rest == 0) {
13239 rb_str_resize(buf, 0);
13240 break;
13241 }
13242 l = buflen < rest ? buflen : (long)rest;
13243 }
13244 if (!stp->src_fptr) {
13245 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13246
13247 if (read_method == id_read && NIL_P(rc))
13248 break;
13249 }
13250 else {
13251 ssize_t ss;
13252 rb_str_resize(buf, buflen);
13253 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13254 rb_str_resize(buf, ss > 0 ? ss : 0);
13255 if (ss < 0)
13256 return Qnil;
13257 if (ss == 0)
13258 rb_eof_error();
13259 if (off >= (rb_off_t)0)
13260 off += ss;
13261 }
13262 n = rb_io_write(stp->dst, buf);
13263 numwrote = NUM2LONG(n);
13264 stp->total += numwrote;
13265 rest -= numwrote;
13266 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13267 break;
13268 }
13269 }
13270
13271 return Qnil;
13272}
13273
13274static VALUE
13275copy_stream_fallback(struct copy_stream_struct *stp)
13276{
13277 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13278 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13279 }
13280 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13281 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13282 rb_eEOFError, (VALUE)0);
13283 return Qnil;
13284}
13285
13286static VALUE
13287copy_stream_body(VALUE arg)
13288{
13289 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13290 VALUE src_io = stp->src, dst_io = stp->dst;
13291 const int common_oflags = 0
13292#ifdef O_NOCTTY
13293 | O_NOCTTY
13294#endif
13295 ;
13296
13297 stp->th = rb_thread_current();
13298
13299 stp->total = 0;
13300
13301 if (src_io == argf ||
13302 !(RB_TYPE_P(src_io, T_FILE) ||
13303 RB_TYPE_P(src_io, T_STRING) ||
13304 rb_respond_to(src_io, rb_intern("to_path")))) {
13305 stp->src_fptr = NULL;
13306 }
13307 else {
13308 int stat_ret;
13309 VALUE tmp_io = rb_io_check_io(src_io);
13310 if (!NIL_P(tmp_io)) {
13311 src_io = tmp_io;
13312 }
13313 else if (!RB_TYPE_P(src_io, T_FILE)) {
13314 VALUE args[2];
13315 FilePathValue(src_io);
13316 args[0] = src_io;
13317 args[1] = INT2NUM(O_RDONLY|common_oflags);
13318 src_io = rb_class_new_instance(2, args, rb_cFile);
13319 stp->src = src_io;
13320 stp->close_src = 1;
13321 }
13322 RB_IO_POINTER(src_io, stp->src_fptr);
13323 rb_io_check_byte_readable(stp->src_fptr);
13324
13325 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13326 if (stat_ret < 0) {
13327 stp->syserr = "fstat";
13328 stp->error_no = errno;
13329 return Qnil;
13330 }
13331 }
13332
13333 if (dst_io == argf ||
13334 !(RB_TYPE_P(dst_io, T_FILE) ||
13335 RB_TYPE_P(dst_io, T_STRING) ||
13336 rb_respond_to(dst_io, rb_intern("to_path")))) {
13337 stp->dst_fptr = NULL;
13338 }
13339 else {
13340 int stat_ret;
13341 VALUE tmp_io = rb_io_check_io(dst_io);
13342 if (!NIL_P(tmp_io)) {
13343 dst_io = GetWriteIO(tmp_io);
13344 }
13345 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13346 VALUE args[3];
13347 FilePathValue(dst_io);
13348 args[0] = dst_io;
13349 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13350 args[2] = INT2FIX(0666);
13351 dst_io = rb_class_new_instance(3, args, rb_cFile);
13352 stp->dst = dst_io;
13353 stp->close_dst = 1;
13354 }
13355 else {
13356 dst_io = GetWriteIO(dst_io);
13357 stp->dst = dst_io;
13358 }
13359 RB_IO_POINTER(dst_io, stp->dst_fptr);
13360 rb_io_check_writable(stp->dst_fptr);
13361
13362 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13363 if (stat_ret < 0) {
13364 stp->syserr = "fstat";
13365 stp->error_no = errno;
13366 return Qnil;
13367 }
13368 }
13369
13370#ifdef O_BINARY
13371 if (stp->src_fptr)
13372 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13373#endif
13374 if (stp->dst_fptr)
13375 io_ascii8bit_binmode(stp->dst_fptr);
13376
13377 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13378 size_t len = stp->src_fptr->rbuf.len;
13379 VALUE str;
13380 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13381 len = (size_t)stp->copy_length;
13382 }
13383 str = rb_str_buf_new(len);
13384 rb_str_resize(str,len);
13385 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13386 if (stp->dst_fptr) { /* IO or filename */
13387 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13388 rb_sys_fail_on_write(stp->dst_fptr);
13389 }
13390 else /* others such as StringIO */
13391 rb_io_write(dst_io, str);
13392 rb_str_resize(str, 0);
13393 stp->total += len;
13394 if (stp->copy_length >= (rb_off_t)0)
13395 stp->copy_length -= len;
13396 }
13397
13398 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13399 rb_raise(rb_eIOError, "flush failed");
13400 }
13401
13402 if (stp->copy_length == 0)
13403 return Qnil;
13404
13405 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13406 return copy_stream_fallback(stp);
13407 }
13408
13409 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13410 return Qnil;
13411}
13412
13413static VALUE
13414copy_stream_finalize(VALUE arg)
13415{
13416 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13417
13418#ifdef HAVE_FCOPYFILE
13419 if (stp->copyfile_state) {
13420 copyfile_state_free(stp->copyfile_state);
13421 }
13422#endif
13423
13424 if (stp->close_src) {
13425 rb_io_close_m(stp->src);
13426 }
13427 if (stp->close_dst) {
13428 rb_io_close_m(stp->dst);
13429 }
13430 if (stp->syserr) {
13431 rb_syserr_fail(stp->error_no, stp->syserr);
13432 }
13433 if (stp->notimp) {
13434 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13435 }
13436 return Qnil;
13437}
13438
13439/*
13440 * call-seq:
13441 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13442 *
13443 * Copies from the given +src+ to the given +dst+,
13444 * returning the number of bytes copied.
13445 *
13446 * - The given +src+ must be one of the following:
13447 *
13448 * - The path to a readable file, from which source data is to be read.
13449 * - An \IO-like object, opened for reading and capable of responding
13450 * to method +:readpartial+ or method +:read+.
13451 *
13452 * - The given +dst+ must be one of the following:
13453 *
13454 * - The path to a writable file, to which data is to be written.
13455 * - An \IO-like object, opened for writing and capable of responding
13456 * to method +:write+.
13457 *
13458 * The examples here use file <tt>t.txt</tt> as source:
13459 *
13460 * File.read('t.txt')
13461 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13462 * File.read('t.txt').size # => 47
13463 *
13464 * If only arguments +src+ and +dst+ are given,
13465 * the entire source stream is copied:
13466 *
13467 * # Paths.
13468 * IO.copy_stream('t.txt', 't.tmp') # => 47
13469 *
13470 * # IOs (recall that a File is also an IO).
13471 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13472 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13473 * IO.copy_stream(src_io, dst_io) # => 47
13474 * src_io.close
13475 * dst_io.close
13476 *
13477 * With argument +src_length+ a non-negative integer,
13478 * no more than that many bytes are copied:
13479 *
13480 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13481 * File.read('t.tmp') # => "First line"
13482 *
13483 * With argument +src_offset+ also given,
13484 * the source stream is read beginning at that offset:
13485 *
13486 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13487 * IO.read('t.tmp') # => "Second line"
13488 *
13489 */
13490static VALUE
13491rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13492{
13493 VALUE src, dst, length, src_offset;
13494 struct copy_stream_struct st;
13495
13496 MEMZERO(&st, struct copy_stream_struct, 1);
13497
13498 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13499
13500 st.src = src;
13501 st.dst = dst;
13502
13503 st.src_fptr = NULL;
13504 st.dst_fptr = NULL;
13505
13506 if (NIL_P(length))
13507 st.copy_length = (rb_off_t)-1;
13508 else
13509 st.copy_length = NUM2OFFT(length);
13510
13511 if (NIL_P(src_offset))
13512 st.src_offset = (rb_off_t)-1;
13513 else
13514 st.src_offset = NUM2OFFT(src_offset);
13515
13516 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13517
13518 return OFFT2NUM(st.total);
13519}
13520
13521/*
13522 * call-seq:
13523 * external_encoding -> encoding or nil
13524 *
13525 * Returns the Encoding object that represents the encoding of the stream,
13526 * or +nil+ if the stream is in write mode and no encoding is specified.
13527 *
13528 * See {Encodings}[rdoc-ref:File@Encodings].
13529 *
13530 */
13531
13532static VALUE
13533rb_io_external_encoding(VALUE io)
13534{
13535 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13536
13537 if (fptr->encs.enc2) {
13538 return rb_enc_from_encoding(fptr->encs.enc2);
13539 }
13540 if (fptr->mode & FMODE_WRITABLE) {
13541 if (fptr->encs.enc)
13542 return rb_enc_from_encoding(fptr->encs.enc);
13543 return Qnil;
13544 }
13545 return rb_enc_from_encoding(io_read_encoding(fptr));
13546}
13547
13548/*
13549 * call-seq:
13550 * internal_encoding -> encoding or nil
13551 *
13552 * Returns the Encoding object that represents the encoding of the internal string,
13553 * if conversion is specified,
13554 * or +nil+ otherwise.
13555 *
13556 * See {Encodings}[rdoc-ref:File@Encodings].
13557 *
13558 */
13559
13560static VALUE
13561rb_io_internal_encoding(VALUE io)
13562{
13563 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13564
13565 if (!fptr->encs.enc2) return Qnil;
13566 return rb_enc_from_encoding(io_read_encoding(fptr));
13567}
13568
13569/*
13570 * call-seq:
13571 * set_encoding(ext_enc) -> self
13572 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13573 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13574 *
13575 * See {Encodings}[rdoc-ref:File@Encodings].
13576 *
13577 * Argument +ext_enc+, if given, must be an Encoding object
13578 * or a String with the encoding name;
13579 * it is assigned as the encoding for the stream.
13580 *
13581 * Argument +int_enc+, if given, must be an Encoding object
13582 * or a String with the encoding name;
13583 * it is assigned as the encoding for the internal string.
13584 *
13585 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13586 * containing two colon-separated encoding names;
13587 * corresponding Encoding objects are assigned as the external
13588 * and internal encodings for the stream.
13589 *
13590 * If the external encoding of a string is binary/ASCII-8BIT,
13591 * the internal encoding of the string is set to nil, since no
13592 * transcoding is needed.
13593 *
13594 * Optional keyword arguments +enc_opts+ specify
13595 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13596 *
13597 */
13598
13599static VALUE
13600rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13601{
13602 rb_io_t *fptr;
13603 VALUE v1, v2, opt;
13604
13605 if (!RB_TYPE_P(io, T_FILE)) {
13606 return forward(io, id_set_encoding, argc, argv);
13607 }
13608
13609 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13610 GetOpenFile(io, fptr);
13611 io_encoding_set(fptr, v1, v2, opt);
13612 return io;
13613}
13614
13615void
13616rb_stdio_set_default_encoding(void)
13617{
13618 VALUE val = Qnil;
13619
13620#ifdef _WIN32
13621 if (isatty(fileno(stdin))) {
13622 rb_encoding *external = rb_locale_encoding();
13623 rb_encoding *internal = rb_default_internal_encoding();
13624 if (!internal) internal = rb_default_external_encoding();
13625 io_encoding_set(RFILE(rb_stdin)->fptr,
13626 rb_enc_from_encoding(external),
13627 rb_enc_from_encoding(internal),
13628 Qnil);
13629 }
13630 else
13631#endif
13632 rb_io_set_encoding(1, &val, rb_stdin);
13633 rb_io_set_encoding(1, &val, rb_stdout);
13634 rb_io_set_encoding(1, &val, rb_stderr);
13635}
13636
13637static inline int
13638global_argf_p(VALUE arg)
13639{
13640 return arg == argf;
13641}
13642
13643typedef VALUE (*argf_encoding_func)(VALUE io);
13644
13645static VALUE
13646argf_encoding(VALUE argf, argf_encoding_func func)
13647{
13648 if (!RTEST(ARGF.current_file)) {
13649 return rb_enc_default_external();
13650 }
13651 return func(rb_io_check_io(ARGF.current_file));
13652}
13653
13654/*
13655 * call-seq:
13656 * ARGF.external_encoding -> encoding
13657 *
13658 * Returns the external encoding for files read from ARGF as an Encoding
13659 * object. The external encoding is the encoding of the text as stored in a
13660 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13661 * represent this text within Ruby.
13662 *
13663 * To set the external encoding use ARGF.set_encoding.
13664 *
13665 * For example:
13666 *
13667 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13668 *
13669 */
13670static VALUE
13671argf_external_encoding(VALUE argf)
13672{
13673 return argf_encoding(argf, rb_io_external_encoding);
13674}
13675
13676/*
13677 * call-seq:
13678 * ARGF.internal_encoding -> encoding
13679 *
13680 * Returns the internal encoding for strings read from ARGF as an
13681 * Encoding object.
13682 *
13683 * If ARGF.set_encoding has been called with two encoding names, the second
13684 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13685 * value is returned. Failing that, if a default external encoding was
13686 * specified on the command-line, that value is used. If the encoding is
13687 * unknown, +nil+ is returned.
13688 */
13689static VALUE
13690argf_internal_encoding(VALUE argf)
13691{
13692 return argf_encoding(argf, rb_io_internal_encoding);
13693}
13694
13695/*
13696 * call-seq:
13697 * ARGF.set_encoding(ext_enc) -> ARGF
13698 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13699 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13700 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13701 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13702 *
13703 * If single argument is specified, strings read from ARGF are tagged with
13704 * the encoding specified.
13705 *
13706 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13707 * the read string is converted from the first encoding (external encoding)
13708 * to the second encoding (internal encoding), then tagged with the second
13709 * encoding.
13710 *
13711 * If two arguments are specified, they must be encoding objects or encoding
13712 * names. Again, the first specifies the external encoding; the second
13713 * specifies the internal encoding.
13714 *
13715 * If the external encoding and the internal encoding are specified, the
13716 * optional Hash argument can be used to adjust the conversion process. The
13717 * structure of this hash is explained in the String#encode documentation.
13718 *
13719 * For example:
13720 *
13721 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13722 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13723 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13724 * # to UTF-8.
13725 */
13726static VALUE
13727argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13728{
13729 rb_io_t *fptr;
13730
13731 if (!next_argv()) {
13732 rb_raise(rb_eArgError, "no stream to set encoding");
13733 }
13734 rb_io_set_encoding(argc, argv, ARGF.current_file);
13735 GetOpenFile(ARGF.current_file, fptr);
13736 ARGF.encs = fptr->encs;
13737 RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
13738 return argf;
13739}
13740
13741/*
13742 * call-seq:
13743 * ARGF.tell -> Integer
13744 * ARGF.pos -> Integer
13745 *
13746 * Returns the current offset (in bytes) of the current file in ARGF.
13747 *
13748 * ARGF.pos #=> 0
13749 * ARGF.gets #=> "This is line one\n"
13750 * ARGF.pos #=> 17
13751 *
13752 */
13753static VALUE
13754argf_tell(VALUE argf)
13755{
13756 if (!next_argv()) {
13757 rb_raise(rb_eArgError, "no stream to tell");
13758 }
13759 ARGF_FORWARD(0, 0);
13760 return rb_io_tell(ARGF.current_file);
13761}
13762
13763/*
13764 * call-seq:
13765 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13766 *
13767 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13768 * the value of _whence_. See IO#seek for further details.
13769 */
13770static VALUE
13771argf_seek_m(int argc, VALUE *argv, VALUE argf)
13772{
13773 if (!next_argv()) {
13774 rb_raise(rb_eArgError, "no stream to seek");
13775 }
13776 ARGF_FORWARD(argc, argv);
13777 return rb_io_seek_m(argc, argv, ARGF.current_file);
13778}
13779
13780/*
13781 * call-seq:
13782 * ARGF.pos = position -> Integer
13783 *
13784 * Seeks to the position given by _position_ (in bytes) in ARGF.
13785 *
13786 * For example:
13787 *
13788 * ARGF.pos = 17
13789 * ARGF.gets #=> "This is line two\n"
13790 */
13791static VALUE
13792argf_set_pos(VALUE argf, VALUE offset)
13793{
13794 if (!next_argv()) {
13795 rb_raise(rb_eArgError, "no stream to set position");
13796 }
13797 ARGF_FORWARD(1, &offset);
13798 return rb_io_set_pos(ARGF.current_file, offset);
13799}
13800
13801/*
13802 * call-seq:
13803 * ARGF.rewind -> 0
13804 *
13805 * Positions the current file to the beginning of input, resetting
13806 * ARGF.lineno to zero.
13807 *
13808 * ARGF.readline #=> "This is line one\n"
13809 * ARGF.rewind #=> 0
13810 * ARGF.lineno #=> 0
13811 * ARGF.readline #=> "This is line one\n"
13812 */
13813static VALUE
13814argf_rewind(VALUE argf)
13815{
13816 VALUE ret;
13817 int old_lineno;
13818
13819 if (!next_argv()) {
13820 rb_raise(rb_eArgError, "no stream to rewind");
13821 }
13822 ARGF_FORWARD(0, 0);
13823 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13824 ret = rb_io_rewind(ARGF.current_file);
13825 if (!global_argf_p(argf)) {
13826 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13827 }
13828 return ret;
13829}
13830
13831/*
13832 * call-seq:
13833 * ARGF.fileno -> integer
13834 * ARGF.to_i -> integer
13835 *
13836 * Returns an integer representing the numeric file descriptor for
13837 * the current file. Raises an ArgumentError if there isn't a current file.
13838 *
13839 * ARGF.fileno #=> 3
13840 */
13841static VALUE
13842argf_fileno(VALUE argf)
13843{
13844 if (!next_argv()) {
13845 rb_raise(rb_eArgError, "no stream");
13846 }
13847 ARGF_FORWARD(0, 0);
13848 return rb_io_fileno(ARGF.current_file);
13849}
13850
13851/*
13852 * call-seq:
13853 * ARGF.to_io -> IO
13854 *
13855 * Returns an IO object representing the current file. This will be a
13856 * File object unless the current file is a stream such as STDIN.
13857 *
13858 * For example:
13859 *
13860 * ARGF.to_io #=> #<File:glark.txt>
13861 * ARGF.to_io #=> #<IO:<STDIN>>
13862 */
13863static VALUE
13864argf_to_io(VALUE argf)
13865{
13866 next_argv();
13867 ARGF_FORWARD(0, 0);
13868 return ARGF.current_file;
13869}
13870
13871/*
13872 * call-seq:
13873 * ARGF.eof? -> true or false
13874 * ARGF.eof -> true or false
13875 *
13876 * Returns true if the current file in ARGF is at end of file, i.e. it has
13877 * no data to read. The stream must be opened for reading or an IOError
13878 * will be raised.
13879 *
13880 * $ echo "eof" | ruby argf.rb
13881 *
13882 * ARGF.eof? #=> false
13883 * 3.times { ARGF.readchar }
13884 * ARGF.eof? #=> false
13885 * ARGF.readchar #=> "\n"
13886 * ARGF.eof? #=> true
13887 */
13888
13889static VALUE
13890argf_eof(VALUE argf)
13891{
13892 next_argv();
13893 if (RTEST(ARGF.current_file)) {
13894 if (ARGF.init_p == 0) return Qtrue;
13895 next_argv();
13896 ARGF_FORWARD(0, 0);
13897 if (rb_io_eof(ARGF.current_file)) {
13898 return Qtrue;
13899 }
13900 }
13901 return Qfalse;
13902}
13903
13904/*
13905 * call-seq:
13906 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13907 *
13908 * Reads _length_ bytes from ARGF. The files named on the command line
13909 * are concatenated and treated as a single file by this method, so when
13910 * called without arguments the contents of this pseudo file are returned in
13911 * their entirety.
13912 *
13913 * _length_ must be a non-negative integer or +nil+.
13914 *
13915 * If _length_ is a positive integer, +read+ tries to read
13916 * _length_ bytes without any conversion (binary mode).
13917 * It returns +nil+ if an EOF is encountered before anything can be read.
13918 * Fewer than _length_ bytes are returned if an EOF is encountered during
13919 * the read.
13920 * In the case of an integer _length_, the resulting string is always
13921 * in ASCII-8BIT encoding.
13922 *
13923 * If _length_ is omitted or is +nil+, it reads until EOF
13924 * and the encoding conversion is applied, if applicable.
13925 * A string is returned even if EOF is encountered before any data is read.
13926 *
13927 * If _length_ is zero, it returns an empty string (<code>""</code>).
13928 *
13929 * If the optional _outbuf_ argument is present,
13930 * it must reference a String, which will receive the data.
13931 * The _outbuf_ will contain only the received data after the method call
13932 * even if it is not empty at the beginning.
13933 *
13934 * For example:
13935 *
13936 * $ echo "small" > small.txt
13937 * $ echo "large" > large.txt
13938 * $ ./glark.rb small.txt large.txt
13939 *
13940 * ARGF.read #=> "small\nlarge"
13941 * ARGF.read(200) #=> "small\nlarge"
13942 * ARGF.read(2) #=> "sm"
13943 * ARGF.read(0) #=> ""
13944 *
13945 * Note that this method behaves like the fread() function in C.
13946 * This means it retries to invoke read(2) system calls to read data
13947 * with the specified length.
13948 * If you need the behavior like a single read(2) system call,
13949 * consider ARGF#readpartial or ARGF#read_nonblock.
13950 */
13951
13952static VALUE
13953argf_read(int argc, VALUE *argv, VALUE argf)
13954{
13955 VALUE tmp, str, length;
13956 long len = 0;
13957
13958 rb_scan_args(argc, argv, "02", &length, &str);
13959 if (!NIL_P(length)) {
13960 len = NUM2LONG(argv[0]);
13961 }
13962 if (!NIL_P(str)) {
13963 StringValue(str);
13964 rb_str_resize(str,0);
13965 argv[1] = Qnil;
13966 }
13967
13968 retry:
13969 if (!next_argv()) {
13970 return str;
13971 }
13972 if (ARGF_GENERIC_INPUT_P()) {
13973 tmp = argf_forward(argc, argv, argf);
13974 }
13975 else {
13976 tmp = io_read(argc, argv, ARGF.current_file);
13977 }
13978 if (NIL_P(str)) str = tmp;
13979 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13980 if (NIL_P(tmp) || NIL_P(length)) {
13981 if (ARGF.next_p != -1) {
13982 argf_close(argf);
13983 ARGF.next_p = 1;
13984 goto retry;
13985 }
13986 }
13987 else if (argc >= 1) {
13988 long slen = RSTRING_LEN(str);
13989 if (slen < len) {
13990 argv[0] = LONG2NUM(len - slen);
13991 goto retry;
13992 }
13993 }
13994 return str;
13995}
13996
13998 int argc;
13999 VALUE *argv;
14000 VALUE argf;
14001};
14002
14003static VALUE
14004argf_forward_call(VALUE arg)
14005{
14006 struct argf_call_arg *p = (struct argf_call_arg *)arg;
14007 argf_forward(p->argc, p->argv, p->argf);
14008 return Qnil;
14009}
14010
14011static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
14012 int nonblock);
14013
14014/*
14015 * call-seq:
14016 * ARGF.readpartial(maxlen) -> string
14017 * ARGF.readpartial(maxlen, outbuf) -> outbuf
14018 *
14019 * Reads at most _maxlen_ bytes from the ARGF stream.
14020 *
14021 * If the optional _outbuf_ argument is present,
14022 * it must reference a String, which will receive the data.
14023 * The _outbuf_ will contain only the received data after the method call
14024 * even if it is not empty at the beginning.
14025 *
14026 * It raises EOFError on end of ARGF stream.
14027 * Since ARGF stream is a concatenation of multiple files,
14028 * internally EOF is occur for each file.
14029 * ARGF.readpartial returns empty strings for EOFs except the last one and
14030 * raises EOFError for the last one.
14031 *
14032 */
14033
14034static VALUE
14035argf_readpartial(int argc, VALUE *argv, VALUE argf)
14036{
14037 return argf_getpartial(argc, argv, argf, Qnil, 0);
14038}
14039
14040/*
14041 * call-seq:
14042 * ARGF.read_nonblock(maxlen[, options]) -> string
14043 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14044 *
14045 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14046 */
14047
14048static VALUE
14049argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14050{
14051 VALUE opts;
14052
14053 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14054
14055 if (!NIL_P(opts))
14056 argc--;
14057
14058 return argf_getpartial(argc, argv, argf, opts, 1);
14059}
14060
14061static VALUE
14062argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14063{
14064 VALUE tmp, str, length;
14065 int no_exception;
14066
14067 rb_scan_args(argc, argv, "11", &length, &str);
14068 if (!NIL_P(str)) {
14069 StringValue(str);
14070 argv[1] = str;
14071 }
14072 no_exception = no_exception_p(opts);
14073
14074 if (!next_argv()) {
14075 if (!NIL_P(str)) {
14076 rb_str_resize(str, 0);
14077 }
14078 rb_eof_error();
14079 }
14080 if (ARGF_GENERIC_INPUT_P()) {
14081 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14082 struct argf_call_arg arg;
14083 arg.argc = argc;
14084 arg.argv = argv;
14085 arg.argf = argf;
14086 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14087 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14088 }
14089 else {
14090 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14091 }
14092 if (NIL_P(tmp)) {
14093 if (ARGF.next_p == -1) {
14094 return io_nonblock_eof(no_exception);
14095 }
14096 argf_close(argf);
14097 ARGF.next_p = 1;
14098 if (RARRAY_LEN(ARGF.argv) == 0) {
14099 return io_nonblock_eof(no_exception);
14100 }
14101 if (NIL_P(str))
14102 str = rb_str_new(NULL, 0);
14103 return str;
14104 }
14105 return tmp;
14106}
14107
14108/*
14109 * call-seq:
14110 * ARGF.getc -> String or nil
14111 *
14112 * Reads the next character from ARGF and returns it as a String. Returns
14113 * +nil+ at the end of the stream.
14114 *
14115 * ARGF treats the files named on the command line as a single file created
14116 * by concatenating their contents. After returning the last character of the
14117 * first file, it returns the first character of the second file, and so on.
14118 *
14119 * For example:
14120 *
14121 * $ echo "foo" > file
14122 * $ ruby argf.rb file
14123 *
14124 * ARGF.getc #=> "f"
14125 * ARGF.getc #=> "o"
14126 * ARGF.getc #=> "o"
14127 * ARGF.getc #=> "\n"
14128 * ARGF.getc #=> nil
14129 * ARGF.getc #=> nil
14130 */
14131static VALUE
14132argf_getc(VALUE argf)
14133{
14134 VALUE ch;
14135
14136 retry:
14137 if (!next_argv()) return Qnil;
14138 if (ARGF_GENERIC_INPUT_P()) {
14139 ch = forward_current(rb_intern("getc"), 0, 0);
14140 }
14141 else {
14142 ch = rb_io_getc(ARGF.current_file);
14143 }
14144 if (NIL_P(ch) && ARGF.next_p != -1) {
14145 argf_close(argf);
14146 ARGF.next_p = 1;
14147 goto retry;
14148 }
14149
14150 return ch;
14151}
14152
14153/*
14154 * call-seq:
14155 * ARGF.getbyte -> Integer or nil
14156 *
14157 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14158 * the end of the stream.
14159 *
14160 * For example:
14161 *
14162 * $ echo "foo" > file
14163 * $ ruby argf.rb file
14164 *
14165 * ARGF.getbyte #=> 102
14166 * ARGF.getbyte #=> 111
14167 * ARGF.getbyte #=> 111
14168 * ARGF.getbyte #=> 10
14169 * ARGF.getbyte #=> nil
14170 */
14171static VALUE
14172argf_getbyte(VALUE argf)
14173{
14174 VALUE ch;
14175
14176 retry:
14177 if (!next_argv()) return Qnil;
14178 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14179 ch = forward_current(rb_intern("getbyte"), 0, 0);
14180 }
14181 else {
14182 ch = rb_io_getbyte(ARGF.current_file);
14183 }
14184 if (NIL_P(ch) && ARGF.next_p != -1) {
14185 argf_close(argf);
14186 ARGF.next_p = 1;
14187 goto retry;
14188 }
14189
14190 return ch;
14191}
14192
14193/*
14194 * call-seq:
14195 * ARGF.readchar -> String or nil
14196 *
14197 * Reads the next character from ARGF and returns it as a String. Raises
14198 * an EOFError after the last character of the last file has been read.
14199 *
14200 * For example:
14201 *
14202 * $ echo "foo" > file
14203 * $ ruby argf.rb file
14204 *
14205 * ARGF.readchar #=> "f"
14206 * ARGF.readchar #=> "o"
14207 * ARGF.readchar #=> "o"
14208 * ARGF.readchar #=> "\n"
14209 * ARGF.readchar #=> end of file reached (EOFError)
14210 */
14211static VALUE
14212argf_readchar(VALUE argf)
14213{
14214 VALUE ch;
14215
14216 retry:
14217 if (!next_argv()) rb_eof_error();
14218 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14219 ch = forward_current(rb_intern("getc"), 0, 0);
14220 }
14221 else {
14222 ch = rb_io_getc(ARGF.current_file);
14223 }
14224 if (NIL_P(ch) && ARGF.next_p != -1) {
14225 argf_close(argf);
14226 ARGF.next_p = 1;
14227 goto retry;
14228 }
14229
14230 return ch;
14231}
14232
14233/*
14234 * call-seq:
14235 * ARGF.readbyte -> Integer
14236 *
14237 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14238 * an EOFError after the last byte of the last file has been read.
14239 *
14240 * For example:
14241 *
14242 * $ echo "foo" > file
14243 * $ ruby argf.rb file
14244 *
14245 * ARGF.readbyte #=> 102
14246 * ARGF.readbyte #=> 111
14247 * ARGF.readbyte #=> 111
14248 * ARGF.readbyte #=> 10
14249 * ARGF.readbyte #=> end of file reached (EOFError)
14250 */
14251static VALUE
14252argf_readbyte(VALUE argf)
14253{
14254 VALUE c;
14255
14256 NEXT_ARGF_FORWARD(0, 0);
14257 c = argf_getbyte(argf);
14258 if (NIL_P(c)) {
14259 rb_eof_error();
14260 }
14261 return c;
14262}
14263
14264#define FOREACH_ARGF() while (next_argv())
14265
14266static VALUE
14267argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14268{
14269 const VALUE current = ARGF.current_file;
14270 rb_yield_values2(argc, argv);
14271 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14273 }
14274 return Qnil;
14275}
14276
14277#define ARGF_block_call(mid, argc, argv, func, argf) \
14278 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14279 func, argf, rb_keyword_given_p())
14280
14281static void
14282argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14283{
14284 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14285 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14286}
14287
14288static VALUE
14289argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14290{
14291 if (!global_argf_p(argf)) {
14292 ARGF.last_lineno = ++ARGF.lineno;
14293 }
14294 return argf_block_call_i(i, argf, argc, argv, blockarg);
14295}
14296
14297static void
14298argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14299{
14300 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14301 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14302}
14303
14304/*
14305 * call-seq:
14306 * ARGF.each(sep=$/) {|line| block } -> ARGF
14307 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14308 * ARGF.each(...) -> an_enumerator
14309 *
14310 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14311 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14312 * ARGF.each_line(...) -> an_enumerator
14313 *
14314 * Returns an enumerator which iterates over each line (separated by _sep_,
14315 * which defaults to your platform's newline character) of each file in
14316 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14317 * block, otherwise an enumerator is returned.
14318 * The optional _limit_ argument is an Integer specifying the maximum
14319 * length of each line; longer lines will be split according to this limit.
14320 *
14321 * This method allows you to treat the files supplied on the command line as
14322 * a single file consisting of the concatenation of each named file. After
14323 * the last line of the first file has been returned, the first line of the
14324 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14325 * used to determine the filename of the current line and line number of the
14326 * whole input, respectively.
14327 *
14328 * For example, the following code prints out each line of each named file
14329 * prefixed with its line number, displaying the filename once per file:
14330 *
14331 * ARGF.each_line do |line|
14332 * puts ARGF.filename if ARGF.file.lineno == 1
14333 * puts "#{ARGF.file.lineno}: #{line}"
14334 * end
14335 *
14336 * While the following code prints only the first file's name at first, and
14337 * the contents with line number counted through all named files.
14338 *
14339 * ARGF.each_line do |line|
14340 * puts ARGF.filename if ARGF.lineno == 1
14341 * puts "#{ARGF.lineno}: #{line}"
14342 * end
14343 */
14344static VALUE
14345argf_each_line(int argc, VALUE *argv, VALUE argf)
14346{
14347 RETURN_ENUMERATOR(argf, argc, argv);
14348 FOREACH_ARGF() {
14349 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14350 }
14351 return argf;
14352}
14353
14354/*
14355 * call-seq:
14356 * ARGF.each_byte {|byte| block } -> ARGF
14357 * ARGF.each_byte -> an_enumerator
14358 *
14359 * Iterates over each byte of each file in +ARGV+.
14360 * A byte is returned as an Integer in the range 0..255.
14361 *
14362 * This method allows you to treat the files supplied on the command line as
14363 * a single file consisting of the concatenation of each named file. After
14364 * the last byte of the first file has been returned, the first byte of the
14365 * second file is returned. The ARGF.filename method can be used to
14366 * determine the filename of the current byte.
14367 *
14368 * If no block is given, an enumerator is returned instead.
14369 *
14370 * For example:
14371 *
14372 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14373 *
14374 */
14375static VALUE
14376argf_each_byte(VALUE argf)
14377{
14378 RETURN_ENUMERATOR(argf, 0, 0);
14379 FOREACH_ARGF() {
14380 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14381 }
14382 return argf;
14383}
14384
14385/*
14386 * call-seq:
14387 * ARGF.each_char {|char| block } -> ARGF
14388 * ARGF.each_char -> an_enumerator
14389 *
14390 * Iterates over each character of each file in ARGF.
14391 *
14392 * This method allows you to treat the files supplied on the command line as
14393 * a single file consisting of the concatenation of each named file. After
14394 * the last character of the first file has been returned, the first
14395 * character of the second file is returned. The ARGF.filename method can
14396 * be used to determine the name of the file in which the current character
14397 * appears.
14398 *
14399 * If no block is given, an enumerator is returned instead.
14400 */
14401static VALUE
14402argf_each_char(VALUE argf)
14403{
14404 RETURN_ENUMERATOR(argf, 0, 0);
14405 FOREACH_ARGF() {
14406 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14407 }
14408 return argf;
14409}
14410
14411/*
14412 * call-seq:
14413 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14414 * ARGF.each_codepoint -> an_enumerator
14415 *
14416 * Iterates over each codepoint of each file in ARGF.
14417 *
14418 * This method allows you to treat the files supplied on the command line as
14419 * a single file consisting of the concatenation of each named file. After
14420 * the last codepoint of the first file has been returned, the first
14421 * codepoint of the second file is returned. The ARGF.filename method can
14422 * be used to determine the name of the file in which the current codepoint
14423 * appears.
14424 *
14425 * If no block is given, an enumerator is returned instead.
14426 */
14427static VALUE
14428argf_each_codepoint(VALUE argf)
14429{
14430 RETURN_ENUMERATOR(argf, 0, 0);
14431 FOREACH_ARGF() {
14432 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14433 }
14434 return argf;
14435}
14436
14437/*
14438 * call-seq:
14439 * ARGF.filename -> String
14440 * ARGF.path -> String
14441 *
14442 * Returns the current filename. "-" is returned when the current file is
14443 * STDIN.
14444 *
14445 * For example:
14446 *
14447 * $ echo "foo" > foo
14448 * $ echo "bar" > bar
14449 * $ echo "glark" > glark
14450 *
14451 * $ ruby argf.rb foo bar glark
14452 *
14453 * ARGF.filename #=> "foo"
14454 * ARGF.read(5) #=> "foo\nb"
14455 * ARGF.filename #=> "bar"
14456 * ARGF.skip
14457 * ARGF.filename #=> "glark"
14458 */
14459static VALUE
14460argf_filename(VALUE argf)
14461{
14462 next_argv();
14463 return ARGF.filename;
14464}
14465
14466static VALUE
14467argf_filename_getter(ID id, VALUE *var)
14468{
14469 return argf_filename(*var);
14470}
14471
14472/*
14473 * call-seq:
14474 * ARGF.file -> IO or File object
14475 *
14476 * Returns the current file as an IO or File object.
14477 * <code>$stdin</code> is returned when the current file is STDIN.
14478 *
14479 * For example:
14480 *
14481 * $ echo "foo" > foo
14482 * $ echo "bar" > bar
14483 *
14484 * $ ruby argf.rb foo bar
14485 *
14486 * ARGF.file #=> #<File:foo>
14487 * ARGF.read(5) #=> "foo\nb"
14488 * ARGF.file #=> #<File:bar>
14489 */
14490static VALUE
14491argf_file(VALUE argf)
14492{
14493 next_argv();
14494 return ARGF.current_file;
14495}
14496
14497/*
14498 * call-seq:
14499 * ARGF.binmode -> ARGF
14500 *
14501 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14502 * be reset to non-binary mode. This option has the following effects:
14503 *
14504 * * Newline conversion is disabled.
14505 * * Encoding conversion is disabled.
14506 * * Content is treated as ASCII-8BIT.
14507 */
14508static VALUE
14509argf_binmode_m(VALUE argf)
14510{
14511 ARGF.binmode = 1;
14512 next_argv();
14513 ARGF_FORWARD(0, 0);
14514 rb_io_ascii8bit_binmode(ARGF.current_file);
14515 return argf;
14516}
14517
14518/*
14519 * call-seq:
14520 * ARGF.binmode? -> true or false
14521 *
14522 * Returns true if ARGF is being read in binary mode; false otherwise.
14523 * To enable binary mode use ARGF.binmode.
14524 *
14525 * For example:
14526 *
14527 * ARGF.binmode? #=> false
14528 * ARGF.binmode
14529 * ARGF.binmode? #=> true
14530 */
14531static VALUE
14532argf_binmode_p(VALUE argf)
14533{
14534 return RBOOL(ARGF.binmode);
14535}
14536
14537/*
14538 * call-seq:
14539 * ARGF.skip -> ARGF
14540 *
14541 * Sets the current file to the next file in ARGV. If there aren't any more
14542 * files it has no effect.
14543 *
14544 * For example:
14545 *
14546 * $ ruby argf.rb foo bar
14547 * ARGF.filename #=> "foo"
14548 * ARGF.skip
14549 * ARGF.filename #=> "bar"
14550 */
14551static VALUE
14552argf_skip(VALUE argf)
14553{
14554 if (ARGF.init_p && ARGF.next_p == 0) {
14555 argf_close(argf);
14556 ARGF.next_p = 1;
14557 }
14558 return argf;
14559}
14560
14561/*
14562 * call-seq:
14563 * ARGF.close -> ARGF
14564 *
14565 * Closes the current file and skips to the next file in ARGV. If there are
14566 * no more files to open, just closes the current file. STDIN will not be
14567 * closed.
14568 *
14569 * For example:
14570 *
14571 * $ ruby argf.rb foo bar
14572 *
14573 * ARGF.filename #=> "foo"
14574 * ARGF.close
14575 * ARGF.filename #=> "bar"
14576 * ARGF.close
14577 */
14578static VALUE
14579argf_close_m(VALUE argf)
14580{
14581 next_argv();
14582 argf_close(argf);
14583 if (ARGF.next_p != -1) {
14584 ARGF.next_p = 1;
14585 }
14586 ARGF.lineno = 0;
14587 return argf;
14588}
14589
14590/*
14591 * call-seq:
14592 * ARGF.closed? -> true or false
14593 *
14594 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14595 * ARGF.close to actually close the current file.
14596 */
14597static VALUE
14598argf_closed(VALUE argf)
14599{
14600 next_argv();
14601 ARGF_FORWARD(0, 0);
14602 return rb_io_closed_p(ARGF.current_file);
14603}
14604
14605/*
14606 * call-seq:
14607 * ARGF.to_s -> String
14608 *
14609 * Returns "ARGF".
14610 */
14611static VALUE
14612argf_to_s(VALUE argf)
14613{
14614 return rb_str_new2("ARGF");
14615}
14616
14617/*
14618 * call-seq:
14619 * ARGF.inplace_mode -> String
14620 *
14621 * Returns the file extension appended to the names of backup copies of
14622 * modified files under in-place edit mode. This value can be set using
14623 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14624 */
14625static VALUE
14626argf_inplace_mode_get(VALUE argf)
14627{
14628 if (!ARGF.inplace) return Qnil;
14629 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14630 return rb_str_dup(ARGF.inplace);
14631}
14632
14633static VALUE
14634opt_i_get(ID id, VALUE *var)
14635{
14636 return argf_inplace_mode_get(*var);
14637}
14638
14639/*
14640 * call-seq:
14641 * ARGF.inplace_mode = ext -> ARGF
14642 *
14643 * Sets the filename extension for in-place editing mode to the given String.
14644 * The backup copy of each file being edited has this value appended to its
14645 * filename.
14646 *
14647 * For example:
14648 *
14649 * $ ruby argf.rb file.txt
14650 *
14651 * ARGF.inplace_mode = '.bak'
14652 * ARGF.each_line do |line|
14653 * print line.sub("foo","bar")
14654 * end
14655 *
14656 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14657 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14658 * "bar".
14659 */
14660static VALUE
14661argf_inplace_mode_set(VALUE argf, VALUE val)
14662{
14663 if (!RTEST(val)) {
14664 ARGF.inplace = Qfalse;
14665 }
14666 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14667 ARGF.inplace = Qnil;
14668 }
14669 else {
14670 ARGF_SET(inplace, rb_str_new_frozen(val));
14671 }
14672 return argf;
14673}
14674
14675static void
14676opt_i_set(VALUE val, ID id, VALUE *var)
14677{
14678 argf_inplace_mode_set(*var, val);
14679}
14680
14681void
14682ruby_set_inplace_mode(const char *suffix)
14683{
14684 ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
14685}
14686
14687/*
14688 * call-seq:
14689 * ARGF.argv -> ARGV
14690 *
14691 * Returns the +ARGV+ array, which contains the arguments passed to your
14692 * script, one per element.
14693 *
14694 * For example:
14695 *
14696 * $ ruby argf.rb -v glark.txt
14697 *
14698 * ARGF.argv #=> ["-v", "glark.txt"]
14699 *
14700 */
14701static VALUE
14702argf_argv(VALUE argf)
14703{
14704 return ARGF.argv;
14705}
14706
14707static VALUE
14708argf_argv_getter(ID id, VALUE *var)
14709{
14710 return argf_argv(*var);
14711}
14712
14713VALUE
14715{
14716 return ARGF.argv;
14717}
14718
14719/*
14720 * call-seq:
14721 * ARGF.to_write_io -> io
14722 *
14723 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14724 * enabled.
14725 */
14726static VALUE
14727argf_write_io(VALUE argf)
14728{
14729 if (!RTEST(ARGF.current_file)) {
14730 rb_raise(rb_eIOError, "not opened for writing");
14731 }
14732 return GetWriteIO(ARGF.current_file);
14733}
14734
14735/*
14736 * call-seq:
14737 * ARGF.write(*objects) -> integer
14738 *
14739 * Writes each of the given +objects+ if inplace mode.
14740 */
14741static VALUE
14742argf_write(int argc, VALUE *argv, VALUE argf)
14743{
14744 return rb_io_writev(argf_write_io(argf), argc, argv);
14745}
14746
14747void
14748rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14749{
14750 rb_readwrite_syserr_fail(waiting, errno, mesg);
14751}
14752
14753void
14754rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14755{
14756 VALUE arg, c = Qnil;
14757 arg = mesg ? rb_str_new2(mesg) : Qnil;
14758 switch (waiting) {
14759 case RB_IO_WAIT_WRITABLE:
14760 switch (n) {
14761 case EAGAIN:
14762 c = rb_eEAGAINWaitWritable;
14763 break;
14764#if EAGAIN != EWOULDBLOCK
14765 case EWOULDBLOCK:
14766 c = rb_eEWOULDBLOCKWaitWritable;
14767 break;
14768#endif
14769 case EINPROGRESS:
14770 c = rb_eEINPROGRESSWaitWritable;
14771 break;
14772 default:
14774 }
14775 break;
14776 case RB_IO_WAIT_READABLE:
14777 switch (n) {
14778 case EAGAIN:
14779 c = rb_eEAGAINWaitReadable;
14780 break;
14781#if EAGAIN != EWOULDBLOCK
14782 case EWOULDBLOCK:
14783 c = rb_eEWOULDBLOCKWaitReadable;
14784 break;
14785#endif
14786 case EINPROGRESS:
14787 c = rb_eEINPROGRESSWaitReadable;
14788 break;
14789 default:
14791 }
14792 break;
14793 default:
14794 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14795 }
14797}
14798
14799static VALUE
14800get_LAST_READ_LINE(ID _x, VALUE *_y)
14801{
14802 return rb_lastline_get();
14803}
14804
14805static void
14806set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14807{
14808 rb_lastline_set(val);
14809}
14810
14811/*
14812 * Document-class: IOError
14813 *
14814 * Raised when an IO operation fails.
14815 *
14816 * File.open("/etc/hosts") {|f| f << "example"}
14817 * #=> IOError: not opened for writing
14818 *
14819 * File.open("/etc/hosts") {|f| f.close; f.read }
14820 * #=> IOError: closed stream
14821 *
14822 * Note that some IO failures raise <code>SystemCallError</code>s
14823 * and these are not subclasses of IOError:
14824 *
14825 * File.open("does/not/exist")
14826 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14827 */
14828
14829/*
14830 * Document-class: EOFError
14831 *
14832 * Raised by some IO operations when reaching the end of file. Many IO
14833 * methods exist in two forms,
14834 *
14835 * one that returns +nil+ when the end of file is reached, the other
14836 * raises EOFError.
14837 *
14838 * EOFError is a subclass of IOError.
14839 *
14840 * file = File.open("/etc/hosts")
14841 * file.read
14842 * file.gets #=> nil
14843 * file.readline #=> EOFError: end of file reached
14844 * file.close
14845 */
14846
14847/*
14848 * Document-class: ARGF
14849 *
14850 * == \ARGF and +ARGV+
14851 *
14852 * The \ARGF object works with the array at global variable +ARGV+
14853 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14854 *
14855 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14856 *
14857 * Initially, it contains the command-line arguments and options
14858 * that are passed to the Ruby program;
14859 * the program can modify that array as it likes.
14860 *
14861 * - **ARGF** may be thought of as the <b>argument files</b> object.
14862 *
14863 * It can access file streams and/or the <tt>$stdin</tt> stream,
14864 * based on what it finds in +ARGV+.
14865 * This provides a convenient way for the command line
14866 * to specify streams for a Ruby program to read.
14867 *
14868 * == Reading
14869 *
14870 * \ARGF may read from _source_ streams,
14871 * which at any particular time are determined by the content of +ARGV+.
14872 *
14873 * === Simplest Case
14874 *
14875 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14876 * the source is <tt>$stdin</tt>:
14877 *
14878 * - \File +t.rb+:
14879 *
14880 * p ['ARGV', ARGV]
14881 * p ['ARGF.read', ARGF.read]
14882 *
14883 * - Commands and outputs
14884 * (see below for the content of files +foo.txt+ and +bar.txt+):
14885 *
14886 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14887 * ["ARGV", []]
14888 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14889 *
14890 * $ cat foo.txt bar.txt | ruby t.rb
14891 * ["ARGV", []]
14892 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14893 *
14894 * === About the Examples
14895 *
14896 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14897 *
14898 * $ cat foo.txt
14899 * Foo 0
14900 * Foo 1
14901 * $ cat bar.txt
14902 * Bar 0
14903 * Bar 1
14904 * Bar 2
14905 * Bar 3
14906 *
14907 * === Sources in +ARGV+
14908 *
14909 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14910 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14911 * the sources are found in +ARGV+.
14912 *
14913 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14914 * and is one of:
14915 *
14916 * - The string path to a file that may be opened as a stream.
14917 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14918 *
14919 * Each element that is _not_ one of these
14920 * should be removed from +ARGV+ before \ARGF accesses that source.
14921 *
14922 * In the following example:
14923 *
14924 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14925 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14926 *
14927 * Example:
14928 *
14929 * - \File +t.rb+:
14930 *
14931 * # Print arguments (and options, if any) found on command line.
14932 * p ['ARGV', ARGV]
14933 *
14934 * - Command and output:
14935 *
14936 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14937 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14938 *
14939 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14940 *
14941 * - \File +t.rb+:
14942 *
14943 * p "ARGV: #{ARGV}"
14944 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
14945 *
14946 * - Command and output:
14947 *
14948 * $ ruby t.rb foo.txt bar.txt
14949 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14950 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14951 *
14952 * Because the value at +ARGV+ is an ordinary array,
14953 * you can manipulate it to control which sources \ARGF considers:
14954 *
14955 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14956 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14957 *
14958 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14959 * when all sources have been accessed, the array is empty:
14960 *
14961 * - \File +t.rb+:
14962 *
14963 * until ARGV.empty? && ARGF.eof?
14964 * p "ARGV: #{ARGV}"
14965 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14966 * end
14967 *
14968 * - Command and output:
14969 *
14970 * $ ruby t.rb foo.txt bar.txt
14971 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14972 * "Line: Foo 0\n"
14973 * "ARGV: [\"bar.txt\"]"
14974 * "Line: Foo 1\n"
14975 * "ARGV: [\"bar.txt\"]"
14976 * "Line: Bar 0\n"
14977 * "ARGV: []"
14978 * "Line: Bar 1\n"
14979 * "ARGV: []"
14980 * "Line: Bar 2\n"
14981 * "ARGV: []"
14982 * "Line: Bar 3\n"
14983 *
14984 * ==== Filepaths in +ARGV+
14985 *
14986 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14987 *
14988 * This program prints what it reads from files at the paths specified
14989 * on the command line:
14990 *
14991 * - \File +t.rb+:
14992 *
14993 * p ['ARGV', ARGV]
14994 * # Read and print all content from the specified sources.
14995 * p ['ARGF.read', ARGF.read]
14996 *
14997 * - Command and output:
14998 *
14999 * $ ruby t.rb foo.txt bar.txt
15000 * ["ARGV", [foo.txt, bar.txt]
15001 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15002 *
15003 * ==== Specifying <tt>$stdin</tt> in +ARGV+
15004 *
15005 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
15006 *
15007 * - \File +t.rb+:
15008 *
15009 * p ['ARGV', ARGV]
15010 * p ['ARGF.read', ARGF.read]
15011 *
15012 * - Command and output:
15013 *
15014 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
15015 * ["ARGV", ["-"]]
15016 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15017 *
15018 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
15019 *
15020 * - Command and output:
15021 *
15022 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15023 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15024 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15025 *
15026 * ==== Mixtures and Repetitions in +ARGV+
15027 *
15028 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15029 * and character <tt>'-'</tt>, including repetitions.
15030 *
15031 * ==== Modifications to +ARGV+
15032 *
15033 * The running Ruby program may make any modifications to the +ARGV+ array;
15034 * the current value of +ARGV+ affects \ARGF reading.
15035 *
15036 * ==== Empty +ARGV+
15037 *
15038 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15039 * or raises an exception, depending on the specific method.
15040 *
15041 * === More Read Methods
15042 *
15043 * As seen above, method ARGF#read reads the content of all sources
15044 * into a single string.
15045 * Other \ARGF methods provide other ways to access that content;
15046 * these include:
15047 *
15048 * - Byte access: #each_byte, #getbyte, #readbyte.
15049 * - Character access: #each_char, #getc, #readchar.
15050 * - Codepoint access: #each_codepoint.
15051 * - Line access: #each_line, #gets, #readline, #readlines.
15052 * - Source access: #read, #read_nonblock, #readpartial.
15053 *
15054 * === About \Enumerable
15055 *
15056 * \ARGF includes module Enumerable.
15057 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15058 *
15059 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15060 * _not_ from +ARGV+;
15061 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15062 * not an array of the strings from +ARGV+:
15063 *
15064 * - \File +t.rb+:
15065 *
15066 * p ['ARGV', ARGV]
15067 * p ['ARGF.entries', ARGF.entries]
15068 *
15069 * - Command and output:
15070 *
15071 * $ ruby t.rb foo.txt bar.txt
15072 * ["ARGV", ["foo.txt", "bar.txt"]]
15073 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15074 *
15075 * == Writing
15076 *
15077 * If <i>inplace mode</i> is in effect,
15078 * \ARGF may write to target streams,
15079 * which at any particular time are determined by the content of ARGV.
15080 *
15081 * Methods about inplace mode:
15082 *
15083 * - #inplace_mode
15084 * - #inplace_mode=
15085 * - #to_write_io
15086 *
15087 * Methods for writing:
15088 *
15089 * - #print
15090 * - #printf
15091 * - #putc
15092 * - #puts
15093 * - #write
15094 *
15095 */
15096
15097/*
15098 * An instance of class \IO (commonly called a _stream_)
15099 * represents an input/output stream in the underlying operating system.
15100 * Class \IO is the basis for input and output in Ruby.
15101 *
15102 * Class File is the only class in the Ruby core that is a subclass of \IO.
15103 * Some classes in the Ruby standard library are also subclasses of \IO;
15104 * these include TCPSocket and UDPSocket.
15105 *
15106 * The global constant ARGF (also accessible as <tt>$<</tt>)
15107 * provides an IO-like stream that allows access to all file paths
15108 * found in ARGV (or found in STDIN if ARGV is empty).
15109 * ARGF is not itself a subclass of \IO.
15110 *
15111 * Class StringIO provides an IO-like stream that handles a String.
15112 * StringIO is not itself a subclass of \IO.
15113 *
15114 * Important objects based on \IO include:
15115 *
15116 * - $stdin.
15117 * - $stdout.
15118 * - $stderr.
15119 * - Instances of class File.
15120 *
15121 * An instance of \IO may be created using:
15122 *
15123 * - IO.new: returns a new \IO object for the given integer file descriptor.
15124 * - IO.open: passes a new \IO object to the given block.
15125 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15126 * of a newly-launched subprocess.
15127 * - Kernel#open: Returns a new \IO object connected to a given source:
15128 * stream, file, or subprocess.
15129 *
15130 * Like a File stream, an \IO stream has:
15131 *
15132 * - A read/write mode, which may be read-only, write-only, or read/write;
15133 * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
15134 * - A data mode, which may be text-only or binary;
15135 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15136 * - Internal and external encodings;
15137 * see {Encodings}[rdoc-ref:File@Encodings].
15138 *
15139 * And like other \IO streams, it has:
15140 *
15141 * - A position, which determines where in the stream the next
15142 * read or write is to occur;
15143 * see {Position}[rdoc-ref:IO@Position].
15144 * - A line number, which is a special, line-oriented, "position"
15145 * (different from the position mentioned above);
15146 * see {Line Number}[rdoc-ref:IO@Line+Number].
15147 *
15148 * == Extension <tt>io/console</tt>
15149 *
15150 * Extension <tt>io/console</tt> provides numerous methods
15151 * for interacting with the console;
15152 * requiring it adds numerous methods to class \IO.
15153 *
15154 * == Example Files
15155 *
15156 * Many examples here use these variables:
15157 *
15158 * :include: doc/examples/files.rdoc
15159 *
15160 * == Open Options
15161 *
15162 * A number of \IO methods accept optional keyword arguments
15163 * that determine how a new stream is to be opened:
15164 *
15165 * - +:mode+: Stream mode.
15166 * - +:flags+: Integer file open flags;
15167 * If +mode+ is also given, the two are bitwise-ORed.
15168 * - +:external_encoding+: External encoding for the stream.
15169 * - +:internal_encoding+: Internal encoding for the stream.
15170 * <tt>'-'</tt> is a synonym for the default internal encoding.
15171 * If the value is +nil+ no conversion occurs.
15172 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15173 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15174 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15175 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15176 * when the stream closes; otherwise it remains open.
15177 * - +:path+: If a string value is provided, it is used in #inspect and is available as
15178 * #path method.
15179 *
15180 * Also available are the options offered in String#encode,
15181 * which may control conversion between external and internal encoding.
15182 *
15183 * == Basic \IO
15184 *
15185 * You can perform basic stream \IO with these methods,
15186 * which typically operate on multi-byte strings:
15187 *
15188 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15189 * - IO#write: Writes zero or more strings to the stream;
15190 * each given object that is not already a string is converted via +to_s+.
15191 *
15192 * === Position
15193 *
15194 * An \IO stream has a nonnegative integer _position_,
15195 * which is the byte offset at which the next read or write is to occur.
15196 * A new stream has position zero (and line number zero);
15197 * method +rewind+ resets the position (and line number) to zero.
15198 *
15199 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15200 * Encoding::Converter instances used for that \IO.
15201 *
15202 * The relevant methods:
15203 *
15204 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15205 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15206 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15207 * relative to a given position +whence+
15208 * (indicating the beginning, end, or current position).
15209 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15210 *
15211 * === Open and Closed Streams
15212 *
15213 * A new \IO stream may be open for reading, open for writing, or both.
15214 *
15215 * A stream is automatically closed when claimed by the garbage collector.
15216 *
15217 * Attempted reading or writing on a closed stream raises an exception.
15218 *
15219 * The relevant methods:
15220 *
15221 * - IO#close: Closes the stream for both reading and writing.
15222 * - IO#close_read: Closes the stream for reading.
15223 * - IO#close_write: Closes the stream for writing.
15224 * - IO#closed?: Returns whether the stream is closed.
15225 *
15226 * === End-of-Stream
15227 *
15228 * You can query whether a stream is positioned at its end:
15229 *
15230 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15231 *
15232 * You can reposition to end-of-stream by using method IO#seek:
15233 *
15234 * f = File.new('t.txt')
15235 * f.eof? # => false
15236 * f.seek(0, :END)
15237 * f.eof? # => true
15238 * f.close
15239 *
15240 * Or by reading all stream content (which is slower than using IO#seek):
15241 *
15242 * f.rewind
15243 * f.eof? # => false
15244 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15245 * f.eof? # => true
15246 *
15247 * == Line \IO
15248 *
15249 * Class \IO supports line-oriented
15250 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15251 *
15252 * === Line Input
15253 *
15254 * Class \IO supports line-oriented input for
15255 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input].
15256 *
15257 * ==== Line Input Options
15258 *
15259 * Optional keyword argument +chomp+ (default: +false+)
15260 * specifies whether line separators are to be excluded from the result of a read.
15261 *
15262 * ==== \File Line Input
15263 *
15264 * You can read lines from a file using these methods:
15265 *
15266 * - IO.foreach: Reads each line and passes it to the given block.
15267 * - IO.readlines: Reads and returns all lines in an array.
15268 *
15269 * For each of these methods:
15270 *
15271 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15272 * - Line parsing depends on the effective <i>line separator</i>;
15273 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15274 * - The length of each returned line depends on the effective <i>line limit</i>;
15275 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15276 *
15277 * ==== Stream Line Input
15278 *
15279 * You can read lines from an \IO stream using these methods:
15280 *
15281 * - IO#each_line: Reads each remaining line, passing it to the given block.
15282 * - IO#gets: Returns the next line.
15283 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15284 * - IO#readlines: Returns all remaining lines in an array.
15285 *
15286 * For each of these methods:
15287 *
15288 * - Reading may begin mid-line,
15289 * depending on the stream's _position_;
15290 * see {Position}[rdoc-ref:IO@Position].
15291 * - Line parsing depends on the effective <i>line separator</i>;
15292 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15293 * - The length of each returned line depends on the effective <i>line limit</i>;
15294 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15295 *
15296 * ===== Line Separator
15297 *
15298 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15299 * the string that determines what is considered a line;
15300 * it is sometimes called the <i>input record separator</i>.
15301 *
15302 * The default line separator is taken from global variable <tt>$/</tt>,
15303 * whose initial value is <tt>"\n"</tt>.
15304 *
15305 * Generally, the line to be read next is all data
15306 * from the current {position}[rdoc-ref:IO@Position]
15307 * to the next line separator
15308 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15309 *
15310 * f = File.new('t.txt')
15311 * # Method gets with no sep argument returns the next line, according to $/.
15312 * f.gets # => "First line\n"
15313 * f.gets # => "Second line\n"
15314 * f.gets # => "\n"
15315 * f.gets # => "Fourth line\n"
15316 * f.gets # => "Fifth line\n"
15317 * f.close
15318 *
15319 * You can use a different line separator by passing argument +sep+:
15320 *
15321 * f = File.new('t.txt')
15322 * f.gets('l') # => "First l"
15323 * f.gets('li') # => "ine\nSecond li"
15324 * f.gets('lin') # => "ne\n\nFourth lin"
15325 * f.gets # => "e\n"
15326 * f.close
15327 *
15328 * Or by setting global variable <tt>$/</tt>:
15329 *
15330 * f = File.new('t.txt')
15331 * $/ = 'l'
15332 * f.gets # => "First l"
15333 * f.gets # => "ine\nSecond l"
15334 * f.gets # => "ine\n\nFourth l"
15335 * f.close
15336 *
15337 * ===== Special Line Separator Values
15338 *
15339 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15340 * accepts two special values for parameter +sep+:
15341 *
15342 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15343 *
15344 * f = File.new('t.txt')
15345 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15346 * f.close
15347 *
15348 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15349 * (paragraphs being separated by two consecutive line separators):
15350 *
15351 * f = File.new('t.txt')
15352 * f.gets('') # => "First line\nSecond line\n\n"
15353 * f.gets('') # => "Fourth line\nFifth line\n"
15354 * f.close
15355 *
15356 * ===== Line Limit
15357 *
15358 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15359 * uses an integer <i>line limit</i>,
15360 * which restricts the number of bytes that may be returned.
15361 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15362 * than the limit).
15363 *
15364 * The default limit value is <tt>-1</tt>;
15365 * any negative limit value means that there is no limit.
15366 *
15367 * If there is no limit, the line is determined only by +sep+.
15368 *
15369 * # Text with 1-byte characters.
15370 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15371 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15372 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15373 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15374 * # No more than one line.
15375 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15376 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15377 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15378 *
15379 * # Text with 3-byte characters, which will not be split.
15380 * File.read('t.ja') # => "こんにちは"
15381 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15382 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15383 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15384 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15385 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15386 *
15387 * ===== Line Separator and Line Limit
15388 *
15389 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15390 *
15391 * - Returns the next line as determined by line separator +sep+.
15392 * - But returns no more bytes than are allowed by the limit +limit+.
15393 *
15394 * Example:
15395 *
15396 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15397 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15398 *
15399 * ===== Line Number
15400 *
15401 * A readable \IO stream has a non-negative integer <i>line number</i>:
15402 *
15403 * - IO#lineno: Returns the line number.
15404 * - IO#lineno=: Resets and returns the line number.
15405 *
15406 * Unless modified by a call to method IO#lineno=,
15407 * the line number is the number of lines read
15408 * by certain line-oriented methods,
15409 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15410 *
15411 * - IO.foreach: Increments the line number on each call to the block.
15412 * - IO#each_line: Increments the line number on each call to the block.
15413 * - IO#gets: Increments the line number.
15414 * - IO#readline: Increments the line number.
15415 * - IO#readlines: Increments the line number for each line read.
15416 *
15417 * A new stream is initially has line number zero (and position zero);
15418 * method +rewind+ resets the line number (and position) to zero:
15419 *
15420 * f = File.new('t.txt')
15421 * f.lineno # => 0
15422 * f.gets # => "First line\n"
15423 * f.lineno # => 1
15424 * f.rewind
15425 * f.lineno # => 0
15426 * f.close
15427 *
15428 * Reading lines from a stream usually changes its line number:
15429 *
15430 * f = File.new('t.txt', 'r')
15431 * f.lineno # => 0
15432 * f.readline # => "This is line one.\n"
15433 * f.lineno # => 1
15434 * f.readline # => "This is the second line.\n"
15435 * f.lineno # => 2
15436 * f.readline # => "Here's the third line.\n"
15437 * f.lineno # => 3
15438 * f.eof? # => true
15439 * f.close
15440 *
15441 * Iterating over lines in a stream usually changes its line number:
15442 *
15443 * File.open('t.txt') do |f|
15444 * f.each_line do |line|
15445 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15446 * end
15447 * end
15448 *
15449 * Output:
15450 *
15451 * "position=11 eof?=false lineno=1"
15452 * "position=23 eof?=false lineno=2"
15453 * "position=24 eof?=false lineno=3"
15454 * "position=36 eof?=false lineno=4"
15455 * "position=47 eof?=true lineno=5"
15456 *
15457 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15458 * the line number does not affect where the next read or write will occur:
15459 *
15460 * f = File.new('t.txt')
15461 * f.lineno = 1000
15462 * f.lineno # => 1000
15463 * f.gets # => "First line\n"
15464 * f.lineno # => 1001
15465 * f.close
15466 *
15467 * Associated with the line number is the global variable <tt>$.</tt>:
15468 *
15469 * - When a stream is opened, <tt>$.</tt> is not set;
15470 * its value is left over from previous activity in the process:
15471 *
15472 * $. = 41
15473 * f = File.new('t.txt')
15474 * $. = 41
15475 * # => 41
15476 * f.close
15477 *
15478 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15479 *
15480 * f0 = File.new('t.txt')
15481 * f1 = File.new('t.dat')
15482 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15483 * $. # => 5
15484 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15485 * $. # => 1
15486 * f0.close
15487 * f1.close
15488 *
15489 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15490 *
15491 * f = File.new('t.txt')
15492 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15493 * $. # => 5
15494 * f.rewind
15495 * f.seek(0, :SET)
15496 * $. # => 5
15497 * f.close
15498 *
15499 * === Line Output
15500 *
15501 * You can write to an \IO stream line-by-line using this method:
15502 *
15503 * - IO#puts: Writes objects to the stream.
15504 *
15505 * == Character \IO
15506 *
15507 * You can process an \IO stream character-by-character using these methods:
15508 *
15509 * - IO#getc: Reads and returns the next character from the stream.
15510 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15511 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15512 * - IO#putc: Writes a character to the stream.
15513 * - IO#each_char: Reads each remaining character in the stream,
15514 * passing the character to the given block.
15515 *
15516 * == Byte \IO
15517 *
15518 * You can process an \IO stream byte-by-byte using these methods:
15519 *
15520 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15521 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15522 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15523 * - IO#each_byte: Reads each remaining byte in the stream,
15524 * passing the byte to the given block.
15525 *
15526 * == Codepoint \IO
15527 *
15528 * You can process an \IO stream codepoint-by-codepoint:
15529 *
15530 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15531 *
15532 * == What's Here
15533 *
15534 * First, what's elsewhere. Class \IO:
15535 *
15536 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
15537 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
15538 * which provides dozens of additional methods.
15539 *
15540 * Here, class \IO provides methods that are useful for:
15541 *
15542 * - {Creating}[rdoc-ref:IO@Creating]
15543 * - {Reading}[rdoc-ref:IO@Reading]
15544 * - {Writing}[rdoc-ref:IO@Writing]
15545 * - {Positioning}[rdoc-ref:IO@Positioning]
15546 * - {Iterating}[rdoc-ref:IO@Iterating]
15547 * - {Settings}[rdoc-ref:IO@Settings]
15548 * - {Querying}[rdoc-ref:IO@Querying]
15549 * - {Buffering}[rdoc-ref:IO@Buffering]
15550 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15551 * - {Other}[rdoc-ref:IO@Other]
15552 *
15553 * === Creating
15554 *
15555 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15556 * integer file descriptor.
15557 * - ::open: Creates a new \IO object.
15558 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15559 * - ::popen: Creates an \IO object to interact with a subprocess.
15560 * - ::select: Selects which given \IO instances are ready for reading,
15561 * writing, or have pending exceptions.
15562 *
15563 * === Reading
15564 *
15565 * - ::binread: Returns a binary string with all or a subset of bytes
15566 * from the given file.
15567 * - ::read: Returns a string with all or a subset of bytes from the given file.
15568 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15569 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15570 * - #getc: Returns the next character read from +self+ as a string.
15571 * - #gets: Returns the line read from +self+.
15572 * - #pread: Returns all or the next _n_ bytes read from +self+,
15573 * not updating the receiver's offset.
15574 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15575 * for a given _n_.
15576 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15577 * in non-block mode.
15578 * - #readbyte: Returns the next byte read from +self+;
15579 * same as #getbyte, but raises an exception on end-of-stream.
15580 * - #readchar: Returns the next character read from +self+;
15581 * same as #getc, but raises an exception on end-of-stream.
15582 * - #readline: Returns the next line read from +self+;
15583 * same as #getline, but raises an exception of end-of-stream.
15584 * - #readlines: Returns an array of all lines read read from +self+.
15585 * - #readpartial: Returns up to the given number of bytes from +self+.
15586 *
15587 * === Writing
15588 *
15589 * - ::binwrite: Writes the given string to the file at the given filepath,
15590 * in binary mode.
15591 * - ::write: Writes the given string to +self+.
15592 * - #<<: Appends the given string to +self+.
15593 * - #print: Prints last read line or given objects to +self+.
15594 * - #printf: Writes to +self+ based on the given format string and objects.
15595 * - #putc: Writes a character to +self+.
15596 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15597 * - #pwrite: Writes the given string at the given offset,
15598 * not updating the receiver's offset.
15599 * - #write: Writes one or more given strings to +self+.
15600 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15601 *
15602 * === Positioning
15603 *
15604 * - #lineno: Returns the current line number in +self+.
15605 * - #lineno=: Sets the line number is +self+.
15606 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15607 * - #pos=: Sets the byte offset in +self+.
15608 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15609 * - #rewind: Positions +self+ to the beginning of input.
15610 * - #seek: Sets the offset for +self+ relative to given position.
15611 *
15612 * === Iterating
15613 *
15614 * - ::foreach: Yields each line of given file to the block.
15615 * - #each (aliased as #each_line): Calls the given block
15616 * with each successive line in +self+.
15617 * - #each_byte: Calls the given block with each successive byte in +self+
15618 * as an integer.
15619 * - #each_char: Calls the given block with each successive character in +self+
15620 * as a string.
15621 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15622 * as an integer.
15623 *
15624 * === Settings
15625 *
15626 * - #autoclose=: Sets whether +self+ auto-closes.
15627 * - #binmode: Sets +self+ to binary mode.
15628 * - #close: Closes +self+.
15629 * - #close_on_exec=: Sets the close-on-exec flag.
15630 * - #close_read: Closes +self+ for reading.
15631 * - #close_write: Closes +self+ for writing.
15632 * - #set_encoding: Sets the encoding for +self+.
15633 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15634 * Unicode byte-order-mark.
15635 * - #sync=: Sets the sync-mode to the given value.
15636 *
15637 * === Querying
15638 *
15639 * - #autoclose?: Returns whether +self+ auto-closes.
15640 * - #binmode?: Returns whether +self+ is in binary mode.
15641 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15642 * - #closed?: Returns whether +self+ is closed.
15643 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15644 * - #external_encoding: Returns the external encoding object for +self+.
15645 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15646 * - #internal_encoding: Returns the internal encoding object for +self+.
15647 * - #pid: Returns the process ID of a child process associated with +self+,
15648 * if +self+ was created by ::popen.
15649 * - #stat: Returns the File::Stat object containing status information for +self+.
15650 * - #sync: Returns whether +self+ is in sync-mode.
15651 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15652 *
15653 * === Buffering
15654 *
15655 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15656 * - #flush: Flushes any buffered data within +self+ to the underlying
15657 * operating system.
15658 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15659 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15660 * - #ungetc: Prepends buffer for +self+ with given string.
15661 *
15662 * === Low-Level Access
15663 *
15664 * - ::sysopen: Opens the file given by its path,
15665 * returning the integer file descriptor.
15666 * - #advise: Announces the intention to access data from +self+ in a specific way.
15667 * - #fcntl: Passes a low-level command to the file specified
15668 * by the given file descriptor.
15669 * - #ioctl: Passes a low-level command to the device specified
15670 * by the given file descriptor.
15671 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15672 * - #sysseek: Sets the offset for +self+.
15673 * - #syswrite: Writes the given string to +self+ using a low-level write.
15674 *
15675 * === Other
15676 *
15677 * - ::copy_stream: Copies data from a source to a destination,
15678 * each of which is a filepath or an \IO-like object.
15679 * - ::try_convert: Returns a new \IO object resulting from converting
15680 * the given object.
15681 * - #inspect: Returns the string representation of +self+.
15682 *
15683 */
15684
15685void
15686Init_IO(void)
15687{
15688 VALUE rb_cARGF;
15689#ifdef __CYGWIN__
15690#include <sys/cygwin.h>
15691 static struct __cygwin_perfile pf[] =
15692 {
15693 {"", O_RDONLY | O_BINARY},
15694 {"", O_WRONLY | O_BINARY},
15695 {"", O_RDWR | O_BINARY},
15696 {"", O_APPEND | O_BINARY},
15697 {NULL, 0}
15698 };
15699 cygwin_internal(CW_PERFILE, pf);
15700#endif
15701
15702 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15703 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15704
15705 id_write = rb_intern_const("write");
15706 id_read = rb_intern_const("read");
15707 id_flush = rb_intern_const("flush");
15708 id_readpartial = rb_intern_const("readpartial");
15709 id_set_encoding = rb_intern_const("set_encoding");
15710 id_fileno = rb_intern_const("fileno");
15711
15712 rb_define_global_function("syscall", rb_f_syscall, -1);
15713
15714 rb_define_global_function("open", rb_f_open, -1);
15715 rb_define_global_function("printf", rb_f_printf, -1);
15716 rb_define_global_function("print", rb_f_print, -1);
15717 rb_define_global_function("putc", rb_f_putc, 1);
15718 rb_define_global_function("puts", rb_f_puts, -1);
15719 rb_define_global_function("gets", rb_f_gets, -1);
15720 rb_define_global_function("readline", rb_f_readline, -1);
15721 rb_define_global_function("select", rb_f_select, -1);
15722
15723 rb_define_global_function("readlines", rb_f_readlines, -1);
15724
15725 rb_define_global_function("`", rb_f_backquote, 1);
15726
15727 rb_define_global_function("p", rb_f_p, -1);
15728 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15729
15730 rb_cIO = rb_define_class("IO", rb_cObject);
15732
15733 /* Can be raised by IO operations when IO#timeout= is set. */
15734 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15735
15736 /* Readable event mask for IO#wait. */
15737 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15738 /* Writable event mask for IO#wait. */
15739 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15740 /* Priority event mask for IO#wait. */
15741 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15742
15743 /* exception to wait for reading. see IO.select. */
15744 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15745 /* exception to wait for writing. see IO.select. */
15746 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15747 /* exception to wait for reading by EAGAIN. see IO.select. */
15748 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15749 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15750 /* exception to wait for writing by EAGAIN. see IO.select. */
15751 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15752 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15753#if EAGAIN == EWOULDBLOCK
15754 /* same as IO::EAGAINWaitReadable */
15755 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15756 /* same as IO::EAGAINWaitWritable */
15757 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15758#else
15759 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15760 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15761 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15762 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15763 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15764 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15765#endif
15766 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15767 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15768 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15769 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15770 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15771 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15772
15773#if 0
15774 /* This is necessary only for forcing rdoc handle File::open */
15775 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15776#endif
15777
15778 rb_define_alloc_func(rb_cIO, io_alloc);
15779 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15780 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15781 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15782 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15783 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15784 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15785 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15786 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15787 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15788 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15789 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15790 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15791 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15792 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15793 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15794
15795 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15796
15798 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15799
15800 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15801 rb_vm_register_global_object(rb_default_rs);
15802 rb_rs = rb_default_rs;
15804 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15805 rb_gvar_ractor_local("$/"); // not local but ractor safe
15806 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15807 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15808 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
15809
15810 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15811 rb_gvar_ractor_local("$_");
15812 rb_gvar_box_dynamic("$_");
15813
15814 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15815 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15816
15817 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15818 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15819 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15820 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15821
15822 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15823 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15824 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15825 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15826 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15827
15828 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15829 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15830
15831 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15832 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15833
15834 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15835 rb_define_alias(rb_cIO, "to_i", "fileno");
15836 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15837
15838 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15839 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15840
15841 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15842 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15843 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15844 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15845
15846 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15847 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15848
15849 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15850
15851 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15852 rb_define_method(rb_cIO, "read", io_read, -1);
15853 rb_define_method(rb_cIO, "write", io_write_m, -1);
15854 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15855 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15856 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15857 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15858 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15859 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15860 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15862 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15863 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15864 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15865 /* Set I/O position from the beginning */
15866 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15867 /* Set I/O position from the current position */
15868 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15869 /* Set I/O position from the end */
15870 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15871#ifdef SEEK_DATA
15872 /* Set I/O position to the next location containing data */
15873 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15874#endif
15875#ifdef SEEK_HOLE
15876 /* Set I/O position to the next hole */
15877 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15878#endif
15879 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15880 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15881 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15882 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15883 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15884
15885 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15886 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15887
15888 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15889 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15890 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15891 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15892
15893 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15894 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15895 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15896 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15897 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15898 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15899
15900 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15901 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15902 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15903
15904 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15905 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15906
15907 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15908
15909 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15910 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15911 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15912 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15913
15914 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15915 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15916
15917 rb_define_method(rb_cIO, "wait", io_wait, -1);
15918
15919 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15920 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15921 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15922
15923 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15924 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15925 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15926 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15927
15928 rb_gvar_ractor_local("$stdin");
15929 rb_gvar_ractor_local("$stdout");
15930 rb_gvar_ractor_local("$>");
15931 rb_gvar_ractor_local("$stderr");
15932
15934 rb_stdin = rb_io_prep_stdin();
15936 rb_stdout = rb_io_prep_stdout();
15938 rb_stderr = rb_io_prep_stderr();
15939
15940 orig_stdout = rb_stdout;
15941 orig_stderr = rb_stderr;
15942
15943 /* Holds the original stdin */
15945 /* Holds the original stdout */
15947 /* Holds the original stderr */
15949
15950#if 0
15951 /* Hack to get rdoc to regard ARGF as a class: */
15952 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15953#endif
15954
15955 rb_cARGF = rb_class_new(rb_cObject);
15956 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15957 rb_define_alloc_func(rb_cARGF, argf_alloc);
15958
15960
15961 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15962 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15963 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15964 rb_define_alias(rb_cARGF, "inspect", "to_s");
15965 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15966
15967 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15968 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15969 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15970 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15971 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15972 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15973 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15974 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15975 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15976
15977 rb_define_method(rb_cARGF, "read", argf_read, -1);
15978 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15979 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15980 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15981 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15982 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15983 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15984 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15985 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15986 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15987 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15988 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15989 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15990 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15991 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15992 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15993 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15994 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15995 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15996 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15997
15998 rb_define_method(rb_cARGF, "write", argf_write, -1);
15999 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
16000 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
16001 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
16002 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
16003
16004 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
16005 rb_define_method(rb_cARGF, "path", argf_filename, 0);
16006 rb_define_method(rb_cARGF, "file", argf_file, 0);
16007 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
16008 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
16009 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
16010
16011 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
16012 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
16013
16014 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
16015 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
16016
16017 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
16018 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
16019 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
16020
16021 argf = rb_class_new_instance(0, 0, rb_cARGF);
16022
16024 /*
16025 * ARGF is a stream designed for use in scripts that process files given
16026 * as command-line arguments or passed in via STDIN.
16027 *
16028 * See ARGF (the class) for more details.
16029 */
16031
16032 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16033 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16034 ARGF_SET(filename, rb_str_new2("-"));
16035
16036 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16037 rb_gvar_ractor_local("$-i");
16038
16039 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16040
16041#if defined (_WIN32) || defined(__CYGWIN__)
16042 atexit(pipe_atexit);
16043#endif
16044
16045 Init_File();
16046
16047 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16048
16049 sym_mode = ID2SYM(rb_intern_const("mode"));
16050 sym_perm = ID2SYM(rb_intern_const("perm"));
16051 sym_flags = ID2SYM(rb_intern_const("flags"));
16052 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16053 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16054 sym_encoding = ID2SYM(rb_id_encoding());
16055 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16056 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16057 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16058 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16059 sym_normal = ID2SYM(rb_intern_const("normal"));
16060 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16061 sym_random = ID2SYM(rb_intern_const("random"));
16062 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16063 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16064 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16065 sym_SET = ID2SYM(rb_intern_const("SET"));
16066 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16067 sym_END = ID2SYM(rb_intern_const("END"));
16068#ifdef SEEK_DATA
16069 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16070#endif
16071#ifdef SEEK_HOLE
16072 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16073#endif
16074 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16075 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16076}
16077
16078#include "io.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:117
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1608
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:789
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2908
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:3211
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:3198
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1032
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2987
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1676
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1678
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:478
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:510
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1441
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:675
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:4042
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:14754
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1428
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:4132
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:4048
#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:1431
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:14748
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2347
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:468
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1451
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:59
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3332
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:657
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2250
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2291
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:2279
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
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:555
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:668
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:191
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:192
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1308
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
Definition object.c:3313
VALUE rb_cFile
File class.
Definition file.c:192
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:3326
#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:468
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:456
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition encoding.h:571
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1378
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:843
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:2663
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:2124
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:1485
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:1781
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1825
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:1960
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:2714
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:2023
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:2977
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4343
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4349
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1742
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1792
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:8642
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4339
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:429
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:8775
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2386
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9204
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:5211
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5116
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:376
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:9385
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:250
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:330
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:2728
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:9184
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:300
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6436
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6390
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5275
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7438
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10465
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:463
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:7321
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:369
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7328
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5803
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:209
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:2109
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2103
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:3897
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1682
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1533
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1022
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1554
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2022
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3665
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4367
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3484
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:3839
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3031
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3347
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3466
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:2800
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1754
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1515
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1886
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1649
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:1639
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:1632
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3422
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1633
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1655
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2970
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:455
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:2059
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:514
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3560
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:3438
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:3997
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:869
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:6522
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:815
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:861
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:785
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1073
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:6655
#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:1019
#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:1028
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:1625
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:7138
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:6804
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2931
#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:9431
#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:1686
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:1645
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:3005
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:6929
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:792
#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:5714
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:821
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5911
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:890
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2051
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:1000
#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:827
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3460
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1581
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:9297
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:838
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1052
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:1701
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:800
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1546
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7425
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1486
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:1404
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:1473
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:1461
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:1449
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2270
#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:221
#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:14714
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9083
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:459
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:510
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:744
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:734
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:73
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:964
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:774
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:940
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:467
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:976
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:472
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:750
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
Definition scheduler.c:996
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:952
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:4783
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:230
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:238
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:131
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:372
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:359
rb_pid_t pid
child's pid (for pipes)
Definition io.h:314
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:383
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