Ruby: io.c Source File

Ruby 3.4.1p0 (2024-12-25 revision 48d4efcb85000e1ebae42004e963b5d0cedddcf2)

io.c
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
16#include "ruby/fiber/scheduler.h"
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
119#include "ruby/internal/stdbool.h"
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
187 VALUE rb_cIO;
188 VALUE rb_eEOFError;
189 VALUE rb_eIOError;
190 VALUE rb_eIOTimeoutError;
191 VALUE rb_mWaitReadable;
192 VALUE rb_mWaitWritable;
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
200
201 VALUE rb_stdin, rb_stdout, rb_stderr;
202static VALUE orig_stdout, orig_stderr;
203
204 VALUE rb_output_fs;
205 VALUE rb_rs;
206 VALUE rb_output_rs;
207 VALUE rb_default_rs;
208
209static VALUE argf;
210
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
216#ifdef SEEK_DATA
217static VALUE sym_DATA;
218#endif
219#ifdef SEEK_HOLE
220static VALUE sym_HOLE;
221#endif
222
223static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
224
225 VALUE
226rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
227{
228 return rb_thread_io_blocking_call(function, argument, io->fd, events);
229}
230
231 VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
232{
233 return rb_io_blocking_region_wait(io, function, argument, 0);
234}
235
236 struct argf {
237 VALUE filename, current_file;
238 long last_lineno; /* $. */
239 long lineno;
240 VALUE argv;
241 VALUE inplace;
242 struct rb_io_encoding encs;
243 int8_t init_p, next_p, binmode;
244};
245
246static rb_atomic_t max_file_descriptor = NOFILE;
247void
248rb_update_max_fd(int fd)
249{
250 rb_atomic_t afd = (rb_atomic_t)fd;
251 rb_atomic_t max_fd = max_file_descriptor;
252 int err;
253
254 if (fd < 0 || afd <= max_fd)
255 return;
256
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
259#else
260 {
261 struct stat buf;
262 err = fstat(fd, &buf) != 0;
263 }
264#endif
265 if (err && errno == EBADF) {
266 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
267 }
268
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
271 }
272}
273
274void
275rb_maygvl_fd_fix_cloexec(int fd)
276{
277 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
281 if (flags == -1) {
282 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
283 }
284 if (fd <= 2)
285 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
286 else
287 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
290 if (ret != 0) {
291 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
292 }
293 }
294#endif
295}
296
297void
298rb_fd_fix_cloexec(int fd)
299{
300 rb_maygvl_fd_fix_cloexec(fd);
301 rb_update_max_fd(fd);
302}
303
304/* this is only called once */
305static int
306rb_fix_detect_o_cloexec(int fd)
307{
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
310
311 if (flags == -1)
312 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
313
314 if (flags & FD_CLOEXEC)
315 return 1;
316#endif /* fall through if O_CLOEXEC does not work: */
317 rb_maygvl_fd_fix_cloexec(fd);
318 return 0;
319}
320
321static inline bool
322io_again_p(int e)
323{
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
325}
326
327int
328rb_cloexec_open(const char *pathname, int flags, mode_t mode)
329{
330 int ret;
331 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
332
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
335
336 int retry_count = 0;
337
338#ifdef O_CLOEXEC
339 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
340 flags |= O_CLOEXEC;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
343#endif
344
345 while ((ret = open(pathname, flags, mode)) == -1) {
346 int e = errno;
347 if (!io_again_p(e)) break;
348 if (retry_count++ >= retry_max_count) break;
349
350 sleep(retry_interval);
351 }
352
353 if (ret < 0) return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
356 }
357 else if (o_cloexec_state > 0) {
358 return ret;
359 }
360 else {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
362 }
363 return ret;
364}
365
366int
367rb_cloexec_dup(int oldfd)
368{
369 /* Don't allocate standard file descriptors: 0, 1, 2 */
370 return rb_cloexec_fcntl_dupfd(oldfd, 3);
371}
372
373int
374rb_cloexec_dup2(int oldfd, int newfd)
375{
376 int ret;
377
378 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
379 * rb_cloexec_dup2 succeeds as dup2. */
380 if (oldfd == newfd) {
381 ret = newfd;
382 }
383 else {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
388 if (ret != -1)
389 return ret;
390 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
391 if (errno == ENOSYS) {
392 try_dup3 = 0;
393 ret = dup2(oldfd, newfd);
394 }
395 }
396 else {
397 ret = dup2(oldfd, newfd);
398 }
399#else
400 ret = dup2(oldfd, newfd);
401#endif
402 if (ret < 0) return ret;
403 }
404 rb_maygvl_fd_fix_cloexec(ret);
405 return ret;
406}
407
408static int
409rb_fd_set_nonblock(int fd)
410{
411#ifdef _WIN32
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
415
416 if (oflags == -1)
417 return -1;
418 if (oflags & O_NONBLOCK)
419 return 0;
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
422#endif
423 return 0;
424}
425
426int
427rb_cloexec_pipe(int descriptors[2])
428{
429#ifdef HAVE_PIPE2
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
431#else
432 int result = pipe(descriptors);
433#endif
434
435 if (result < 0)
436 return result;
437
438#ifdef __CYGWIN__
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
441 descriptors[0] = -1;
442 errno = ENFILE;
443 return -1;
444 }
445#endif
446
447#ifndef HAVE_PIPE2
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
450
451#ifndef _WIN32
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
454#endif
455#endif
456
457 return result;
458}
459
460int
461rb_cloexec_fcntl_dupfd(int fd, int minfd)
462{
463 int ret;
464
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
469 if (ret != -1) {
470 if (ret <= 2)
471 rb_maygvl_fd_fix_cloexec(ret);
472 return ret;
473 }
474 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
475 if (errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
477 if (ret != -1) {
478 try_dupfd_cloexec = 0;
479 }
480 }
481 }
482 else {
483 ret = fcntl(fd, F_DUPFD, minfd);
484 }
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
487#else
488 ret = dup(fd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
491 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
492 close(prev_fd);
493 }
494 return ret;
495#endif
496 if (ret < 0) return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
498 return ret;
499}
500
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
503
504#define GetWriteIO(io) rb_io_get_write_io(io)
505
506#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
510
511#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
514
515#if defined(_WIN32)
516#define WAIT_FD_IN_WIN32(fptr) \
517 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
518#else
519#define WAIT_FD_IN_WIN32(fptr)
520#endif
521
522#define READ_CHECK(fptr) do {\
523 if (!READ_DATA_PENDING(fptr)) {\
524 WAIT_FD_IN_WIN32(fptr);\
525 rb_io_check_closed(fptr);\
526 }\
527} while(0)
528
529#ifndef S_ISSOCK
530# ifdef _S_ISSOCK
531# define S_ISSOCK(m) _S_ISSOCK(m)
532# else
533# ifdef _S_IFSOCK
534# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
535# else
536# ifdef S_IFSOCK
537# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
538# endif
539# endif
540# endif
541#endif
542
543static int io_fflush(rb_io_t *);
544static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
545static void clear_codeconv(rb_io_t *fptr);
546
547#define FMODE_SIGNAL_ON_EPIPE (1<<17)
548
549#define fptr_signal_on_epipe(fptr) \
550 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
551
552#define fptr_set_signal_on_epipe(fptr, flag) \
553 ((flag) ? \
554 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
556
557extern ID ruby_static_id_signo;
558
559NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
560static void
561rb_sys_fail_on_write(rb_io_t *fptr)
562{
563 int e = errno;
564 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
565#if defined EPIPE
566 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
567 const VALUE sig =
568# if defined SIGPIPE
569 INT2FIX(SIGPIPE) - INT2FIX(0) +
570# endif
571 INT2FIX(0);
572 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
573 }
574#endif
575 rb_exc_raise(errinfo);
576}
577
578#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581# define RUBY_CRLF_ENVIRONMENT 1
582#else
583# define RUBY_CRLF_ENVIRONMENT 0
584#endif
585
586#if RUBY_CRLF_ENVIRONMENT
587/* Windows */
588# define DEFAULT_TEXTMODE FMODE_TEXTMODE
589# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
590/*
591 * CRLF newline is set as default newline decorator.
592 * If only CRLF newline conversion is needed, we use binary IO process
593 * with OS's text mode for IO performance improvement.
594 * If encoding conversion is needed or a user sets text mode, we use encoding
595 * conversion IO process and universal newline decorator by default.
596 */
597#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598#define WRITECONV_MASK ( \
599 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600 ECONV_STATEFUL_DECORATOR_MASK|\
601 0)
602#define NEED_WRITECONV(fptr) ( \
603 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
605 0)
606#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
607
608#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610 if (((fptr)->mode & FMODE_READABLE) &&\
611 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612 setmode((fptr)->fd, O_BINARY);\
613 }\
614 else {\
615 setmode((fptr)->fd, O_TEXT);\
616 }\
617 }\
618} while(0)
619
620#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
623 }\
624} while(0)
625
626/*
627 * IO unread with taking care of removed '\r' in text mode.
628 */
629static void
630io_unread(rb_io_t *fptr, bool discard_rbuf)
631{
632 rb_off_t r, pos;
633 ssize_t read_size;
634 long i;
635 long newlines = 0;
636 long extra_max;
637 char *p;
638 char *buf;
639
640 rb_io_check_closed(fptr);
641 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
642 return;
643 }
644
645 errno = 0;
646 if (!rb_w32_fd_is_text(fptr->fd)) {
647 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
648 if (r < 0 && errno) {
649 if (errno == ESPIPE)
650 fptr->mode |= FMODE_DUPLEX;
651 if (!discard_rbuf) return;
652 }
653
654 goto end;
655 }
656
657 pos = lseek(fptr->fd, 0, SEEK_CUR);
658 if (pos < 0 && errno) {
659 if (errno == ESPIPE)
660 fptr->mode |= FMODE_DUPLEX;
661 if (!discard_rbuf) goto end;
662 }
663
664 /* add extra offset for removed '\r' in rbuf */
665 extra_max = (long)(pos - fptr->rbuf.len);
666 p = fptr->rbuf.ptr + fptr->rbuf.off;
667
668 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
669 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
670 newlines++;
671 }
672
673 for (i = 0; i < fptr->rbuf.len; i++) {
674 if (*p == '\n') newlines++;
675 if (extra_max == newlines) break;
676 p++;
677 }
678
679 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
680 while (newlines >= 0) {
681 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
682 if (newlines == 0) break;
683 if (r < 0) {
684 newlines--;
685 continue;
686 }
687 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
688 if (read_size < 0) {
689 int e = errno;
690 free(buf);
691 rb_syserr_fail_path(e, fptr->pathv);
692 }
693 if (read_size == fptr->rbuf.len) {
694 lseek(fptr->fd, r, SEEK_SET);
695 break;
696 }
697 else {
698 newlines--;
699 }
700 }
701 free(buf);
702 end:
703 fptr->rbuf.off = 0;
704 fptr->rbuf.len = 0;
705 clear_codeconv(fptr);
706 return;
707}
708
709/*
710 * We use io_seek to back cursor position when changing mode from text to binary,
711 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
712 * conversion for working properly with mode change.
713 *
714 * Return previous translation mode.
715 */
716static inline int
717set_binary_mode_with_seek_cur(rb_io_t *fptr)
718{
719 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
720
721 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
722 return setmode(fptr->fd, O_BINARY);
723 }
724 flush_before_seek(fptr, false);
725 return setmode(fptr->fd, O_BINARY);
726}
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
728
729#else
730/* Unix */
731# define DEFAULT_TEXTMODE 0
732#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733#define NEED_WRITECONV(fptr) ( \
734 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
737 0)
738#define SET_BINARY_MODE(fptr) (void)(fptr)
739#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
742#endif
743
744#if !defined HAVE_SHUTDOWN && !defined shutdown
745#define shutdown(a,b) 0
746#endif
747
748#if defined(_WIN32)
749#define is_socket(fd, path) rb_w32_is_socket(fd)
750#elif !defined(S_ISSOCK)
751#define is_socket(fd, path) 0
752#else
753static int
754is_socket(int fd, VALUE path)
755{
756 struct stat sbuf;
757 if (fstat(fd, &sbuf) < 0)
758 rb_sys_fail_path(path);
759 return S_ISSOCK(sbuf.st_mode);
760}
761#endif
762
763static const char closed_stream[] = "closed stream";
764
765static void
766io_fd_check_closed(int fd)
767{
768 if (fd < 0) {
769 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
770 rb_raise(rb_eIOError, closed_stream);
771 }
772}
773
774void
775rb_eof_error(void)
776{
777 rb_raise(rb_eEOFError, "end of file reached");
778}
779
780 VALUE
781rb_io_taint_check(VALUE io)
782{
783 rb_check_frozen(io);
784 return io;
785}
786
787void
788rb_io_check_initialized(rb_io_t *fptr)
789{
790 if (!fptr) {
791 rb_raise(rb_eIOError, "uninitialized stream");
792 }
793}
794
795void
796rb_io_check_closed(rb_io_t *fptr)
797{
798 rb_io_check_initialized(fptr);
799 io_fd_check_closed(fptr->fd);
800}
801
802static rb_io_t *
803rb_io_get_fptr(VALUE io)
804{
805 rb_io_t *fptr = RFILE(io)->fptr;
806 rb_io_check_initialized(fptr);
807 return fptr;
808}
809
810 VALUE
811rb_io_get_io(VALUE io)
812{
813 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
814}
815
816 VALUE
817rb_io_check_io(VALUE io)
818{
819 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
820}
821
822 VALUE
823rb_io_get_write_io(VALUE io)
824{
825 VALUE write_io;
826 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
827 if (write_io) {
828 return write_io;
829 }
830 return io;
831}
832
833 VALUE
834rb_io_set_write_io(VALUE io, VALUE w)
835{
836 VALUE write_io;
837 rb_io_t *fptr = rb_io_get_fptr(io);
838 if (!RTEST(w)) {
839 w = 0;
840 }
841 else {
842 GetWriteIO(w);
843 }
844 write_io = fptr->tied_io_for_writing;
845 fptr->tied_io_for_writing = w;
846 return write_io ? write_io : Qnil;
847}
848
849/*
850 * call-seq:
851 * timeout -> duration or nil
852 *
853 * Get the internal timeout duration or nil if it was not set.
854 *
855 */
856 VALUE
857rb_io_timeout(VALUE self)
858{
859 rb_io_t *fptr = rb_io_get_fptr(self);
860
861 return fptr->timeout;
862}
863
864/*
865 * call-seq:
866 * timeout = duration -> duration
867 * timeout = nil -> nil
868 *
869 * Sets the internal timeout to the specified duration or nil. The timeout
870 * applies to all blocking operations where possible.
871 *
872 * When the operation performs longer than the timeout set, IO::TimeoutError
873 * is raised.
874 *
875 * This affects the following methods (but is not limited to): #gets, #puts,
876 * #read, #write, #wait_readable and #wait_writable. This also affects
877 * blocking socket operations like Socket#accept and Socket#connect.
878 *
879 * Some operations like File#open and IO#close are not affected by the
880 * timeout. A timeout during a write operation may leave the IO in an
881 * inconsistent state, e.g. data was partially written. Generally speaking, a
882 * timeout is a last ditch effort to prevent an application from hanging on
883 * slow I/O operations, such as those that occur during a slowloris attack.
884 */
885 VALUE
886rb_io_set_timeout(VALUE self, VALUE timeout)
887{
888 // Validate it:
889 if (RTEST(timeout)) {
890 rb_time_interval(timeout);
891 }
892
893 rb_io_t *fptr = rb_io_get_fptr(self);
894
895 fptr->timeout = timeout;
896
897 return self;
898}
899
900/*
901 * call-seq:
902 * IO.try_convert(object) -> new_io or nil
903 *
904 * Attempts to convert +object+ into an \IO object via method +to_io+;
905 * returns the new \IO object if successful, or +nil+ otherwise:
906 *
907 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
908 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
909 * IO.try_convert('STDOUT') # => nil
910 *
911 */
912static VALUE
913rb_io_s_try_convert(VALUE dummy, VALUE io)
914{
915 return rb_io_check_io(io);
916}
917
918#if !RUBY_CRLF_ENVIRONMENT
919static void
920io_unread(rb_io_t *fptr, bool discard_rbuf)
921{
922 rb_off_t r;
923 rb_io_check_closed(fptr);
924 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
925 return;
926 /* xxx: target position may be negative if buffer is filled by ungetc */
927 errno = 0;
928 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
929 if (r < 0 && errno) {
930 if (errno == ESPIPE)
931 fptr->mode |= FMODE_DUPLEX;
932 if (!discard_rbuf) return;
933 }
934 fptr->rbuf.off = 0;
935 fptr->rbuf.len = 0;
936 clear_codeconv(fptr);
937 return;
938}
939#endif
940
941static rb_encoding *io_input_encoding(rb_io_t *fptr);
942
943static void
944io_ungetbyte(VALUE str, rb_io_t *fptr)
945{
946 long len = RSTRING_LEN(str);
947
948 if (fptr->rbuf.ptr == NULL) {
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
950 fptr->rbuf.off = 0;
951 fptr->rbuf.len = 0;
952#if SIZEOF_LONG > SIZEOF_INT
953 if (len > INT_MAX)
954 rb_raise(rb_eIOError, "ungetbyte failed");
955#endif
956 if (len > min_capa)
957 fptr->rbuf.capa = (int)len;
958 else
959 fptr->rbuf.capa = min_capa;
960 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
961 }
962 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
963 rb_raise(rb_eIOError, "ungetbyte failed");
964 }
965 if (fptr->rbuf.off < len) {
966 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
967 fptr->rbuf.ptr+fptr->rbuf.off,
968 char, fptr->rbuf.len);
969 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
970 }
971 fptr->rbuf.off-=(int)len;
972 fptr->rbuf.len+=(int)len;
973 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
974}
975
976static rb_io_t *
977flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
978{
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
982 errno = 0;
983 return fptr;
984}
985
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
988
989#ifndef SEEK_CUR
990# define SEEK_SET 0
991# define SEEK_CUR 1
992# define SEEK_END 2
993#endif
994
995void
996rb_io_check_char_readable(rb_io_t *fptr)
997{
998 rb_io_check_closed(fptr);
999 if (!(fptr->mode & FMODE_READABLE)) {
1000 rb_raise(rb_eIOError, "not opened for reading");
1001 }
1002 if (fptr->wbuf.len) {
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1005 }
1006 if (fptr->tied_io_for_writing) {
1007 rb_io_t *wfptr;
1008 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1011 }
1012}
1013
1014void
1015rb_io_check_byte_readable(rb_io_t *fptr)
1016{
1017 rb_io_check_char_readable(fptr);
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1020 }
1021}
1022
1023void
1024rb_io_check_readable(rb_io_t *fptr)
1025{
1026 rb_io_check_byte_readable(fptr);
1027}
1028
1029static rb_encoding*
1030io_read_encoding(rb_io_t *fptr)
1031{
1032 if (fptr->encs.enc) {
1033 return fptr->encs.enc;
1034 }
1035 return rb_default_external_encoding();
1036}
1037
1038static rb_encoding*
1039io_input_encoding(rb_io_t *fptr)
1040{
1041 if (fptr->encs.enc2) {
1042 return fptr->encs.enc2;
1043 }
1044 return io_read_encoding(fptr);
1045}
1046
1047void
1048rb_io_check_writable(rb_io_t *fptr)
1049{
1050 rb_io_check_closed(fptr);
1051 if (!(fptr->mode & FMODE_WRITABLE)) {
1052 rb_raise(rb_eIOError, "not opened for writing");
1053 }
1054 if (fptr->rbuf.len) {
1055 io_unread(fptr, true);
1056 }
1057}
1058
1059int
1060rb_io_read_pending(rb_io_t *fptr)
1061{
1062 /* This function is used for bytes and chars. Confusing. */
1063 if (READ_CHAR_PENDING(fptr))
1064 return 1; /* should raise? */
1065 return READ_DATA_PENDING(fptr);
1066}
1067
1068void
1069rb_io_read_check(rb_io_t *fptr)
1070{
1071 if (!READ_DATA_PENDING(fptr)) {
1072 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1073 }
1074 return;
1075}
1076
1077int
1078rb_gc_for_fd(int err)
1079{
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1081 rb_gc();
1082 return 1;
1083 }
1084 return 0;
1085}
1086
1087/* try `expr` upto twice while it returns false and `errno`
1088 * is to GC. Each `errno`s are available as `first_errno` and
1089 * `retried_errno` respectively */
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1092 (!retried && \
1093 !(expr) && \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1097
1098static int
1099ruby_dup(int orig)
1100{
1101 int fd = -1;
1102
1103 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1104 rb_syserr_fail(first_errno, 0);
1105 }
1106 rb_update_max_fd(fd);
1107 return fd;
1108}
1109
1110static VALUE
1111io_alloc(VALUE klass)
1112{
1113 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1114
1115 io->fptr = 0;
1116
1117 return (VALUE)io;
1118}
1119
1120#ifndef S_ISREG
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1122#endif
1123
1124 struct io_internal_read_struct {
1125 VALUE th;
1126 rb_io_t *fptr;
1127 int nonblock;
1128 int fd;
1129
1130 void *buf;
1131 size_t capa;
1132 struct timeval *timeout;
1133};
1134
1135 struct io_internal_write_struct {
1136 VALUE th;
1137 rb_io_t *fptr;
1138 int nonblock;
1139 int fd;
1140
1141 const void *buf;
1142 size_t capa;
1143 struct timeval *timeout;
1144};
1145
1146#ifdef HAVE_WRITEV
1147struct io_internal_writev_struct {
1148 VALUE th;
1149 rb_io_t *fptr;
1150 int nonblock;
1151 int fd;
1152
1153 int iovcnt;
1154 const struct iovec *iov;
1155 struct timeval *timeout;
1156};
1157#endif
1158
1159static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1160
1166static inline int
1167io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1168{
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1170 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1171 return -1;
1172 }
1173
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1175
1176 if (ready > 0) {
1177 return ready;
1178 }
1179 else if (ready == 0) {
1180 errno = ETIMEDOUT;
1181 return -1;
1182 }
1183
1184 errno = error;
1185 return -1;
1186}
1187
1188static VALUE
1189internal_read_func(void *ptr)
1190{
1191 struct io_internal_read_struct *iis = ptr;
1192 ssize_t result;
1193
1194 if (iis->timeout && !iis->nonblock) {
1195 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1196 return -1;
1197 }
1198 }
1199
1200 retry:
1201 result = read(iis->fd, iis->buf, iis->capa);
1202
1203 if (result < 0 && !iis->nonblock) {
1204 if (io_again_p(errno)) {
1205 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1206 return -1;
1207 }
1208 else {
1209 goto retry;
1210 }
1211 }
1212 }
1213
1214 return result;
1215}
1216
1217#if defined __APPLE__
1218# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1219#else
1220# define do_write_retry(code) result = code
1221#endif
1222
1223static VALUE
1224internal_write_func(void *ptr)
1225{
1226 struct io_internal_write_struct *iis = ptr;
1227 ssize_t result;
1228
1229 if (iis->timeout && !iis->nonblock) {
1230 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1231 return -1;
1232 }
1233 }
1234
1235 retry:
1236 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1237
1238 if (result < 0 && !iis->nonblock) {
1239 int e = errno;
1240 if (io_again_p(e)) {
1241 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1242 return -1;
1243 }
1244 else {
1245 goto retry;
1246 }
1247 }
1248 }
1249
1250 return result;
1251}
1252
1253#ifdef HAVE_WRITEV
1254static VALUE
1255internal_writev_func(void *ptr)
1256{
1257 struct io_internal_writev_struct *iis = ptr;
1258 ssize_t result;
1259
1260 if (iis->timeout && !iis->nonblock) {
1261 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1262 return -1;
1263 }
1264 }
1265
1266 retry:
1267 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1268
1269 if (result < 0 && !iis->nonblock) {
1270 if (io_again_p(errno)) {
1271 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1272 return -1;
1273 }
1274 else {
1275 goto retry;
1276 }
1277 }
1278 }
1279
1280 return result;
1281}
1282#endif
1283
1284static ssize_t
1285rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1286{
1287 VALUE scheduler = rb_fiber_scheduler_current();
1288 if (scheduler != Qnil) {
1289 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1290
1291 if (!UNDEF_P(result)) {
1292 return rb_fiber_scheduler_io_result_apply(result);
1293 }
1294 }
1295
1296 struct io_internal_read_struct iis = {
1297 .th = rb_thread_current(),
1298 .fptr = fptr,
1299 .nonblock = 0,
1300 .fd = fptr->fd,
1301
1302 .buf = buf,
1303 .capa = count,
1304 .timeout = NULL,
1305 };
1306
1307 struct timeval timeout_storage;
1308
1309 if (fptr->timeout != Qnil) {
1310 timeout_storage = rb_time_interval(fptr->timeout);
1311 iis.timeout = &timeout_storage;
1312 }
1313
1314 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1315}
1316
1317static ssize_t
1318rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1319{
1320 VALUE scheduler = rb_fiber_scheduler_current();
1321 if (scheduler != Qnil) {
1322 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1323
1324 if (!UNDEF_P(result)) {
1325 return rb_fiber_scheduler_io_result_apply(result);
1326 }
1327 }
1328
1329 struct io_internal_write_struct iis = {
1330 .th = rb_thread_current(),
1331 .fptr = fptr,
1332 .nonblock = 0,
1333 .fd = fptr->fd,
1334
1335 .buf = buf,
1336 .capa = count,
1337 .timeout = NULL
1338 };
1339
1340 struct timeval timeout_storage;
1341
1342 if (fptr->timeout != Qnil) {
1343 timeout_storage = rb_time_interval(fptr->timeout);
1344 iis.timeout = &timeout_storage;
1345 }
1346
1347 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1348}
1349
1350#ifdef HAVE_WRITEV
1351static ssize_t
1352rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1353{
1354 if (!iovcnt) return 0;
1355
1356 VALUE scheduler = rb_fiber_scheduler_current();
1357 if (scheduler != Qnil) {
1358 // This path assumes at least one `iov`:
1359 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1360
1361 if (!UNDEF_P(result)) {
1362 return rb_fiber_scheduler_io_result_apply(result);
1363 }
1364 }
1365
1366 struct io_internal_writev_struct iis = {
1367 .th = rb_thread_current(),
1368 .fptr = fptr,
1369 .nonblock = 0,
1370 .fd = fptr->fd,
1371
1372 .iov = iov,
1373 .iovcnt = iovcnt,
1374 .timeout = NULL
1375 };
1376
1377 struct timeval timeout_storage;
1378
1379 if (fptr->timeout != Qnil) {
1380 timeout_storage = rb_time_interval(fptr->timeout);
1381 iis.timeout = &timeout_storage;
1382 }
1383
1384 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1385}
1386#endif
1387
1388static VALUE
1389io_flush_buffer_sync(void *arg)
1390{
1391 rb_io_t *fptr = arg;
1392 long l = fptr->wbuf.len;
1393 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1394
1395 if (fptr->wbuf.len <= r) {
1396 fptr->wbuf.off = 0;
1397 fptr->wbuf.len = 0;
1398 return 0;
1399 }
1400
1401 if (0 <= r) {
1402 fptr->wbuf.off += (int)r;
1403 fptr->wbuf.len -= (int)r;
1404 errno = EAGAIN;
1405 }
1406
1407 return (VALUE)-1;
1408}
1409
1410static VALUE
1411io_flush_buffer_async(VALUE arg)
1412{
1413 rb_io_t *fptr = (rb_io_t *)arg;
1414 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1415}
1416
1417static inline int
1418io_flush_buffer(rb_io_t *fptr)
1419{
1420 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1421 return (int)io_flush_buffer_async((VALUE)fptr);
1422 }
1423 else {
1424 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1425 }
1426}
1427
1428static int
1429io_fflush(rb_io_t *fptr)
1430{
1431 rb_io_check_closed(fptr);
1432
1433 if (fptr->wbuf.len == 0)
1434 return 0;
1435
1436 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1437 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1438 return -1;
1439
1440 rb_io_check_closed(fptr);
1441 }
1442
1443 return 0;
1444}
1445
1446 VALUE
1447rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1448{
1449 VALUE scheduler = rb_fiber_scheduler_current();
1450
1451 if (scheduler != Qnil) {
1452 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1453 }
1454
1455 rb_io_t * fptr = NULL;
1456 RB_IO_POINTER(io, fptr);
1457
1458 struct timeval tv_storage;
1459 struct timeval *tv = NULL;
1460
1461 if (NIL_OR_UNDEF_P(timeout)) {
1462 timeout = fptr->timeout;
1463 }
1464
1465 if (timeout != Qnil) {
1466 tv_storage = rb_time_interval(timeout);
1467 tv = &tv_storage;
1468 }
1469
1470 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1471
1472 if (ready < 0) {
1473 rb_sys_fail(0);
1474 }
1475
1476 // Not sure if this is necessary:
1477 rb_io_check_closed(fptr);
1478
1479 if (ready) {
1480 return RB_INT2NUM(ready);
1481 }
1482 else {
1483 return Qfalse;
1484 }
1485}
1486
1487static VALUE
1488io_from_fd(int fd)
1489{
1490 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1491}
1492
1493static int
1494io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1495{
1496 VALUE scheduler = rb_fiber_scheduler_current();
1497
1498 if (scheduler != Qnil) {
1499 return RTEST(
1500 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1501 );
1502 }
1503
1504 return rb_thread_wait_for_single_fd(fd, events, timeout);
1505}
1506
1507int
1508rb_io_wait_readable(int f)
1509{
1510 io_fd_check_closed(f);
1511
1512 VALUE scheduler = rb_fiber_scheduler_current();
1513
1514 switch (errno) {
1515 case EINTR:
1516#if defined(ERESTART)
1517 case ERESTART:
1518#endif
1519 rb_thread_check_ints();
1520 return TRUE;
1521
1522 case EAGAIN:
1523#if EWOULDBLOCK != EAGAIN
1524 case EWOULDBLOCK:
1525#endif
1526 if (scheduler != Qnil) {
1527 return RTEST(
1528 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1529 );
1530 }
1531 else {
1532 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1533 }
1534 return TRUE;
1535
1536 default:
1537 return FALSE;
1538 }
1539}
1540
1541int
1542rb_io_wait_writable(int f)
1543{
1544 io_fd_check_closed(f);
1545
1546 VALUE scheduler = rb_fiber_scheduler_current();
1547
1548 switch (errno) {
1549 case EINTR:
1550#if defined(ERESTART)
1551 case ERESTART:
1552#endif
1553 /*
1554 * In old Linux, several special files under /proc and /sys don't handle
1555 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1556 * Otherwise, we face nasty hang up. Sigh.
1557 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1558 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1559 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1560 * Then rb_thread_check_ints() is enough.
1561 */
1562 rb_thread_check_ints();
1563 return TRUE;
1564
1565 case EAGAIN:
1566#if EWOULDBLOCK != EAGAIN
1567 case EWOULDBLOCK:
1568#endif
1569 if (scheduler != Qnil) {
1570 return RTEST(
1571 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1572 );
1573 }
1574 else {
1575 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1576 }
1577 return TRUE;
1578
1579 default:
1580 return FALSE;
1581 }
1582}
1583
1584int
1585rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1586{
1587 return io_wait_for_single_fd(fd, events, timeout);
1588}
1589
1590int
1591rb_thread_wait_fd(int fd)
1592{
1593 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1594}
1595
1596int
1597rb_thread_fd_writable(int fd)
1598{
1599 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1600}
1601
1602 VALUE
1603rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1604{
1605 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1606 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1607 // instead relies on `read(-1) -> -1` which causes this code path. We then
1608 // check here whether the IO was in fact closed. Probably it's better to
1609 // check that `fptr->fd != -1` before using it in syscall.
1610 rb_io_check_closed(RFILE(io)->fptr);
1611
1612 switch (error) {
1613 // In old Linux, several special files under /proc and /sys don't handle
1614 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1615 // Otherwise, we face nasty hang up. Sigh.
1616 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1617 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1618 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1619 // Then rb_thread_check_ints() is enough.
1620 case EINTR:
1621#if defined(ERESTART)
1622 case ERESTART:
1623#endif
1624 // We might have pending interrupts since the previous syscall was interrupted:
1625 rb_thread_check_ints();
1626
1627 // The operation was interrupted, so retry it immediately:
1628 return events;
1629
1630 case EAGAIN:
1631#if EWOULDBLOCK != EAGAIN
1632 case EWOULDBLOCK:
1633#endif
1634 // The operation would block, so wait for the specified events:
1635 return rb_io_wait(io, events, timeout);
1636
1637 default:
1638 // Non-specific error, no event is ready:
1639 return Qnil;
1640 }
1641}
1642
1643int
1644rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
1645{
1646 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1647
1648 if (RTEST(result)) {
1649 return RB_NUM2INT(result);
1650 }
1651 else if (result == RUBY_Qfalse) {
1652 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1653 }
1654
1655 return 0;
1656}
1657
1658int
1659rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
1660{
1661 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1662
1663 if (RTEST(result)) {
1664 return RB_NUM2INT(result);
1665 }
1666 else if (result == RUBY_Qfalse) {
1667 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1668 }
1669
1670 return 0;
1671}
1672
1673static void
1674make_writeconv(rb_io_t *fptr)
1675{
1676 if (!fptr->writeconv_initialized) {
1677 const char *senc, *denc;
1678 rb_encoding *enc;
1679 int ecflags;
1680 VALUE ecopts;
1681
1682 fptr->writeconv_initialized = 1;
1683
1684 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1685 ecopts = fptr->encs.ecopts;
1686
1687 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1688 /* no encoding conversion */
1689 fptr->writeconv_pre_ecflags = 0;
1690 fptr->writeconv_pre_ecopts = Qnil;
1691 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1692 if (!fptr->writeconv)
1693 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1694 fptr->writeconv_asciicompat = Qnil;
1695 }
1696 else {
1697 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1698 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1699 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1700 /* single conversion */
1701 fptr->writeconv_pre_ecflags = ecflags;
1702 fptr->writeconv_pre_ecopts = ecopts;
1703 fptr->writeconv = NULL;
1704 fptr->writeconv_asciicompat = Qnil;
1705 }
1706 else {
1707 /* double conversion */
1708 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1709 fptr->writeconv_pre_ecopts = ecopts;
1710 if (senc) {
1711 denc = rb_enc_name(enc);
1712 fptr->writeconv_asciicompat = rb_str_new2(senc);
1713 }
1714 else {
1715 senc = denc = "";
1716 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1717 }
1718 ecflags = fptr->encs.ecflags & (ECONV_ERROR_HANDLER_MASK|ECONV_STATEFUL_DECORATOR_MASK);
1719 ecopts = fptr->encs.ecopts;
1720 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1721 if (!fptr->writeconv)
1722 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1723 }
1724 }
1725 }
1726}
1727
1728/* writing functions */
1729 struct binwrite_arg {
1730 rb_io_t *fptr;
1731 const char *ptr;
1732 long length;
1733};
1734
1735 struct write_arg {
1736 VALUE io;
1737 VALUE str;
1738 int nosync;
1739};
1740
1741#ifdef HAVE_WRITEV
1742static ssize_t
1743io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1744{
1745 if (fptr->wbuf.len) {
1746 struct iovec iov[2];
1747
1748 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1749 iov[0].iov_len = fptr->wbuf.len;
1750 iov[1].iov_base = (void*)ptr;
1751 iov[1].iov_len = length;
1752
1753 ssize_t result = rb_writev_internal(fptr, iov, 2);
1754
1755 if (result < 0)
1756 return result;
1757
1758 if (result >= fptr->wbuf.len) {
1759 // We wrote more than the internal buffer:
1760 result -= fptr->wbuf.len;
1761 fptr->wbuf.off = 0;
1762 fptr->wbuf.len = 0;
1763 }
1764 else {
1765 // We only wrote less data than the internal buffer:
1766 fptr->wbuf.off += (int)result;
1767 fptr->wbuf.len -= (int)result;
1768
1769 result = 0;
1770 }
1771
1772 return result;
1773 }
1774 else {
1775 return rb_io_write_memory(fptr, ptr, length);
1776 }
1777}
1778#else
1779static ssize_t
1780io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1781{
1782 long remaining = length;
1783
1784 if (fptr->wbuf.len) {
1785 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1786 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1787 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1788 fptr->wbuf.off = 0;
1789 }
1790
1791 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1792 fptr->wbuf.len += (int)length;
1793
1794 // We copied the entire incoming data to the internal buffer:
1795 remaining = 0;
1796 }
1797
1798 // Flush the internal buffer:
1799 if (io_fflush(fptr) < 0) {
1800 return -1;
1801 }
1802
1803 // If all the data was buffered, we are done:
1804 if (remaining == 0) {
1805 return length;
1806 }
1807 }
1808
1809 // Otherwise, we should write the data directly:
1810 return rb_io_write_memory(fptr, ptr, length);
1811}
1812#endif
1813
1814static VALUE
1815io_binwrite_string(VALUE arg)
1816{
1817 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1818
1819 const char *ptr = p->ptr;
1820 size_t remaining = p->length;
1821
1822 while (remaining) {
1823 // Write as much as possible:
1824 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1825
1826 if (result == 0) {
1827 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1828 // should try again immediately.
1829 }
1830 else if (result > 0) {
1831 if ((size_t)result == remaining) break;
1832 ptr += result;
1833 remaining -= result;
1834 }
1835 // Wait for it to become writable:
1836 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1837 rb_io_check_closed(p->fptr);
1838 }
1839 else {
1840 // The error was unrelated to waiting for it to become writable, so we fail:
1841 return -1;
1842 }
1843 }
1844
1845 return p->length;
1846}
1847
1848inline static void
1849io_allocate_write_buffer(rb_io_t *fptr, int sync)
1850{
1851 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1852 fptr->wbuf.off = 0;
1853 fptr->wbuf.len = 0;
1854 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1855 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1856 }
1857
1858 if (NIL_P(fptr->write_lock)) {
1859 fptr->write_lock = rb_mutex_new();
1860 rb_mutex_allow_trap(fptr->write_lock, 1);
1861 }
1862}
1863
1864static inline int
1865io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1866{
1867 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1868 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1869 return 1;
1870
1871 // If the amount of data we want to write exceeds the internal buffer:
1872 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1873 return 1;
1874
1875 // Otherwise, we can append to the internal buffer:
1876 return 0;
1877}
1878
1879static long
1880io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1881{
1882 if (len <= 0) return len;
1883
1884 // Don't write anything if current thread has a pending interrupt:
1885 rb_thread_check_ints();
1886
1887 io_allocate_write_buffer(fptr, !nosync);
1888
1889 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1890 struct binwrite_arg arg;
1891
1892 arg.fptr = fptr;
1893 arg.ptr = ptr;
1894 arg.length = len;
1895
1896 if (!NIL_P(fptr->write_lock)) {
1897 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1898 }
1899 else {
1900 return io_binwrite_string((VALUE)&arg);
1901 }
1902 }
1903 else {
1904 if (fptr->wbuf.off) {
1905 if (fptr->wbuf.len)
1906 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1907 fptr->wbuf.off = 0;
1908 }
1909
1910 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1911 fptr->wbuf.len += (int)len;
1912
1913 return len;
1914 }
1915}
1916
1917# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1918 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1919
1920#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1921 MODE_BTMODE(d, e, f) : \
1922 MODE_BTMODE(a, b, c))
1923
1924static VALUE
1925do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1926{
1927 if (NEED_WRITECONV(fptr)) {
1928 VALUE common_encoding = Qnil;
1929 SET_BINARY_MODE(fptr);
1930
1931 make_writeconv(fptr);
1932
1933 if (fptr->writeconv) {
1934#define fmode (fptr->mode)
1935 if (!NIL_P(fptr->writeconv_asciicompat))
1936 common_encoding = fptr->writeconv_asciicompat;
1937 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1938 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1939 rb_enc_name(rb_enc_get(str)));
1940 }
1941#undef fmode
1942 }
1943 else {
1944 if (fptr->encs.enc2)
1945 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1946 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1947 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1948 }
1949
1950 if (!NIL_P(common_encoding)) {
1951 str = rb_str_encode(str, common_encoding,
1952 fptr->writeconv_pre_ecflags, fptr->writeconv_pre_ecopts);
1953 *converted = 1;
1954 }
1955
1956 if (fptr->writeconv) {
1957 str = rb_econv_str_convert(fptr->writeconv, str, ECONV_PARTIAL_INPUT);
1958 *converted = 1;
1959 }
1960 }
1961#if RUBY_CRLF_ENVIRONMENT
1962#define fmode (fptr->mode)
1963 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1964 if ((fptr->mode & FMODE_READABLE) &&
1965 !(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
1966 setmode(fptr->fd, O_BINARY);
1967 }
1968 else {
1969 setmode(fptr->fd, O_TEXT);
1970 }
1971 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1972 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1973 rb_enc_name(rb_enc_get(str)));
1974 }
1975 }
1976#undef fmode
1977#endif
1978 return str;
1979}
1980
1981static long
1982io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1983{
1984 int converted = 0;
1985 VALUE tmp;
1986 long n, len;
1987 const char *ptr;
1988
1989#ifdef _WIN32
1990 if (fptr->mode & FMODE_TTY) {
1991 long len = rb_w32_write_console(str, fptr->fd);
1992 if (len > 0) return len;
1993 }
1994#endif
1995
1996 str = do_writeconv(str, fptr, &converted);
1997 if (converted)
1998 OBJ_FREEZE(str);
1999
2000 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2001 RSTRING_GETMEM(tmp, ptr, len);
2002 n = io_binwrite(ptr, len, fptr, nosync);
2003 rb_str_tmp_frozen_release(str, tmp);
2004
2005 return n;
2006}
2007
2008ssize_t
2009rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2010{
2011 rb_io_t *fptr;
2012
2013 GetOpenFile(io, fptr);
2014 rb_io_check_writable(fptr);
2015 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2016}
2017
2018static VALUE
2019io_write(VALUE io, VALUE str, int nosync)
2020{
2021 rb_io_t *fptr;
2022 long n;
2023 VALUE tmp;
2024
2025 io = GetWriteIO(io);
2026 str = rb_obj_as_string(str);
2027 tmp = rb_io_check_io(io);
2028
2029 if (NIL_P(tmp)) {
2030 /* port is not IO, call write method for it. */
2031 return rb_funcall(io, id_write, 1, str);
2032 }
2033
2034 io = tmp;
2035 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2036
2037 GetOpenFile(io, fptr);
2038 rb_io_check_writable(fptr);
2039
2040 n = io_fwrite(str, fptr, nosync);
2041 if (n < 0L) rb_sys_fail_on_write(fptr);
2042
2043 return LONG2FIX(n);
2044}
2045
2046#ifdef HAVE_WRITEV
2047struct binwritev_arg {
2048 rb_io_t *fptr;
2049 struct iovec *iov;
2050 int iovcnt;
2051 size_t total;
2052};
2053
2054static VALUE
2055io_binwritev_internal(VALUE arg)
2056{
2057 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2058
2059 size_t remaining = p->total;
2060 size_t offset = 0;
2061
2062 rb_io_t *fptr = p->fptr;
2063 struct iovec *iov = p->iov;
2064 int iovcnt = p->iovcnt;
2065
2066 while (remaining) {
2067 long result = rb_writev_internal(fptr, iov, iovcnt);
2068
2069 if (result >= 0) {
2070 offset += result;
2071 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2072 if (offset < (size_t)fptr->wbuf.len) {
2073 fptr->wbuf.off += result;
2074 fptr->wbuf.len -= result;
2075 }
2076 else {
2077 offset -= (size_t)fptr->wbuf.len;
2078 fptr->wbuf.off = 0;
2079 fptr->wbuf.len = 0;
2080 }
2081 }
2082
2083 if (offset == p->total) {
2084 return p->total;
2085 }
2086
2087 while (result >= (ssize_t)iov->iov_len) {
2088 /* iovcnt > 0 */
2089 result -= iov->iov_len;
2090 iov->iov_len = 0;
2091 iov++;
2092
2093 if (!--iovcnt) {
2094 // I don't believe this code path can ever occur.
2095 return offset;
2096 }
2097 }
2098
2099 iov->iov_base = (char *)iov->iov_base + result;
2100 iov->iov_len -= result;
2101 }
2102 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2103 rb_io_check_closed(fptr);
2104 }
2105 else {
2106 return -1;
2107 }
2108 }
2109
2110 return offset;
2111}
2112
2113static long
2114io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2115{
2116 // Don't write anything if current thread has a pending interrupt:
2117 rb_thread_check_ints();
2118
2119 if (iovcnt == 0) return 0;
2120
2121 size_t total = 0;
2122 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2123
2124 io_allocate_write_buffer(fptr, 1);
2125
2126 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2127 // The end of the buffered data:
2128 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2129
2130 if (offset + total <= (size_t)fptr->wbuf.capa) {
2131 for (int i = 1; i < iovcnt; i++) {
2132 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2133 offset += iov[i].iov_len;
2134 }
2135
2136 fptr->wbuf.len += total;
2137
2138 return total;
2139 }
2140 else {
2141 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2142 iov[0].iov_len = fptr->wbuf.len;
2143 }
2144 }
2145 else {
2146 // The first iov is reserved for the internal buffer, and it's empty.
2147 iov++;
2148
2149 if (!--iovcnt) {
2150 // If there are no other io vectors we are done.
2151 return 0;
2152 }
2153 }
2154
2155 struct binwritev_arg arg;
2156 arg.fptr = fptr;
2157 arg.iov = iov;
2158 arg.iovcnt = iovcnt;
2159 arg.total = total;
2160
2161 if (!NIL_P(fptr->write_lock)) {
2162 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2163 }
2164 else {
2165 return io_binwritev_internal((VALUE)&arg);
2166 }
2167}
2168
2169static long
2170io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2171{
2172 int i, converted, iovcnt = argc + 1;
2173 long n;
2174 VALUE v1, v2, str, tmp, *tmp_array;
2175 struct iovec *iov;
2176
2177 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2178 tmp_array = ALLOCV_N(VALUE, v2, argc);
2179
2180 for (i = 0; i < argc; i++) {
2181 str = rb_obj_as_string(argv[i]);
2182 converted = 0;
2183 str = do_writeconv(str, fptr, &converted);
2184
2185 if (converted)
2186 OBJ_FREEZE(str);
2187
2188 tmp = rb_str_tmp_frozen_acquire(str);
2189 tmp_array[i] = tmp;
2190
2191 /* iov[0] is reserved for buffer of fptr */
2192 iov[i+1].iov_base = RSTRING_PTR(tmp);
2193 iov[i+1].iov_len = RSTRING_LEN(tmp);
2194 }
2195
2196 n = io_binwritev(iov, iovcnt, fptr);
2197 if (v1) ALLOCV_END(v1);
2198
2199 for (i = 0; i < argc; i++) {
2200 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2201 }
2202
2203 if (v2) ALLOCV_END(v2);
2204
2205 return n;
2206}
2207
2208static int
2209iovcnt_ok(int iovcnt)
2210{
2211#ifdef IOV_MAX
2212 return iovcnt < IOV_MAX;
2213#else /* GNU/Hurd has writev, but no IOV_MAX */
2214 return 1;
2215#endif
2216}
2217#endif /* HAVE_WRITEV */
2218
2219static VALUE
2220io_writev(int argc, const VALUE *argv, VALUE io)
2221{
2222 rb_io_t *fptr;
2223 long n;
2224 VALUE tmp, total = INT2FIX(0);
2225 int i, cnt = 1;
2226
2227 io = GetWriteIO(io);
2228 tmp = rb_io_check_io(io);
2229
2230 if (NIL_P(tmp)) {
2231 /* port is not IO, call write method for it. */
2232 return rb_funcallv(io, id_write, argc, argv);
2233 }
2234
2235 io = tmp;
2236
2237 GetOpenFile(io, fptr);
2238 rb_io_check_writable(fptr);
2239
2240 for (i = 0; i < argc; i += cnt) {
2241#ifdef HAVE_WRITEV
2242 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2243 n = io_fwritev(cnt, &argv[i], fptr);
2244 }
2245 else
2246#endif
2247 {
2248 cnt = 1;
2249 /* sync at last item */
2250 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2251 }
2252
2253 if (n < 0L)
2254 rb_sys_fail_on_write(fptr);
2255
2256 total = rb_fix_plus(LONG2FIX(n), total);
2257 }
2258
2259 return total;
2260}
2261
2262/*
2263 * call-seq:
2264 * write(*objects) -> integer
2265 *
2266 * Writes each of the given +objects+ to +self+,
2267 * which must be opened for writing
2268 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2269 * returns the total number bytes written;
2270 * each of +objects+ that is not a string is converted via method +to_s+:
2271 *
2272 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2273 * $stdout.write('foo', :bar, 2, "\n") # => 8
2274 *
2275 * Output:
2276 *
2277 * Hello, World!
2278 * foobar2
2279 *
2280 * Related: IO#read.
2281 */
2282
2283static VALUE
2284io_write_m(int argc, VALUE *argv, VALUE io)
2285{
2286 if (argc != 1) {
2287 return io_writev(argc, argv, io);
2288 }
2289 else {
2290 VALUE str = argv[0];
2291 return io_write(io, str, 0);
2292 }
2293}
2294
2295 VALUE
2296rb_io_write(VALUE io, VALUE str)
2297{
2298 return rb_funcallv(io, id_write, 1, &str);
2299}
2300
2301static VALUE
2302rb_io_writev(VALUE io, int argc, const VALUE *argv)
2303{
2304 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2305 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2306 VALUE klass = CLASS_OF(io);
2307 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2308 rb_category_warning(
2309 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2310 " which accepts just one argument",
2311 klass, sep
2312 );
2313 }
2314
2315 do rb_io_write(io, *argv++); while (--argc);
2316
2317 return Qnil;
2318 }
2319
2320 return rb_funcallv(io, id_write, argc, argv);
2321}
2322
2323/*
2324 * call-seq:
2325 * self << object -> self
2326 *
2327 * Writes the given +object+ to +self+,
2328 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2329 * returns +self+;
2330 * if +object+ is not a string, it is converted via method +to_s+:
2331 *
2332 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2333 * $stdout << 'foo' << :bar << 2 << "\n"
2334 *
2335 * Output:
2336 *
2337 * Hello, World!
2338 * foobar2
2339 *
2340 */
2341
2342
2343 VALUE
2344rb_io_addstr(VALUE io, VALUE str)
2345{
2346 rb_io_write(io, str);
2347 return io;
2348}
2349
2350#ifdef HAVE_FSYNC
2351static VALUE
2352nogvl_fsync(void *ptr)
2353{
2354 rb_io_t *fptr = ptr;
2355
2356#ifdef _WIN32
2357 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2358 return 0;
2359#endif
2360 return (VALUE)fsync(fptr->fd);
2361}
2362#endif
2363
2364 VALUE
2365rb_io_flush_raw(VALUE io, int sync)
2366{
2367 rb_io_t *fptr;
2368
2369 if (!RB_TYPE_P(io, T_FILE)) {
2370 return rb_funcall(io, id_flush, 0);
2371 }
2372
2373 io = GetWriteIO(io);
2374 GetOpenFile(io, fptr);
2375
2376 if (fptr->mode & FMODE_WRITABLE) {
2377 if (io_fflush(fptr) < 0)
2378 rb_sys_fail_on_write(fptr);
2379 }
2380 if (fptr->mode & FMODE_READABLE) {
2381 io_unread(fptr, true);
2382 }
2383
2384 return io;
2385}
2386
2387/*
2388 * call-seq:
2389 * flush -> self
2390 *
2391 * Flushes data buffered in +self+ to the operating system
2392 * (but does not necessarily flush data buffered in the operating system):
2393 *
2394 * $stdout.print 'no newline' # Not necessarily flushed.
2395 * $stdout.flush # Flushed.
2396 *
2397 */
2398
2399 VALUE
2400rb_io_flush(VALUE io)
2401{
2402 return rb_io_flush_raw(io, 1);
2403}
2404
2405/*
2406 * call-seq:
2407 * tell -> integer
2408 *
2409 * Returns the current position (in bytes) in +self+
2410 * (see {Position}[rdoc-ref:IO@Position]):
2411 *
2412 * f = File.open('t.txt')
2413 * f.tell # => 0
2414 * f.gets # => "First line\n"
2415 * f.tell # => 12
2416 * f.close
2417 *
2418 * Related: IO#pos=, IO#seek.
2419 */
2420
2421static VALUE
2422rb_io_tell(VALUE io)
2423{
2424 rb_io_t *fptr;
2425 rb_off_t pos;
2426
2427 GetOpenFile(io, fptr);
2428 pos = io_tell(fptr);
2429 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2430 pos -= fptr->rbuf.len;
2431 return OFFT2NUM(pos);
2432}
2433
2434static VALUE
2435rb_io_seek(VALUE io, VALUE offset, int whence)
2436{
2437 rb_io_t *fptr;
2438 rb_off_t pos;
2439
2440 pos = NUM2OFFT(offset);
2441 GetOpenFile(io, fptr);
2442 pos = io_seek(fptr, pos, whence);
2443 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2444
2445 return INT2FIX(0);
2446}
2447
2448static int
2449interpret_seek_whence(VALUE vwhence)
2450{
2451 if (vwhence == sym_SET)
2452 return SEEK_SET;
2453 if (vwhence == sym_CUR)
2454 return SEEK_CUR;
2455 if (vwhence == sym_END)
2456 return SEEK_END;
2457#ifdef SEEK_DATA
2458 if (vwhence == sym_DATA)
2459 return SEEK_DATA;
2460#endif
2461#ifdef SEEK_HOLE
2462 if (vwhence == sym_HOLE)
2463 return SEEK_HOLE;
2464#endif
2465 return NUM2INT(vwhence);
2466}
2467
2468/*
2469 * call-seq:
2470 * seek(offset, whence = IO::SEEK_SET) -> 0
2471 *
2472 * Seeks to the position given by integer +offset+
2473 * (see {Position}[rdoc-ref:IO@Position])
2474 * and constant +whence+, which is one of:
2475 *
2476 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2477 * Repositions the stream to its current position plus the given +offset+:
2478 *
2479 * f = File.open('t.txt')
2480 * f.tell # => 0
2481 * f.seek(20, :CUR) # => 0
2482 * f.tell # => 20
2483 * f.seek(-10, :CUR) # => 0
2484 * f.tell # => 10
2485 * f.close
2486 *
2487 * - +:END+ or <tt>IO::SEEK_END</tt>:
2488 * Repositions the stream to its end plus the given +offset+:
2489 *
2490 * f = File.open('t.txt')
2491 * f.tell # => 0
2492 * f.seek(0, :END) # => 0 # Repositions to stream end.
2493 * f.tell # => 52
2494 * f.seek(-20, :END) # => 0
2495 * f.tell # => 32
2496 * f.seek(-40, :END) # => 0
2497 * f.tell # => 12
2498 * f.close
2499 *
2500 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2501 * Repositions the stream to the given +offset+:
2502 *
2503 * f = File.open('t.txt')
2504 * f.tell # => 0
2505 * f.seek(20, :SET) # => 0
2506 * f.tell # => 20
2507 * f.seek(40, :SET) # => 0
2508 * f.tell # => 40
2509 * f.close
2510 *
2511 * Related: IO#pos=, IO#tell.
2512 *
2513 */
2514
2515static VALUE
2516rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2517{
2518 VALUE offset, ptrname;
2519 int whence = SEEK_SET;
2520
2521 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2522 whence = interpret_seek_whence(ptrname);
2523 }
2524
2525 return rb_io_seek(io, offset, whence);
2526}
2527
2528/*
2529 * call-seq:
2530 * pos = new_position -> new_position
2531 *
2532 * Seeks to the given +new_position+ (in bytes);
2533 * see {Position}[rdoc-ref:IO@Position]:
2534 *
2535 * f = File.open('t.txt')
2536 * f.tell # => 0
2537 * f.pos = 20 # => 20
2538 * f.tell # => 20
2539 * f.close
2540 *
2541 * Related: IO#seek, IO#tell.
2542 *
2543 */
2544
2545static VALUE
2546rb_io_set_pos(VALUE io, VALUE offset)
2547{
2548 rb_io_t *fptr;
2549 rb_off_t pos;
2550
2551 pos = NUM2OFFT(offset);
2552 GetOpenFile(io, fptr);
2553 pos = io_seek(fptr, pos, SEEK_SET);
2554 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2555
2556 return OFFT2NUM(pos);
2557}
2558
2559static void clear_readconv(rb_io_t *fptr);
2560
2561/*
2562 * call-seq:
2563 * rewind -> 0
2564 *
2565 * Repositions the stream to its beginning,
2566 * setting both the position and the line number to zero;
2567 * see {Position}[rdoc-ref:IO@Position]
2568 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2569 *
2570 * f = File.open('t.txt')
2571 * f.tell # => 0
2572 * f.lineno # => 0
2573 * f.gets # => "First line\n"
2574 * f.tell # => 12
2575 * f.lineno # => 1
2576 * f.rewind # => 0
2577 * f.tell # => 0
2578 * f.lineno # => 0
2579 * f.close
2580 *
2581 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2582 *
2583 */
2584
2585static VALUE
2586rb_io_rewind(VALUE io)
2587{
2588 rb_io_t *fptr;
2589
2590 GetOpenFile(io, fptr);
2591 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2592 if (io == ARGF.current_file) {
2593 ARGF.lineno -= fptr->lineno;
2594 }
2595 fptr->lineno = 0;
2596 if (fptr->readconv) {
2597 clear_readconv(fptr);
2598 }
2599
2600 return INT2FIX(0);
2601}
2602
2603static int
2604fptr_wait_readable(rb_io_t *fptr)
2605{
2606 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2607
2608 if (result)
2609 rb_io_check_closed(fptr);
2610
2611 return result;
2612}
2613
2614static int
2615io_fillbuf(rb_io_t *fptr)
2616{
2617 ssize_t r;
2618
2619 if (fptr->rbuf.ptr == NULL) {
2620 fptr->rbuf.off = 0;
2621 fptr->rbuf.len = 0;
2622 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2623 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2624#ifdef _WIN32
2625 fptr->rbuf.capa--;
2626#endif
2627 }
2628 if (fptr->rbuf.len == 0) {
2629 retry:
2630 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2631
2632 if (r < 0) {
2633 if (fptr_wait_readable(fptr))
2634 goto retry;
2635
2636 int e = errno;
2637 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2638 if (!NIL_P(fptr->pathv)) {
2639 rb_str_append(path, fptr->pathv);
2640 }
2641
2642 rb_syserr_fail_path(e, path);
2643 }
2644 if (r > 0) rb_io_check_closed(fptr);
2645 fptr->rbuf.off = 0;
2646 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2647 if (r == 0)
2648 return -1; /* EOF */
2649 }
2650 return 0;
2651}
2652
2653/*
2654 * call-seq:
2655 * eof -> true or false
2656 *
2657 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2658 * see {Position}[rdoc-ref:IO@Position]:
2659 *
2660 * f = File.open('t.txt')
2661 * f.eof # => false
2662 * f.seek(0, :END) # => 0
2663 * f.eof # => true
2664 * f.close
2665 *
2666 * Raises an exception unless the stream is opened for reading;
2667 * see {Mode}[rdoc-ref:File@Access+Modes].
2668 *
2669 * If +self+ is a stream such as pipe or socket, this method
2670 * blocks until the other end sends some data or closes it:
2671 *
2672 * r, w = IO.pipe
2673 * Thread.new { sleep 1; w.close }
2674 * r.eof? # => true # After 1-second wait.
2675 *
2676 * r, w = IO.pipe
2677 * Thread.new { sleep 1; w.puts "a" }
2678 * r.eof? # => false # After 1-second wait.
2679 *
2680 * r, w = IO.pipe
2681 * r.eof? # blocks forever
2682 *
2683 * Note that this method reads data to the input byte buffer. So
2684 * IO#sysread may not behave as you intend with IO#eof?, unless you
2685 * call IO#rewind first (which is not available for some streams).
2686 */
2687
2688 VALUE
2689rb_io_eof(VALUE io)
2690{
2691 rb_io_t *fptr;
2692
2693 GetOpenFile(io, fptr);
2694 rb_io_check_char_readable(fptr);
2695
2696 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2697 if (READ_DATA_PENDING(fptr)) return Qfalse;
2698 READ_CHECK(fptr);
2699#if RUBY_CRLF_ENVIRONMENT
2700 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2701 return RBOOL(eof(fptr->fd));
2702 }
2703#endif
2704 return RBOOL(io_fillbuf(fptr) < 0);
2705}
2706
2707/*
2708 * call-seq:
2709 * sync -> true or false
2710 *
2711 * Returns the current sync mode of the stream.
2712 * When sync mode is true, all output is immediately flushed to the underlying
2713 * operating system and is not buffered by Ruby internally. See also #fsync.
2714 *
2715 * f = File.open('t.tmp', 'w')
2716 * f.sync # => false
2717 * f.sync = true
2718 * f.sync # => true
2719 * f.close
2720 *
2721 */
2722
2723static VALUE
2724rb_io_sync(VALUE io)
2725{
2726 rb_io_t *fptr;
2727
2728 io = GetWriteIO(io);
2729 GetOpenFile(io, fptr);
2730 return RBOOL(fptr->mode & FMODE_SYNC);
2731}
2732
2733#ifdef HAVE_FSYNC
2734
2735/*
2736 * call-seq:
2737 * sync = boolean -> boolean
2738 *
2739 * Sets the _sync_ _mode_ for the stream to the given value;
2740 * returns the given value.
2741 *
2742 * Values for the sync mode:
2743 *
2744 * - +true+: All output is immediately flushed to the
2745 * underlying operating system and is not buffered internally.
2746 * - +false+: Output may be buffered internally.
2747 *
2748 * Example;
2749 *
2750 * f = File.open('t.tmp', 'w')
2751 * f.sync # => false
2752 * f.sync = true
2753 * f.sync # => true
2754 * f.close
2755 *
2756 * Related: IO#fsync.
2757 *
2758 */
2759
2760static VALUE
2761rb_io_set_sync(VALUE io, VALUE sync)
2762{
2763 rb_io_t *fptr;
2764
2765 io = GetWriteIO(io);
2766 GetOpenFile(io, fptr);
2767 if (RTEST(sync)) {
2768 fptr->mode |= FMODE_SYNC;
2769 }
2770 else {
2771 fptr->mode &= ~FMODE_SYNC;
2772 }
2773 return sync;
2774}
2775
2776/*
2777 * call-seq:
2778 * fsync -> 0
2779 *
2780 * Immediately writes to disk all data buffered in the stream,
2781 * via the operating system's <tt>fsync(2)</tt>.
2782
2783 * Note this difference:
2784 *
2785 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2786 * but does not guarantee that the operating system actually writes the data to disk.
2787 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2788 * and that data is written to disk.
2789 *
2790 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2791 *
2792 */
2793
2794static VALUE
2795rb_io_fsync(VALUE io)
2796{
2797 rb_io_t *fptr;
2798
2799 io = GetWriteIO(io);
2800 GetOpenFile(io, fptr);
2801
2802 if (io_fflush(fptr) < 0)
2803 rb_sys_fail_on_write(fptr);
2804
2805 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2806 rb_sys_fail_path(fptr->pathv);
2807
2808 return INT2FIX(0);
2809}
2810#else
2811# define rb_io_fsync rb_f_notimplement
2812# define rb_io_sync rb_f_notimplement
2813static VALUE
2814rb_io_set_sync(VALUE io, VALUE sync)
2815{
2816 rb_notimplement();
2817 UNREACHABLE;
2818}
2819#endif
2820
2821#ifdef HAVE_FDATASYNC
2822static VALUE
2823nogvl_fdatasync(void *ptr)
2824{
2825 rb_io_t *fptr = ptr;
2826
2827#ifdef _WIN32
2828 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2829 return 0;
2830#endif
2831 return (VALUE)fdatasync(fptr->fd);
2832}
2833
2834/*
2835 * call-seq:
2836 * fdatasync -> 0
2837 *
2838 * Immediately writes to disk all data buffered in the stream,
2839 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2840 * otherwise via <tt>fsync(2)</tt>, if supported;
2841 * otherwise raises an exception.
2842 *
2843 */
2844
2845static VALUE
2846rb_io_fdatasync(VALUE io)
2847{
2848 rb_io_t *fptr;
2849
2850 io = GetWriteIO(io);
2851 GetOpenFile(io, fptr);
2852
2853 if (io_fflush(fptr) < 0)
2854 rb_sys_fail_on_write(fptr);
2855
2856 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2857 return INT2FIX(0);
2858
2859 /* fall back */
2860 return rb_io_fsync(io);
2861}
2862#else
2863#define rb_io_fdatasync rb_io_fsync
2864#endif
2865
2866/*
2867 * call-seq:
2868 * fileno -> integer
2869 *
2870 * Returns the integer file descriptor for the stream:
2871 *
2872 * $stdin.fileno # => 0
2873 * $stdout.fileno # => 1
2874 * $stderr.fileno # => 2
2875 * File.open('t.txt').fileno # => 10
2876 * f.close
2877 *
2878 */
2879
2880static VALUE
2881rb_io_fileno(VALUE io)
2882{
2883 rb_io_t *fptr = RFILE(io)->fptr;
2884 int fd;
2885
2886 rb_io_check_closed(fptr);
2887 fd = fptr->fd;
2888 return INT2FIX(fd);
2889}
2890
2891int
2892rb_io_descriptor(VALUE io)
2893{
2894 if (RB_TYPE_P(io, T_FILE)) {
2895 rb_io_t *fptr = RFILE(io)->fptr;
2896 rb_io_check_closed(fptr);
2897 return fptr->fd;
2898 }
2899 else {
2900 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2901 if (!UNDEF_P(fileno)) {
2902 return RB_NUM2INT(fileno);
2903 }
2904 }
2905
2906 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2907
2908 UNREACHABLE_RETURN(-1);
2909}
2910
2911int
2912rb_io_mode(VALUE io)
2913{
2914 rb_io_t *fptr;
2915 GetOpenFile(io, fptr);
2916 return fptr->mode;
2917}
2918
2919/*
2920 * call-seq:
2921 * pid -> integer or nil
2922 *
2923 * Returns the process ID of a child process associated with the stream,
2924 * which will have been set by IO#popen, or +nil+ if the stream was not
2925 * created by IO#popen:
2926 *
2927 * pipe = IO.popen("-")
2928 * if pipe
2929 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2930 * else
2931 * $stderr.puts "In child, pid is #{$$}"
2932 * end
2933 *
2934 * Output:
2935 *
2936 * In child, pid is 26209
2937 * In parent, child pid is 26209
2938 *
2939 */
2940
2941static VALUE
2942rb_io_pid(VALUE io)
2943{
2944 rb_io_t *fptr;
2945
2946 GetOpenFile(io, fptr);
2947 if (!fptr->pid)
2948 return Qnil;
2949 return PIDT2NUM(fptr->pid);
2950}
2951
2952/*
2953 * call-seq:
2954 * path -> string or nil
2955 *
2956 * Returns the path associated with the IO, or +nil+ if there is no path
2957 * associated with the IO. It is not guaranteed that the path exists on
2958 * the filesystem.
2959 *
2960 * $stdin.path # => "<STDIN>"
2961 *
2962 * File.open("testfile") {|f| f.path} # => "testfile"
2963 */
2964
2965 VALUE
2966rb_io_path(VALUE io)
2967{
2968 rb_io_t *fptr = RFILE(io)->fptr;
2969
2970 if (!fptr)
2971 return Qnil;
2972
2973 return rb_obj_dup(fptr->pathv);
2974}
2975
2976/*
2977 * call-seq:
2978 * inspect -> string
2979 *
2980 * Returns a string representation of +self+:
2981 *
2982 * f = File.open('t.txt')
2983 * f.inspect # => "#<File:t.txt>"
2984 * f.close
2985 *
2986 */
2987
2988static VALUE
2989rb_io_inspect(VALUE obj)
2990{
2991 rb_io_t *fptr;
2992 VALUE result;
2993 static const char closed[] = " (closed)";
2994
2995 fptr = RFILE(obj)->fptr;
2996 if (!fptr) return rb_any_to_s(obj);
2997 result = rb_str_new_cstr("#<");
2998 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2999 rb_str_cat2(result, ":");
3000 if (NIL_P(fptr->pathv)) {
3001 if (fptr->fd < 0) {
3002 rb_str_cat(result, closed+1, strlen(closed)-1);
3003 }
3004 else {
3005 rb_str_catf(result, "fd %d", fptr->fd);
3006 }
3007 }
3008 else {
3009 rb_str_append(result, fptr->pathv);
3010 if (fptr->fd < 0) {
3011 rb_str_cat(result, closed, strlen(closed));
3012 }
3013 }
3014 return rb_str_cat2(result, ">");
3015}
3016
3017/*
3018 * call-seq:
3019 * to_io -> self
3020 *
3021 * Returns +self+.
3022 *
3023 */
3024
3025static VALUE
3026rb_io_to_io(VALUE io)
3027{
3028 return io;
3029}
3030
3031/* reading functions */
3032static long
3033read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3034{
3035 int n;
3036
3037 n = READ_DATA_PENDING_COUNT(fptr);
3038 if (n <= 0) return 0;
3039 if (n > len) n = (int)len;
3040 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3041 fptr->rbuf.off += n;
3042 fptr->rbuf.len -= n;
3043 return n;
3044}
3045
3046static long
3047io_bufread(char *ptr, long len, rb_io_t *fptr)
3048{
3049 long offset = 0;
3050 long n = len;
3051 long c;
3052
3053 if (READ_DATA_PENDING(fptr) == 0) {
3054 while (n > 0) {
3055 again:
3056 rb_io_check_closed(fptr);
3057 c = rb_io_read_memory(fptr, ptr+offset, n);
3058 if (c == 0) break;
3059 if (c < 0) {
3060 if (fptr_wait_readable(fptr))
3061 goto again;
3062 return -1;
3063 }
3064 offset += c;
3065 if ((n -= c) <= 0) break;
3066 }
3067 return len - n;
3068 }
3069
3070 while (n > 0) {
3071 c = read_buffered_data(ptr+offset, n, fptr);
3072 if (c > 0) {
3073 offset += c;
3074 if ((n -= c) <= 0) break;
3075 }
3076 rb_io_check_closed(fptr);
3077 if (io_fillbuf(fptr) < 0) {
3078 break;
3079 }
3080 }
3081 return len - n;
3082}
3083
3084static int io_setstrbuf(VALUE *str, long len);
3085
3086 struct bufread_arg {
3087 char *str_ptr;
3088 long len;
3089 rb_io_t *fptr;
3090};
3091
3092static VALUE
3093bufread_call(VALUE arg)
3094{
3095 struct bufread_arg *p = (struct bufread_arg *)arg;
3096 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3097 return Qundef;
3098}
3099
3100static long
3101io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3102{
3103 long len;
3104 struct bufread_arg arg;
3105
3106 io_setstrbuf(&str, offset + size);
3107 arg.str_ptr = RSTRING_PTR(str) + offset;
3108 arg.len = size;
3109 arg.fptr = fptr;
3110 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3111 len = arg.len;
3112 if (len < 0) rb_sys_fail_path(fptr->pathv);
3113 return len;
3114}
3115
3116static long
3117remain_size(rb_io_t *fptr)
3118{
3119 struct stat st;
3120 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3121 rb_off_t pos;
3122
3123 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3124#if defined(__HAIKU__)
3125 && (st.st_dev > 3)
3126#endif
3127 )
3128 {
3129 if (io_fflush(fptr) < 0)
3130 rb_sys_fail_on_write(fptr);
3131 pos = lseek(fptr->fd, 0, SEEK_CUR);
3132 if (st.st_size >= pos && pos >= 0) {
3133 siz += st.st_size - pos;
3134 if (siz > LONG_MAX) {
3135 rb_raise(rb_eIOError, "file too big for single read");
3136 }
3137 }
3138 }
3139 else {
3140 siz += BUFSIZ;
3141 }
3142 return (long)siz;
3143}
3144
3145static VALUE
3146io_enc_str(VALUE str, rb_io_t *fptr)
3147{
3148 rb_enc_associate(str, io_read_encoding(fptr));
3149 return str;
3150}
3151
3152static rb_encoding *io_read_encoding(rb_io_t *fptr);
3153
3154static void
3155make_readconv(rb_io_t *fptr, int size)
3156{
3157 if (!fptr->readconv) {
3158 int ecflags;
3159 VALUE ecopts;
3160 const char *sname, *dname;
3161 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3162 ecopts = fptr->encs.ecopts;
3163 if (fptr->encs.enc2) {
3164 sname = rb_enc_name(fptr->encs.enc2);
3165 dname = rb_enc_name(io_read_encoding(fptr));
3166 }
3167 else {
3168 sname = dname = "";
3169 }
3170 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3171 if (!fptr->readconv)
3172 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3173 fptr->cbuf.off = 0;
3174 fptr->cbuf.len = 0;
3175 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3176 fptr->cbuf.capa = size;
3177 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3178 }
3179}
3180
3181#define MORE_CHAR_SUSPENDED Qtrue
3182#define MORE_CHAR_FINISHED Qnil
3183static VALUE
3184fill_cbuf(rb_io_t *fptr, int ec_flags)
3185{
3186 const unsigned char *ss, *sp, *se;
3187 unsigned char *ds, *dp, *de;
3188 rb_econv_result_t res;
3189 int putbackable;
3190 int cbuf_len0;
3191 VALUE exc;
3192
3193 ec_flags |= ECONV_PARTIAL_INPUT;
3194
3195 if (fptr->cbuf.len == fptr->cbuf.capa)
3196 return MORE_CHAR_SUSPENDED; /* cbuf full */
3197 if (fptr->cbuf.len == 0)
3198 fptr->cbuf.off = 0;
3199 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3200 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3201 fptr->cbuf.off = 0;
3202 }
3203
3204 cbuf_len0 = fptr->cbuf.len;
3205
3206 while (1) {
3207 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3208 se = sp + fptr->rbuf.len;
3209 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3210 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3211 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3212 fptr->rbuf.off += (int)(sp - ss);
3213 fptr->rbuf.len -= (int)(sp - ss);
3214 fptr->cbuf.len += (int)(dp - ds);
3215
3216 putbackable = rb_econv_putbackable(fptr->readconv);
3217 if (putbackable) {
3218 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3219 fptr->rbuf.off -= putbackable;
3220 fptr->rbuf.len += putbackable;
3221 }
3222
3223 exc = rb_econv_make_exception(fptr->readconv);
3224 if (!NIL_P(exc))
3225 return exc;
3226
3227 if (cbuf_len0 != fptr->cbuf.len)
3228 return MORE_CHAR_SUSPENDED;
3229
3230 if (res == econv_finished) {
3231 return MORE_CHAR_FINISHED;
3232 }
3233
3234 if (res == econv_source_buffer_empty) {
3235 if (fptr->rbuf.len == 0) {
3236 READ_CHECK(fptr);
3237 if (io_fillbuf(fptr) < 0) {
3238 if (!fptr->readconv) {
3239 return MORE_CHAR_FINISHED;
3240 }
3241 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3242 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3243 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3244 fptr->cbuf.len += (int)(dp - ds);
3245 rb_econv_check_error(fptr->readconv);
3246 break;
3247 }
3248 }
3249 }
3250 }
3251 if (cbuf_len0 != fptr->cbuf.len)
3252 return MORE_CHAR_SUSPENDED;
3253
3254 return MORE_CHAR_FINISHED;
3255}
3256
3257static VALUE
3258more_char(rb_io_t *fptr)
3259{
3260 VALUE v;
3261 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3262 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3263 rb_exc_raise(v);
3264 return v;
3265}
3266
3267static VALUE
3268io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3269{
3270 VALUE str = Qnil;
3271 if (strp) {
3272 str = *strp;
3273 if (NIL_P(str)) {
3274 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3275 }
3276 else {
3277 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3278 }
3279 rb_enc_associate(str, fptr->encs.enc);
3280 }
3281 fptr->cbuf.off += len;
3282 fptr->cbuf.len -= len;
3283 /* xxx: set coderange */
3284 if (fptr->cbuf.len == 0)
3285 fptr->cbuf.off = 0;
3286 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3287 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3288 fptr->cbuf.off = 0;
3289 }
3290 return str;
3291}
3292
3293static int
3294io_setstrbuf(VALUE *str, long len)
3295{
3296#ifdef _WIN32
3297 if (len > 0)
3298 len = (len + 1) & ~1L; /* round up for wide char */
3299#endif
3300 if (NIL_P(*str)) {
3301 *str = rb_str_new(0, len);
3302 return TRUE;
3303 }
3304 else {
3305 VALUE s = StringValue(*str);
3306 rb_str_modify(s);
3307
3308 long clen = RSTRING_LEN(s);
3309 if (clen >= len) {
3310 return FALSE;
3311 }
3312 len -= clen;
3313 }
3314 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3315 rb_str_modify_expand(*str, len);
3316 }
3317 return FALSE;
3318}
3319
3320#define MAX_REALLOC_GAP 4096
3321static void
3322io_shrink_read_string(VALUE str, long n)
3323{
3324 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3325 rb_str_resize(str, n);
3326 }
3327}
3328
3329static void
3330io_set_read_length(VALUE str, long n, int shrinkable)
3331{
3332 if (RSTRING_LEN(str) != n) {
3333 rb_str_modify(str);
3334 rb_str_set_len(str, n);
3335 if (shrinkable) io_shrink_read_string(str, n);
3336 }
3337}
3338
3339static VALUE
3340read_all(rb_io_t *fptr, long siz, VALUE str)
3341{
3342 long bytes;
3343 long n;
3344 long pos;
3345 rb_encoding *enc;
3346 int cr;
3347 int shrinkable;
3348
3349 if (NEED_READCONV(fptr)) {
3350 int first = !NIL_P(str);
3351 SET_BINARY_MODE(fptr);
3352 shrinkable = io_setstrbuf(&str,0);
3353 make_readconv(fptr, 0);
3354 while (1) {
3355 VALUE v;
3356 if (fptr->cbuf.len) {
3357 if (first) rb_str_set_len(str, first = 0);
3358 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3359 }
3360 v = fill_cbuf(fptr, 0);
3361 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3362 if (fptr->cbuf.len) {
3363 if (first) rb_str_set_len(str, first = 0);
3364 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3365 }
3366 rb_exc_raise(v);
3367 }
3368 if (v == MORE_CHAR_FINISHED) {
3369 clear_readconv(fptr);
3370 if (first) rb_str_set_len(str, first = 0);
3371 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3372 return io_enc_str(str, fptr);
3373 }
3374 }
3375 }
3376
3377 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3378 bytes = 0;
3379 pos = 0;
3380
3381 enc = io_read_encoding(fptr);
3382 cr = 0;
3383
3384 if (siz == 0) siz = BUFSIZ;
3385 shrinkable = io_setstrbuf(&str, siz);
3386 for (;;) {
3387 READ_CHECK(fptr);
3388 n = io_fread(str, bytes, siz - bytes, fptr);
3389 if (n == 0 && bytes == 0) {
3390 rb_str_set_len(str, 0);
3391 break;
3392 }
3393 bytes += n;
3394 rb_str_set_len(str, bytes);
3395 if (cr != ENC_CODERANGE_BROKEN)
3396 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3397 if (bytes < siz) break;
3398 siz += BUFSIZ;
3399
3400 size_t capa = rb_str_capacity(str);
3401 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3402 if (capa < BUFSIZ) {
3403 capa = BUFSIZ;
3404 }
3405 else if (capa > IO_MAX_BUFFER_GROWTH) {
3406 capa = IO_MAX_BUFFER_GROWTH;
3407 }
3408 rb_str_modify_expand(str, capa);
3409 }
3410 }
3411 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3412 str = io_enc_str(str, fptr);
3413 ENC_CODERANGE_SET(str, cr);
3414 return str;
3415}
3416
3417void
3418rb_io_set_nonblock(rb_io_t *fptr)
3419{
3420 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3421 rb_sys_fail_path(fptr->pathv);
3422 }
3423}
3424
3425static VALUE
3426io_read_memory_call(VALUE arg)
3427{
3428 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3429
3430 VALUE scheduler = rb_fiber_scheduler_current();
3431 if (scheduler != Qnil) {
3432 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3433
3434 if (!UNDEF_P(result)) {
3435 // This is actually returned as a pseudo-VALUE and later cast to a long:
3436 return (VALUE)rb_fiber_scheduler_io_result_apply(result);
3437 }
3438 }
3439
3440 if (iis->nonblock) {
3441 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3442 }
3443 else {
3444 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3445 }
3446}
3447
3448static long
3449io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3450{
3451 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3452}
3453
3454#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3455
3456static VALUE
3457io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3458{
3459 rb_io_t *fptr;
3460 VALUE length, str;
3461 long n, len;
3462 struct io_internal_read_struct iis;
3463 int shrinkable;
3464
3465 rb_scan_args(argc, argv, "11", &length, &str);
3466
3467 if ((len = NUM2LONG(length)) < 0) {
3468 rb_raise(rb_eArgError, "negative length %ld given", len);
3469 }
3470
3471 shrinkable = io_setstrbuf(&str, len);
3472
3473 GetOpenFile(io, fptr);
3474 rb_io_check_byte_readable(fptr);
3475
3476 if (len == 0) {
3477 io_set_read_length(str, 0, shrinkable);
3478 return str;
3479 }
3480
3481 if (!nonblock)
3482 READ_CHECK(fptr);
3483 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3484 if (n <= 0) {
3485 again:
3486 if (nonblock) {
3487 rb_io_set_nonblock(fptr);
3488 }
3489 io_setstrbuf(&str, len);
3490 iis.th = rb_thread_current();
3491 iis.fptr = fptr;
3492 iis.nonblock = nonblock;
3493 iis.fd = fptr->fd;
3494 iis.buf = RSTRING_PTR(str);
3495 iis.capa = len;
3496 iis.timeout = NULL;
3497 n = io_read_memory_locktmp(str, &iis);
3498 if (n < 0) {
3499 int e = errno;
3500 if (!nonblock && fptr_wait_readable(fptr))
3501 goto again;
3502 if (nonblock && (io_again_p(e))) {
3503 if (no_exception)
3504 return sym_wait_readable;
3505 else
3506 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3507 e, "read would block");
3508 }
3509 rb_syserr_fail_path(e, fptr->pathv);
3510 }
3511 }
3512 io_set_read_length(str, n, shrinkable);
3513
3514 if (n == 0)
3515 return Qnil;
3516 else
3517 return str;
3518}
3519
3520/*
3521 * call-seq:
3522 * readpartial(maxlen) -> string
3523 * readpartial(maxlen, out_string) -> out_string
3524 *
3525 * Reads up to +maxlen+ bytes from the stream;
3526 * returns a string (either a new string or the given +out_string+).
3527 * Its encoding is:
3528 *
3529 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3530 * - ASCII-8BIT, otherwise.
3531 *
3532 * - Contains +maxlen+ bytes from the stream, if available.
3533 * - Otherwise contains all available bytes, if any available.
3534 * - Otherwise is an empty string.
3535 *
3536 * With the single non-negative integer argument +maxlen+ given,
3537 * returns a new string:
3538 *
3539 * f = File.new('t.txt')
3540 * f.readpartial(20) # => "First line\nSecond l"
3541 * f.readpartial(20) # => "ine\n\nFourth line\n"
3542 * f.readpartial(20) # => "Fifth line\n"
3543 * f.readpartial(20) # Raises EOFError.
3544 * f.close
3545 *
3546 * With both argument +maxlen+ and string argument +out_string+ given,
3547 * returns modified +out_string+:
3548 *
3549 * f = File.new('t.txt')
3550 * s = 'foo'
3551 * f.readpartial(20, s) # => "First line\nSecond l"
3552 * s = 'bar'
3553 * f.readpartial(0, s) # => ""
3554 * f.close
3555 *
3556 * This method is useful for a stream such as a pipe, a socket, or a tty.
3557 * It blocks only when no data is immediately available.
3558 * This means that it blocks only when _all_ of the following are true:
3559 *
3560 * - The byte buffer in the stream is empty.
3561 * - The content of the stream is empty.
3562 * - The stream is not at EOF.
3563 *
3564 * When blocked, the method waits for either more data or EOF on the stream:
3565 *
3566 * - If more data is read, the method returns the data.
3567 * - If EOF is reached, the method raises EOFError.
3568 *
3569 * When not blocked, the method responds immediately:
3570 *
3571 * - Returns data from the buffer if there is any.
3572 * - Otherwise returns data from the stream if there is any.
3573 * - Otherwise raises EOFError if the stream has reached EOF.
3574 *
3575 * Note that this method is similar to sysread. The differences are:
3576 *
3577 * - If the byte buffer is not empty, read from the byte buffer
3578 * instead of "sysread for buffered IO (IOError)".
3579 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3580 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3581 * readpartial retries the system call.
3582 *
3583 * The latter means that readpartial is non-blocking-flag insensitive.
3584 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3585 * if the fd is blocking mode.
3586 *
3587 * Examples:
3588 *
3589 * # # Returned Buffer Content Pipe Content
3590 * r, w = IO.pipe #
3591 * w << 'abc' # "" "abc".
3592 * r.readpartial(4096) # => "abc" "" ""
3593 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3594 *
3595 * # # Returned Buffer Content Pipe Content
3596 * r, w = IO.pipe #
3597 * w << 'abc' # "" "abc"
3598 * w.close # "" "abc" EOF
3599 * r.readpartial(4096) # => "abc" "" EOF
3600 * r.readpartial(4096) # raises EOFError
3601 *
3602 * # # Returned Buffer Content Pipe Content
3603 * r, w = IO.pipe #
3604 * w << "abc\ndef\n" # "" "abc\ndef\n"
3605 * r.gets # => "abc\n" "def\n" ""
3606 * w << "ghi\n" # "def\n" "ghi\n"
3607 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3608 * r.readpartial(4096) # => "ghi\n" "" ""
3609 *
3610 */
3611
3612static VALUE
3613io_readpartial(int argc, VALUE *argv, VALUE io)
3614{
3615 VALUE ret;
3616
3617 ret = io_getpartial(argc, argv, io, Qnil, 0);
3618 if (NIL_P(ret))
3619 rb_eof_error();
3620 return ret;
3621}
3622
3623static VALUE
3624io_nonblock_eof(int no_exception)
3625{
3626 if (!no_exception) {
3627 rb_eof_error();
3628 }
3629 return Qnil;
3630}
3631
3632/* :nodoc: */
3633static VALUE
3634io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3635{
3636 rb_io_t *fptr;
3637 long n, len;
3638 struct io_internal_read_struct iis;
3639 int shrinkable;
3640
3641 if ((len = NUM2LONG(length)) < 0) {
3642 rb_raise(rb_eArgError, "negative length %ld given", len);
3643 }
3644
3645 shrinkable = io_setstrbuf(&str, len);
3646 rb_bool_expected(ex, "exception", TRUE);
3647
3648 GetOpenFile(io, fptr);
3649 rb_io_check_byte_readable(fptr);
3650
3651 if (len == 0) {
3652 io_set_read_length(str, 0, shrinkable);
3653 return str;
3654 }
3655
3656 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3657 if (n <= 0) {
3658 rb_fd_set_nonblock(fptr->fd);
3659 shrinkable |= io_setstrbuf(&str, len);
3660 iis.fptr = fptr;
3661 iis.nonblock = 1;
3662 iis.fd = fptr->fd;
3663 iis.buf = RSTRING_PTR(str);
3664 iis.capa = len;
3665 iis.timeout = NULL;
3666 n = io_read_memory_locktmp(str, &iis);
3667 if (n < 0) {
3668 int e = errno;
3669 if (io_again_p(e)) {
3670 if (!ex) return sym_wait_readable;
3671 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3672 e, "read would block");
3673 }
3674 rb_syserr_fail_path(e, fptr->pathv);
3675 }
3676 }
3677 io_set_read_length(str, n, shrinkable);
3678
3679 if (n == 0) {
3680 if (!ex) return Qnil;
3681 rb_eof_error();
3682 }
3683
3684 return str;
3685}
3686
3687/* :nodoc: */
3688static VALUE
3689io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3690{
3691 rb_io_t *fptr;
3692 long n;
3693
3694 if (!RB_TYPE_P(str, T_STRING))
3695 str = rb_obj_as_string(str);
3696 rb_bool_expected(ex, "exception", TRUE);
3697
3698 io = GetWriteIO(io);
3699 GetOpenFile(io, fptr);
3700 rb_io_check_writable(fptr);
3701
3702 if (io_fflush(fptr) < 0)
3703 rb_sys_fail_on_write(fptr);
3704
3705 rb_fd_set_nonblock(fptr->fd);
3706 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3707 RB_GC_GUARD(str);
3708
3709 if (n < 0) {
3710 int e = errno;
3711 if (io_again_p(e)) {
3712 if (!ex) {
3713 return sym_wait_writable;
3714 }
3715 else {
3716 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3717 }
3718 }
3719 rb_syserr_fail_path(e, fptr->pathv);
3720 }
3721
3722 return LONG2FIX(n);
3723}
3724
3725/*
3726 * call-seq:
3727 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3728 *
3729 * Reads bytes from the stream; the stream must be opened for reading
3730 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3731 *
3732 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3733 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3734 *
3735 * Returns a string (either a new string or the given +out_string+)
3736 * containing the bytes read.
3737 * The encoding of the string depends on both +maxLen+ and +out_string+:
3738 *
3739 * - +maxlen+ is +nil+: uses internal encoding of +self+
3740 * (regardless of whether +out_string+ was given).
3741 * - +maxlen+ not +nil+:
3742 *
3743 * - +out_string+ given: encoding of +out_string+ not modified.
3744 * - +out_string+ not given: ASCII-8BIT is used.
3745 *
3746 * <b>Without Argument +out_string+</b>
3747 *
3748 * When argument +out_string+ is omitted,
3749 * the returned value is a new string:
3750 *
3751 * f = File.new('t.txt')
3752 * f.read
3753 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3754 * f.rewind
3755 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3756 * f.read(30) # => "rth line\r\nFifth line\r\n"
3757 * f.read(30) # => nil
3758 * f.close
3759 *
3760 * If +maxlen+ is zero, returns an empty string.
3761 *
3762 * <b> With Argument +out_string+</b>
3763 *
3764 * When argument +out_string+ is given,
3765 * the returned value is +out_string+, whose content is replaced:
3766 *
3767 * f = File.new('t.txt')
3768 * s = 'foo' # => "foo"
3769 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3770 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3771 * f.rewind
3772 * s = 'bar'
3773 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3774 * s # => "First line\r\nSecond line\r\n\r\nFou"
3775 * s = 'baz'
3776 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3777 * s # => "rth line\r\nFifth line\r\n"
3778 * s = 'bat'
3779 * f.read(30, s) # => nil
3780 * s # => ""
3781 * f.close
3782 *
3783 * Note that this method behaves like the fread() function in C.
3784 * This means it retries to invoke read(2) system calls to read data
3785 * with the specified maxlen (or until EOF).
3786 *
3787 * This behavior is preserved even if the stream is in non-blocking mode.
3788 * (This method is non-blocking-flag insensitive as other methods.)
3789 *
3790 * If you need the behavior like a single read(2) system call,
3791 * consider #readpartial, #read_nonblock, and #sysread.
3792 *
3793 * Related: IO#write.
3794 */
3795
3796static VALUE
3797io_read(int argc, VALUE *argv, VALUE io)
3798{
3799 rb_io_t *fptr;
3800 long n, len;
3801 VALUE length, str;
3802 int shrinkable;
3803#if RUBY_CRLF_ENVIRONMENT
3804 int previous_mode;
3805#endif
3806
3807 rb_scan_args(argc, argv, "02", &length, &str);
3808
3809 if (NIL_P(length)) {
3810 GetOpenFile(io, fptr);
3811 rb_io_check_char_readable(fptr);
3812 return read_all(fptr, remain_size(fptr), str);
3813 }
3814 len = NUM2LONG(length);
3815 if (len < 0) {
3816 rb_raise(rb_eArgError, "negative length %ld given", len);
3817 }
3818
3819 shrinkable = io_setstrbuf(&str,len);
3820
3821 GetOpenFile(io, fptr);
3822 rb_io_check_byte_readable(fptr);
3823 if (len == 0) {
3824 io_set_read_length(str, 0, shrinkable);
3825 return str;
3826 }
3827
3828 READ_CHECK(fptr);
3829#if RUBY_CRLF_ENVIRONMENT
3830 previous_mode = set_binary_mode_with_seek_cur(fptr);
3831#endif
3832 n = io_fread(str, 0, len, fptr);
3833 io_set_read_length(str, n, shrinkable);
3834#if RUBY_CRLF_ENVIRONMENT
3835 if (previous_mode == O_TEXT) {
3836 setmode(fptr->fd, O_TEXT);
3837 }
3838#endif
3839 if (n == 0) return Qnil;
3840
3841 return str;
3842}
3843
3844static void
3845rscheck(const char *rsptr, long rslen, VALUE rs)
3846{
3847 if (!rs) return;
3848 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3849 rb_raise(rb_eRuntimeError, "rs modified");
3850}
3851
3852static const char *
3853search_delim(const char *p, long len, int delim, rb_encoding *enc)
3854{
3855 if (rb_enc_mbminlen(enc) == 1) {
3856 p = memchr(p, delim, len);
3857 if (p) return p + 1;
3858 }
3859 else {
3860 const char *end = p + len;
3861 while (p < end) {
3862 int r = rb_enc_precise_mbclen(p, end, enc);
3863 if (!MBCLEN_CHARFOUND_P(r)) {
3864 p += rb_enc_mbminlen(enc);
3865 continue;
3866 }
3867 int n = MBCLEN_CHARFOUND_LEN(r);
3868 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3869 return p + n;
3870 }
3871 p += n;
3872 }
3873 }
3874 return NULL;
3875}
3876
3877static int
3878appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3879{
3880 VALUE str = *strp;
3881 long limit = *lp;
3882
3883 if (NEED_READCONV(fptr)) {
3884 SET_BINARY_MODE(fptr);
3885 make_readconv(fptr, 0);
3886 do {
3887 const char *p, *e;
3888 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3889 if (searchlen) {
3890 p = READ_CHAR_PENDING_PTR(fptr);
3891 if (0 < limit && limit < searchlen)
3892 searchlen = (int)limit;
3893 e = search_delim(p, searchlen, delim, enc);
3894 if (e) {
3895 int len = (int)(e-p);
3896 if (NIL_P(str))
3897 *strp = str = rb_str_new(p, len);
3898 else
3899 rb_str_buf_cat(str, p, len);
3900 fptr->cbuf.off += len;
3901 fptr->cbuf.len -= len;
3902 limit -= len;
3903 *lp = limit;
3904 return delim;
3905 }
3906
3907 if (NIL_P(str))
3908 *strp = str = rb_str_new(p, searchlen);
3909 else
3910 rb_str_buf_cat(str, p, searchlen);
3911 fptr->cbuf.off += searchlen;
3912 fptr->cbuf.len -= searchlen;
3913 limit -= searchlen;
3914
3915 if (limit == 0) {
3916 *lp = limit;
3917 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3918 }
3919 }
3920 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3921 clear_readconv(fptr);
3922 *lp = limit;
3923 return EOF;
3924 }
3925
3926 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3927 do {
3928 long pending = READ_DATA_PENDING_COUNT(fptr);
3929 if (pending > 0) {
3930 const char *p = READ_DATA_PENDING_PTR(fptr);
3931 const char *e;
3932 long last;
3933
3934 if (limit > 0 && pending > limit) pending = limit;
3935 e = search_delim(p, pending, delim, enc);
3936 if (e) pending = e - p;
3937 if (!NIL_P(str)) {
3938 last = RSTRING_LEN(str);
3939 rb_str_resize(str, last + pending);
3940 }
3941 else {
3942 last = 0;
3943 *strp = str = rb_str_buf_new(pending);
3944 rb_str_set_len(str, pending);
3945 }
3946 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3947 limit -= pending;
3948 *lp = limit;
3949 if (e) return delim;
3950 if (limit == 0)
3951 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3952 }
3953 READ_CHECK(fptr);
3954 } while (io_fillbuf(fptr) >= 0);
3955 *lp = limit;
3956 return EOF;
3957}
3958
3959static inline int
3960swallow(rb_io_t *fptr, int term)
3961{
3962 if (NEED_READCONV(fptr)) {
3963 rb_encoding *enc = io_read_encoding(fptr);
3964 int needconv = rb_enc_mbminlen(enc) != 1;
3965 SET_BINARY_MODE(fptr);
3966 make_readconv(fptr, 0);
3967 do {
3968 size_t cnt;
3969 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3970 const char *p = READ_CHAR_PENDING_PTR(fptr);
3971 int i;
3972 if (!needconv) {
3973 if (*p != term) return TRUE;
3974 i = (int)cnt;
3975 while (--i && *++p == term);
3976 }
3977 else {
3978 const char *e = p + cnt;
3979 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3980 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3981 i = (int)(e - p);
3982 }
3983 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3984 }
3985 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3986 return FALSE;
3987 }
3988
3989 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3990 do {
3991 size_t cnt;
3992 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3993 char buf[1024];
3994 const char *p = READ_DATA_PENDING_PTR(fptr);
3995 int i;
3996 if (cnt > sizeof buf) cnt = sizeof buf;
3997 if (*p != term) return TRUE;
3998 i = (int)cnt;
3999 while (--i && *++p == term);
4000 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4001 rb_sys_fail_path(fptr->pathv);
4002 }
4003 READ_CHECK(fptr);
4004 } while (io_fillbuf(fptr) == 0);
4005 return FALSE;
4006}
4007
4008static VALUE
4009rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4010{
4011 VALUE str = Qnil;
4012 int len = 0;
4013 long pos = 0;
4014 int cr = 0;
4015
4016 do {
4017 int pending = READ_DATA_PENDING_COUNT(fptr);
4018
4019 if (pending > 0) {
4020 const char *p = READ_DATA_PENDING_PTR(fptr);
4021 const char *e;
4022 int chomplen = 0;
4023
4024 e = memchr(p, '\n', pending);
4025 if (e) {
4026 pending = (int)(e - p + 1);
4027 if (chomp) {
4028 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4029 }
4030 }
4031 if (NIL_P(str)) {
4032 str = rb_str_new(p, pending - chomplen);
4033 fptr->rbuf.off += pending;
4034 fptr->rbuf.len -= pending;
4035 }
4036 else {
4037 rb_str_resize(str, len + pending - chomplen);
4038 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4039 fptr->rbuf.off += chomplen;
4040 fptr->rbuf.len -= chomplen;
4041 if (pending == 1 && chomplen == 1 && len > 0) {
4042 if (RSTRING_PTR(str)[len-1] == '\r') {
4043 rb_str_resize(str, --len);
4044 break;
4045 }
4046 }
4047 }
4048 len += pending - chomplen;
4049 if (cr != ENC_CODERANGE_BROKEN)
4050 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4051 if (e) break;
4052 }
4053 READ_CHECK(fptr);
4054 } while (io_fillbuf(fptr) >= 0);
4055 if (NIL_P(str)) return Qnil;
4056
4057 str = io_enc_str(str, fptr);
4058 ENC_CODERANGE_SET(str, cr);
4059 fptr->lineno++;
4060
4061 return str;
4062}
4063
4064 struct getline_arg {
4065 VALUE io;
4066 VALUE rs;
4067 long limit;
4068 unsigned int chomp: 1;
4069};
4070
4071static void
4072extract_getline_opts(VALUE opts, struct getline_arg *args)
4073{
4074 int chomp = FALSE;
4075 if (!NIL_P(opts)) {
4076 static ID kwds[1];
4077 VALUE vchomp;
4078 if (!kwds[0]) {
4079 kwds[0] = rb_intern_const("chomp");
4080 }
4081 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4082 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4083 }
4084 args->chomp = chomp;
4085}
4086
4087static void
4088extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4089{
4090 VALUE rs = rb_rs, lim = Qnil;
4091
4092 if (argc == 1) {
4093 VALUE tmp = Qnil;
4094
4095 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4096 rs = tmp;
4097 }
4098 else {
4099 lim = argv[0];
4100 }
4101 }
4102 else if (2 <= argc) {
4103 rs = argv[0], lim = argv[1];
4104 if (!NIL_P(rs))
4105 StringValue(rs);
4106 }
4107 args->rs = rs;
4108 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4109}
4110
4111static void
4112check_getline_args(VALUE *rsp, long *limit, VALUE io)
4113{
4114 rb_io_t *fptr;
4115 VALUE rs = *rsp;
4116
4117 if (!NIL_P(rs)) {
4118 rb_encoding *enc_rs, *enc_io;
4119
4120 GetOpenFile(io, fptr);
4121 enc_rs = rb_enc_get(rs);
4122 enc_io = io_read_encoding(fptr);
4123 if (enc_io != enc_rs &&
4124 (!is_ascii_string(rs) ||
4125 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4126 if (rs == rb_default_rs) {
4127 rs = rb_enc_str_new(0, 0, enc_io);
4128 rb_str_buf_cat_ascii(rs, "\n");
4129 *rsp = rs;
4130 }
4131 else {
4132 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4133 rb_enc_name(enc_io),
4134 rb_enc_name(enc_rs));
4135 }
4136 }
4137 }
4138}
4139
4140static void
4141prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4142{
4143 VALUE opts;
4144 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4145 extract_getline_args(argc, argv, args);
4146 extract_getline_opts(opts, args);
4147 check_getline_args(&args->rs, &args->limit, io);
4148}
4149
4150static VALUE
4151rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4152{
4153 VALUE str = Qnil;
4154 int nolimit = 0;
4155 rb_encoding *enc;
4156
4157 rb_io_check_char_readable(fptr);
4158 if (NIL_P(rs) && limit < 0) {
4159 str = read_all(fptr, 0, Qnil);
4160 if (RSTRING_LEN(str) == 0) return Qnil;
4161 }
4162 else if (limit == 0) {
4163 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4164 }
4165 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4166 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4167 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4168 return rb_io_getline_fast(fptr, enc, chomp);
4169 }
4170 else {
4171 int c, newline = -1;
4172 const char *rsptr = 0;
4173 long rslen = 0;
4174 int rspara = 0;
4175 int extra_limit = 16;
4176 int chomp_cr = chomp;
4177
4178 SET_BINARY_MODE(fptr);
4179 enc = io_read_encoding(fptr);
4180
4181 if (!NIL_P(rs)) {
4182 rslen = RSTRING_LEN(rs);
4183 if (rslen == 0) {
4184 rsptr = "\n\n";
4185 rslen = 2;
4186 rspara = 1;
4187 swallow(fptr, '\n');
4188 rs = 0;
4189 if (!rb_enc_asciicompat(enc)) {
4190 rs = rb_usascii_str_new(rsptr, rslen);
4191 rs = rb_str_conv_enc(rs, 0, enc);
4192 OBJ_FREEZE(rs);
4193 rsptr = RSTRING_PTR(rs);
4194 rslen = RSTRING_LEN(rs);
4195 }
4196 newline = '\n';
4197 }
4198 else if (rb_enc_mbminlen(enc) == 1) {
4199 rsptr = RSTRING_PTR(rs);
4200 newline = (unsigned char)rsptr[rslen - 1];
4201 }
4202 else {
4203 rs = rb_str_conv_enc(rs, 0, enc);
4204 rsptr = RSTRING_PTR(rs);
4205 const char *e = rsptr + rslen;
4206 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4207 int n;
4208 newline = rb_enc_codepoint_len(last, e, &n, enc);
4209 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4210 }
4211 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4212 }
4213
4214 /* MS - Optimization */
4215 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4216 const char *s, *p, *pp, *e;
4217
4218 if (c == newline) {
4219 if (RSTRING_LEN(str) < rslen) continue;
4220 s = RSTRING_PTR(str);
4221 e = RSTRING_END(str);
4222 p = e - rslen;
4223 if (!at_char_boundary(s, p, e, enc)) continue;
4224 if (!rspara) rscheck(rsptr, rslen, rs);
4225 if (memcmp(p, rsptr, rslen) == 0) {
4226 if (chomp) {
4227 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4228 rb_str_set_len(str, p - s);
4229 }
4230 break;
4231 }
4232 }
4233 if (limit == 0) {
4234 s = RSTRING_PTR(str);
4235 p = RSTRING_END(str);
4236 pp = rb_enc_prev_char(s, p, p, enc);
4237 if (extra_limit && pp &&
4238 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4239 /* relax the limit while incomplete character.
4240 * extra_limit limits the relax length */
4241 limit = 1;
4242 extra_limit--;
4243 }
4244 else {
4245 nolimit = 1;
4246 break;
4247 }
4248 }
4249 }
4250
4251 if (rspara && c != EOF)
4252 swallow(fptr, '\n');
4253 if (!NIL_P(str))
4254 str = io_enc_str(str, fptr);
4255 }
4256
4257 if (!NIL_P(str) && !nolimit) {
4258 fptr->lineno++;
4259 }
4260
4261 return str;
4262}
4263
4264static VALUE
4265rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4266{
4267 rb_io_t *fptr;
4268 int old_lineno, new_lineno;
4269 VALUE str;
4270
4271 GetOpenFile(io, fptr);
4272 old_lineno = fptr->lineno;
4273 str = rb_io_getline_0(rs, limit, chomp, fptr);
4274 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4275 if (io == ARGF.current_file) {
4276 ARGF.lineno += new_lineno - old_lineno;
4277 ARGF.last_lineno = ARGF.lineno;
4278 }
4279 else {
4280 ARGF.last_lineno = new_lineno;
4281 }
4282 }
4283
4284 return str;
4285}
4286
4287static VALUE
4288rb_io_getline(int argc, VALUE *argv, VALUE io)
4289{
4290 struct getline_arg args;
4291
4292 prepare_getline_args(argc, argv, &args, io);
4293 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4294}
4295
4296 VALUE
4297rb_io_gets(VALUE io)
4298{
4299 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4300}
4301
4302 VALUE
4303rb_io_gets_internal(VALUE io)
4304{
4305 rb_io_t *fptr;
4306 GetOpenFile(io, fptr);
4307 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4308}
4309
4310/*
4311 * call-seq:
4312 * gets(sep = $/, chomp: false) -> string or nil
4313 * gets(limit, chomp: false) -> string or nil
4314 * gets(sep, limit, chomp: false) -> string or nil
4315 *
4316 * Reads and returns a line from the stream;
4317 * assigns the return value to <tt>$_</tt>.
4318 * See {Line IO}[rdoc-ref:IO@Line+IO].
4319 *
4320 * With no arguments given, returns the next line
4321 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4322 *
4323 * f = File.open('t.txt')
4324 * f.gets # => "First line\n"
4325 * $_ # => "First line\n"
4326 * f.gets # => "\n"
4327 * f.gets # => "Fourth line\n"
4328 * f.gets # => "Fifth line\n"
4329 * f.gets # => nil
4330 * f.close
4331 *
4332 * With only string argument +sep+ given,
4333 * returns the next line as determined by line separator +sep+,
4334 * or +nil+ if none;
4335 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4336 *
4337 * f = File.new('t.txt')
4338 * f.gets('l') # => "First l"
4339 * f.gets('li') # => "ine\nSecond li"
4340 * f.gets('lin') # => "ne\n\nFourth lin"
4341 * f.gets # => "e\n"
4342 * f.close
4343 *
4344 * The two special values for +sep+ are honored:
4345 *
4346 * f = File.new('t.txt')
4347 * # Get all.
4348 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4349 * f.rewind
4350 * # Get paragraph (up to two line separators).
4351 * f.gets('') # => "First line\nSecond line\n\n"
4352 * f.close
4353 *
4354 * With only integer argument +limit+ given,
4355 * limits the number of bytes in the line;
4356 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4357 *
4358 * # No more than one line.
4359 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4360 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4361 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4362 *
4363 * With arguments +sep+ and +limit+ given,
4364 * combines the two behaviors
4365 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4366 *
4367 * Optional keyword argument +chomp+ specifies whether line separators
4368 * are to be omitted:
4369 *
4370 * f = File.open('t.txt')
4371 * # Chomp the lines.
4372 * f.gets(chomp: true) # => "First line"
4373 * f.gets(chomp: true) # => "Second line"
4374 * f.gets(chomp: true) # => ""
4375 * f.gets(chomp: true) # => "Fourth line"
4376 * f.gets(chomp: true) # => "Fifth line"
4377 * f.gets(chomp: true) # => nil
4378 * f.close
4379 *
4380 */
4381
4382static VALUE
4383rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4384{
4385 VALUE str;
4386
4387 str = rb_io_getline(argc, argv, io);
4388 rb_lastline_set(str);
4389
4390 return str;
4391}
4392
4393/*
4394 * call-seq:
4395 * lineno -> integer
4396 *
4397 * Returns the current line number for the stream;
4398 * see {Line Number}[rdoc-ref:IO@Line+Number].
4399 *
4400 */
4401
4402static VALUE
4403rb_io_lineno(VALUE io)
4404{
4405 rb_io_t *fptr;
4406
4407 GetOpenFile(io, fptr);
4408 rb_io_check_char_readable(fptr);
4409 return INT2NUM(fptr->lineno);
4410}
4411
4412/*
4413 * call-seq:
4414 * lineno = integer -> integer
4415 *
4416 * Sets and returns the line number for the stream;
4417 * see {Line Number}[rdoc-ref:IO@Line+Number].
4418 *
4419 */
4420
4421static VALUE
4422rb_io_set_lineno(VALUE io, VALUE lineno)
4423{
4424 rb_io_t *fptr;
4425
4426 GetOpenFile(io, fptr);
4427 rb_io_check_char_readable(fptr);
4428 fptr->lineno = NUM2INT(lineno);
4429 return lineno;
4430}
4431
4432/* :nodoc: */
4433static VALUE
4434io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4435{
4436 long limit = -1;
4437 if (NIL_P(lim)) {
4438 VALUE tmp = Qnil;
4439 // If sep is specified, but it's not a string and not nil, then assume
4440 // it's the limit (it should be an integer)
4441 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4442 // If the user has specified a non-nil / non-string value
4443 // for the separator, we assume it's the limit and set the
4444 // separator to default: rb_rs.
4445 lim = sep;
4446 limit = NUM2LONG(lim);
4447 sep = rb_rs;
4448 }
4449 else {
4450 sep = tmp;
4451 }
4452 }
4453 else {
4454 if (!NIL_P(sep)) StringValue(sep);
4455 limit = NUM2LONG(lim);
4456 }
4457
4458 check_getline_args(&sep, &limit, io);
4459
4460 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4461 rb_lastline_set_up(line, 1);
4462
4463 if (NIL_P(line)) {
4464 rb_eof_error();
4465 }
4466 return line;
4467}
4468
4469static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4470
4471/*
4472 * call-seq:
4473 * readlines(sep = $/, chomp: false) -> array
4474 * readlines(limit, chomp: false) -> array
4475 * readlines(sep, limit, chomp: false) -> array
4476 *
4477 * Reads and returns all remaining line from the stream;
4478 * does not modify <tt>$_</tt>.
4479 * See {Line IO}[rdoc-ref:IO@Line+IO].
4480 *
4481 * With no arguments given, returns lines
4482 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4483 *
4484 * f = File.new('t.txt')
4485 * f.readlines
4486 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4487 * f.readlines # => []
4488 * f.close
4489 *
4490 * With only string argument +sep+ given,
4491 * returns lines as determined by line separator +sep+,
4492 * or +nil+ if none;
4493 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4494 *
4495 * f = File.new('t.txt')
4496 * f.readlines('li')
4497 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4498 * f.close
4499 *
4500 * The two special values for +sep+ are honored:
4501 *
4502 * f = File.new('t.txt')
4503 * # Get all into one string.
4504 * f.readlines(nil)
4505 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4506 * # Get paragraphs (up to two line separators).
4507 * f.rewind
4508 * f.readlines('')
4509 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4510 * f.close
4511 *
4512 * With only integer argument +limit+ given,
4513 * limits the number of bytes in each line;
4514 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4515 *
4516 * f = File.new('t.txt')
4517 * f.readlines(8)
4518 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4519 * f.close
4520 *
4521 * With arguments +sep+ and +limit+ given,
4522 * combines the two behaviors
4523 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4524 *
4525 * Optional keyword argument +chomp+ specifies whether line separators
4526 * are to be omitted:
4527 *
4528 * f = File.new('t.txt')
4529 * f.readlines(chomp: true)
4530 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4531 * f.close
4532 *
4533 */
4534
4535static VALUE
4536rb_io_readlines(int argc, VALUE *argv, VALUE io)
4537{
4538 struct getline_arg args;
4539
4540 prepare_getline_args(argc, argv, &args, io);
4541 return io_readlines(&args, io);
4542}
4543
4544static VALUE
4545io_readlines(const struct getline_arg *arg, VALUE io)
4546{
4547 VALUE line, ary;
4548
4549 if (arg->limit == 0)
4550 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4551 ary = rb_ary_new();
4552 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4553 rb_ary_push(ary, line);
4554 }
4555 return ary;
4556}
4557
4558/*
4559 * call-seq:
4560 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4561 * each_line(limit, chomp: false) {|line| ... } -> self
4562 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4563 * each_line -> enumerator
4564 *
4565 * Calls the block with each remaining line read from the stream;
4566 * returns +self+.
4567 * Does nothing if already at end-of-stream;
4568 * See {Line IO}[rdoc-ref:IO@Line+IO].
4569 *
4570 * With no arguments given, reads lines
4571 * as determined by line separator <tt>$/</tt>:
4572 *
4573 * f = File.new('t.txt')
4574 * f.each_line {|line| p line }
4575 * f.each_line {|line| fail 'Cannot happen' }
4576 * f.close
4577 *
4578 * Output:
4579 *
4580 * "First line\n"
4581 * "Second line\n"
4582 * "\n"
4583 * "Fourth line\n"
4584 * "Fifth line\n"
4585 *
4586 * With only string argument +sep+ given,
4587 * reads lines as determined by line separator +sep+;
4588 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4589 *
4590 * f = File.new('t.txt')
4591 * f.each_line('li') {|line| p line }
4592 * f.close
4593 *
4594 * Output:
4595 *
4596 * "First li"
4597 * "ne\nSecond li"
4598 * "ne\n\nFourth li"
4599 * "ne\nFifth li"
4600 * "ne\n"
4601 *
4602 * The two special values for +sep+ are honored:
4603 *
4604 * f = File.new('t.txt')
4605 * # Get all into one string.
4606 * f.each_line(nil) {|line| p line }
4607 * f.close
4608 *
4609 * Output:
4610 *
4611 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4612 *
4613 * f.rewind
4614 * # Get paragraphs (up to two line separators).
4615 * f.each_line('') {|line| p line }
4616 *
4617 * Output:
4618 *
4619 * "First line\nSecond line\n\n"
4620 * "Fourth line\nFifth line\n"
4621 *
4622 * With only integer argument +limit+ given,
4623 * limits the number of bytes in each line;
4624 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4625 *
4626 * f = File.new('t.txt')
4627 * f.each_line(8) {|line| p line }
4628 * f.close
4629 *
4630 * Output:
4631 *
4632 * "First li"
4633 * "ne\n"
4634 * "Second l"
4635 * "ine\n"
4636 * "\n"
4637 * "Fourth l"
4638 * "ine\n"
4639 * "Fifth li"
4640 * "ne\n"
4641 *
4642 * With arguments +sep+ and +limit+ given,
4643 * combines the two behaviors
4644 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4645 *
4646 * Optional keyword argument +chomp+ specifies whether line separators
4647 * are to be omitted:
4648 *
4649 * f = File.new('t.txt')
4650 * f.each_line(chomp: true) {|line| p line }
4651 * f.close
4652 *
4653 * Output:
4654 *
4655 * "First line"
4656 * "Second line"
4657 * ""
4658 * "Fourth line"
4659 * "Fifth line"
4660 *
4661 * Returns an Enumerator if no block is given.
4662 */
4663
4664static VALUE
4665rb_io_each_line(int argc, VALUE *argv, VALUE io)
4666{
4667 VALUE str;
4668 struct getline_arg args;
4669
4670 RETURN_ENUMERATOR(io, argc, argv);
4671 prepare_getline_args(argc, argv, &args, io);
4672 if (args.limit == 0)
4673 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4674 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4675 rb_yield(str);
4676 }
4677 return io;
4678}
4679
4680/*
4681 * call-seq:
4682 * each_byte {|byte| ... } -> self
4683 * each_byte -> enumerator
4684 *
4685 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4686 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4687 *
4688 * f = File.new('t.rus')
4689 * a = []
4690 * f.each_byte {|b| a << b }
4691 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4692 * f.close
4693 *
4694 * Returns an Enumerator if no block is given.
4695 *
4696 * Related: IO#each_char, IO#each_codepoint.
4697 *
4698 */
4699
4700static VALUE
4701rb_io_each_byte(VALUE io)
4702{
4703 rb_io_t *fptr;
4704
4705 RETURN_ENUMERATOR(io, 0, 0);
4706 GetOpenFile(io, fptr);
4707
4708 do {
4709 while (fptr->rbuf.len > 0) {
4710 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4711 fptr->rbuf.len--;
4712 rb_yield(INT2FIX(*p & 0xff));
4713 rb_io_check_byte_readable(fptr);
4714 errno = 0;
4715 }
4716 READ_CHECK(fptr);
4717 } while (io_fillbuf(fptr) >= 0);
4718 return io;
4719}
4720
4721static VALUE
4722io_getc(rb_io_t *fptr, rb_encoding *enc)
4723{
4724 int r, n, cr = 0;
4725 VALUE str;
4726
4727 if (NEED_READCONV(fptr)) {
4728 rb_encoding *read_enc = io_read_encoding(fptr);
4729
4730 str = Qnil;
4731 SET_BINARY_MODE(fptr);
4732 make_readconv(fptr, 0);
4733
4734 while (1) {
4735 if (fptr->cbuf.len) {
4736 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4737 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4738 read_enc);
4739 if (!MBCLEN_NEEDMORE_P(r))
4740 break;
4741 if (fptr->cbuf.len == fptr->cbuf.capa) {
4742 rb_raise(rb_eIOError, "too long character");
4743 }
4744 }
4745
4746 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4747 if (fptr->cbuf.len == 0) {
4748 clear_readconv(fptr);
4749 return Qnil;
4750 }
4751 /* return an unit of an incomplete character just before EOF */
4752 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4753 fptr->cbuf.off += 1;
4754 fptr->cbuf.len -= 1;
4755 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4756 ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
4757 return str;
4758 }
4759 }
4760 if (MBCLEN_INVALID_P(r)) {
4761 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4762 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4763 read_enc);
4764 io_shift_cbuf(fptr, r, &str);
4765 cr = ENC_CODERANGE_BROKEN;
4766 }
4767 else {
4768 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4769 cr = ENC_CODERANGE_VALID;
4770 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4771 ISASCII(RSTRING_PTR(str)[0])) {
4772 cr = ENC_CODERANGE_7BIT;
4773 }
4774 }
4775 str = io_enc_str(str, fptr);
4776 ENC_CODERANGE_SET(str, cr);
4777 return str;
4778 }
4779
4780 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4781 if (io_fillbuf(fptr) < 0) {
4782 return Qnil;
4783 }
4784 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4785 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4786 fptr->rbuf.off += 1;
4787 fptr->rbuf.len -= 1;
4788 cr = ENC_CODERANGE_7BIT;
4789 }
4790 else {
4791 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4792 if (MBCLEN_CHARFOUND_P(r) &&
4793 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4794 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4795 fptr->rbuf.off += n;
4796 fptr->rbuf.len -= n;
4797 cr = ENC_CODERANGE_VALID;
4798 }
4799 else if (MBCLEN_NEEDMORE_P(r)) {
4800 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4801 fptr->rbuf.len = 0;
4802 getc_needmore:
4803 if (io_fillbuf(fptr) != -1) {
4804 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4805 fptr->rbuf.off++;
4806 fptr->rbuf.len--;
4807 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4808 if (MBCLEN_NEEDMORE_P(r)) {
4809 goto getc_needmore;
4810 }
4811 else if (MBCLEN_CHARFOUND_P(r)) {
4812 cr = ENC_CODERANGE_VALID;
4813 }
4814 }
4815 }
4816 else {
4817 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4818 fptr->rbuf.off++;
4819 fptr->rbuf.len--;
4820 }
4821 }
4822 if (!cr) cr = ENC_CODERANGE_BROKEN;
4823 str = io_enc_str(str, fptr);
4824 ENC_CODERANGE_SET(str, cr);
4825 return str;
4826}
4827
4828/*
4829 * call-seq:
4830 * each_char {|c| ... } -> self
4831 * each_char -> enumerator
4832 *
4833 * Calls the given block with each character in the stream; returns +self+.
4834 * See {Character IO}[rdoc-ref:IO@Character+IO].
4835 *
4836 * f = File.new('t.rus')
4837 * a = []
4838 * f.each_char {|c| a << c.ord }
4839 * a # => [1090, 1077, 1089, 1090]
4840 * f.close
4841 *
4842 * Returns an Enumerator if no block is given.
4843 *
4844 * Related: IO#each_byte, IO#each_codepoint.
4845 *
4846 */
4847
4848static VALUE
4849rb_io_each_char(VALUE io)
4850{
4851 rb_io_t *fptr;
4852 rb_encoding *enc;
4853 VALUE c;
4854
4855 RETURN_ENUMERATOR(io, 0, 0);
4856 GetOpenFile(io, fptr);
4857 rb_io_check_char_readable(fptr);
4858
4859 enc = io_input_encoding(fptr);
4860 READ_CHECK(fptr);
4861 while (!NIL_P(c = io_getc(fptr, enc))) {
4862 rb_yield(c);
4863 }
4864 return io;
4865}
4866
4867/*
4868 * call-seq:
4869 * each_codepoint {|c| ... } -> self
4870 * each_codepoint -> enumerator
4871 *
4872 * Calls the given block with each codepoint in the stream; returns +self+:
4873 *
4874 * f = File.new('t.rus')
4875 * a = []
4876 * f.each_codepoint {|c| a << c }
4877 * a # => [1090, 1077, 1089, 1090]
4878 * f.close
4879 *
4880 * Returns an Enumerator if no block is given.
4881 *
4882 * Related: IO#each_byte, IO#each_char.
4883 *
4884 */
4885
4886static VALUE
4887rb_io_each_codepoint(VALUE io)
4888{
4889 rb_io_t *fptr;
4890 rb_encoding *enc;
4891 unsigned int c;
4892 int r, n;
4893
4894 RETURN_ENUMERATOR(io, 0, 0);
4895 GetOpenFile(io, fptr);
4896 rb_io_check_char_readable(fptr);
4897
4898 READ_CHECK(fptr);
4899 if (NEED_READCONV(fptr)) {
4900 SET_BINARY_MODE(fptr);
4901 r = 1; /* no invalid char yet */
4902 for (;;) {
4903 make_readconv(fptr, 0);
4904 for (;;) {
4905 if (fptr->cbuf.len) {
4906 if (fptr->encs.enc)
4907 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4908 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4909 fptr->encs.enc);
4910 else
4911 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4912 if (!MBCLEN_NEEDMORE_P(r))
4913 break;
4914 if (fptr->cbuf.len == fptr->cbuf.capa) {
4915 rb_raise(rb_eIOError, "too long character");
4916 }
4917 }
4918 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4919 clear_readconv(fptr);
4920 if (!MBCLEN_CHARFOUND_P(r)) {
4921 enc = fptr->encs.enc;
4922 goto invalid;
4923 }
4924 return io;
4925 }
4926 }
4927 if (MBCLEN_INVALID_P(r)) {
4928 enc = fptr->encs.enc;
4929 goto invalid;
4930 }
4931 n = MBCLEN_CHARFOUND_LEN(r);
4932 if (fptr->encs.enc) {
4933 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4934 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4935 fptr->encs.enc);
4936 }
4937 else {
4938 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4939 }
4940 fptr->cbuf.off += n;
4941 fptr->cbuf.len -= n;
4942 rb_yield(UINT2NUM(c));
4943 rb_io_check_byte_readable(fptr);
4944 }
4945 }
4946 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4947 enc = io_input_encoding(fptr);
4948 while (io_fillbuf(fptr) >= 0) {
4949 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4950 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4951 if (MBCLEN_CHARFOUND_P(r) &&
4952 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4953 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4954 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4955 fptr->rbuf.off += n;
4956 fptr->rbuf.len -= n;
4957 rb_yield(UINT2NUM(c));
4958 }
4959 else if (MBCLEN_INVALID_P(r)) {
4960 goto invalid;
4961 }
4962 else if (MBCLEN_NEEDMORE_P(r)) {
4963 char cbuf[8], *p = cbuf;
4964 int more = MBCLEN_NEEDMORE_LEN(r);
4965 if (more > numberof(cbuf)) goto invalid;
4966 more += n = fptr->rbuf.len;
4967 if (more > numberof(cbuf)) goto invalid;
4968 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4969 (p += n, (more -= n) > 0)) {
4970 if (io_fillbuf(fptr) < 0) goto invalid;
4971 if ((n = fptr->rbuf.len) > more) n = more;
4972 }
4973 r = rb_enc_precise_mbclen(cbuf, p, enc);
4974 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4975 c = rb_enc_codepoint(cbuf, p, enc);
4976 rb_yield(UINT2NUM(c));
4977 }
4978 else {
4979 continue;
4980 }
4981 rb_io_check_byte_readable(fptr);
4982 }
4983 return io;
4984
4985 invalid:
4986 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4987 UNREACHABLE_RETURN(Qundef);
4988}
4989
4990/*
4991 * call-seq:
4992 * getc -> character or nil
4993 *
4994 * Reads and returns the next 1-character string from the stream;
4995 * returns +nil+ if already at end-of-stream.
4996 * See {Character IO}[rdoc-ref:IO@Character+IO].
4997 *
4998 * f = File.open('t.txt')
4999 * f.getc # => "F"
5000 * f.close
5001 * f = File.open('t.rus')
5002 * f.getc.ord # => 1090
5003 * f.close
5004 *
5005 * Related: IO#readchar (may raise EOFError).
5006 *
5007 */
5008
5009static VALUE
5010rb_io_getc(VALUE io)
5011{
5012 rb_io_t *fptr;
5013 rb_encoding *enc;
5014
5015 GetOpenFile(io, fptr);
5016 rb_io_check_char_readable(fptr);
5017
5018 enc = io_input_encoding(fptr);
5019 READ_CHECK(fptr);
5020 return io_getc(fptr, enc);
5021}
5022
5023/*
5024 * call-seq:
5025 * readchar -> string
5026 *
5027 * Reads and returns the next 1-character string from the stream;
5028 * raises EOFError if already at end-of-stream.
5029 * See {Character IO}[rdoc-ref:IO@Character+IO].
5030 *
5031 * f = File.open('t.txt')
5032 * f.readchar # => "F"
5033 * f.close
5034 * f = File.open('t.rus')
5035 * f.readchar.ord # => 1090
5036 * f.close
5037 *
5038 * Related: IO#getc (will not raise EOFError).
5039 *
5040 */
5041
5042static VALUE
5043rb_io_readchar(VALUE io)
5044{
5045 VALUE c = rb_io_getc(io);
5046
5047 if (NIL_P(c)) {
5048 rb_eof_error();
5049 }
5050 return c;
5051}
5052
5053/*
5054 * call-seq:
5055 * getbyte -> integer or nil
5056 *
5057 * Reads and returns the next byte (in range 0..255) from the stream;
5058 * returns +nil+ if already at end-of-stream.
5059 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5060 *
5061 * f = File.open('t.txt')
5062 * f.getbyte # => 70
5063 * f.close
5064 * f = File.open('t.rus')
5065 * f.getbyte # => 209
5066 * f.close
5067 *
5068 * Related: IO#readbyte (may raise EOFError).
5069 */
5070
5071 VALUE
5072rb_io_getbyte(VALUE io)
5073{
5074 rb_io_t *fptr;
5075 int c;
5076
5077 GetOpenFile(io, fptr);
5078 rb_io_check_byte_readable(fptr);
5079 READ_CHECK(fptr);
5080 VALUE r_stdout = rb_ractor_stdout();
5081 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5082 rb_io_t *ofp;
5083 GetOpenFile(r_stdout, ofp);
5084 if (ofp->mode & FMODE_TTY) {
5085 rb_io_flush(r_stdout);
5086 }
5087 }
5088 if (io_fillbuf(fptr) < 0) {
5089 return Qnil;
5090 }
5091 fptr->rbuf.off++;
5092 fptr->rbuf.len--;
5093 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5094 return INT2FIX(c & 0xff);
5095}
5096
5097/*
5098 * call-seq:
5099 * readbyte -> integer
5100 *
5101 * Reads and returns the next byte (in range 0..255) from the stream;
5102 * raises EOFError if already at end-of-stream.
5103 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5104 *
5105 * f = File.open('t.txt')
5106 * f.readbyte # => 70
5107 * f.close
5108 * f = File.open('t.rus')
5109 * f.readbyte # => 209
5110 * f.close
5111 *
5112 * Related: IO#getbyte (will not raise EOFError).
5113 *
5114 */
5115
5116static VALUE
5117rb_io_readbyte(VALUE io)
5118{
5119 VALUE c = rb_io_getbyte(io);
5120
5121 if (NIL_P(c)) {
5122 rb_eof_error();
5123 }
5124 return c;
5125}
5126
5127/*
5128 * call-seq:
5129 * ungetbyte(integer) -> nil
5130 * ungetbyte(string) -> nil
5131 *
5132 * Pushes back ("unshifts") the given data onto the stream's buffer,
5133 * placing the data so that it is next to be read; returns +nil+.
5134 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5135 *
5136 * Note that:
5137 *
5138 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5139 * - Calling #rewind on the stream discards the pushed-back data.
5140 *
5141 * When argument +integer+ is given, uses only its low-order byte:
5142 *
5143 * File.write('t.tmp', '012')
5144 * f = File.open('t.tmp')
5145 * f.ungetbyte(0x41) # => nil
5146 * f.read # => "A012"
5147 * f.rewind
5148 * f.ungetbyte(0x4243) # => nil
5149 * f.read # => "C012"
5150 * f.close
5151 *
5152 * When argument +string+ is given, uses all bytes:
5153 *
5154 * File.write('t.tmp', '012')
5155 * f = File.open('t.tmp')
5156 * f.ungetbyte('A') # => nil
5157 * f.read # => "A012"
5158 * f.rewind
5159 * f.ungetbyte('BCDE') # => nil
5160 * f.read # => "BCDE012"
5161 * f.close
5162 *
5163 */
5164
5165 VALUE
5166rb_io_ungetbyte(VALUE io, VALUE b)
5167{
5168 rb_io_t *fptr;
5169
5170 GetOpenFile(io, fptr);
5171 rb_io_check_byte_readable(fptr);
5172 switch (TYPE(b)) {
5173 case T_NIL:
5174 return Qnil;
5175 case T_FIXNUM:
5176 case T_BIGNUM: ;
5177 VALUE v = rb_int_modulo(b, INT2FIX(256));
5178 unsigned char c = NUM2INT(v) & 0xFF;
5179 b = rb_str_new((const char *)&c, 1);
5180 break;
5181 default:
5182 StringValue(b);
5183 }
5184 io_ungetbyte(b, fptr);
5185 return Qnil;
5186}
5187
5188/*
5189 * call-seq:
5190 * ungetc(integer) -> nil
5191 * ungetc(string) -> nil
5192 *
5193 * Pushes back ("unshifts") the given data onto the stream's buffer,
5194 * placing the data so that it is next to be read; returns +nil+.
5195 * See {Character IO}[rdoc-ref:IO@Character+IO].
5196 *
5197 * Note that:
5198 *
5199 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5200 * - Calling #rewind on the stream discards the pushed-back data.
5201 *
5202 * When argument +integer+ is given, interprets the integer as a character:
5203 *
5204 * File.write('t.tmp', '012')
5205 * f = File.open('t.tmp')
5206 * f.ungetc(0x41) # => nil
5207 * f.read # => "A012"
5208 * f.rewind
5209 * f.ungetc(0x0442) # => nil
5210 * f.getc.ord # => 1090
5211 * f.close
5212 *
5213 * When argument +string+ is given, uses all characters:
5214 *
5215 * File.write('t.tmp', '012')
5216 * f = File.open('t.tmp')
5217 * f.ungetc('A') # => nil
5218 * f.read # => "A012"
5219 * f.rewind
5220 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5221 * f.getc.ord # => 1090
5222 * f.getc.ord # => 1077
5223 * f.getc.ord # => 1089
5224 * f.getc.ord # => 1090
5225 * f.close
5226 *
5227 */
5228
5229 VALUE
5230rb_io_ungetc(VALUE io, VALUE c)
5231{
5232 rb_io_t *fptr;
5233 long len;
5234
5235 GetOpenFile(io, fptr);
5236 rb_io_check_char_readable(fptr);
5237 if (FIXNUM_P(c)) {
5238 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5239 }
5240 else if (RB_BIGNUM_TYPE_P(c)) {
5241 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5242 }
5243 else {
5244 StringValue(c);
5245 }
5246 if (NEED_READCONV(fptr)) {
5247 SET_BINARY_MODE(fptr);
5248 len = RSTRING_LEN(c);
5249#if SIZEOF_LONG > SIZEOF_INT
5250 if (len > INT_MAX)
5251 rb_raise(rb_eIOError, "ungetc failed");
5252#endif
5253 make_readconv(fptr, (int)len);
5254 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5255 rb_raise(rb_eIOError, "ungetc failed");
5256 if (fptr->cbuf.off < len) {
5257 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5258 fptr->cbuf.ptr+fptr->cbuf.off,
5259 char, fptr->cbuf.len);
5260 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5261 }
5262 fptr->cbuf.off -= (int)len;
5263 fptr->cbuf.len += (int)len;
5264 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5265 }
5266 else {
5267 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5268 io_ungetbyte(c, fptr);
5269 }
5270 return Qnil;
5271}
5272
5273/*
5274 * call-seq:
5275 * isatty -> true or false
5276 *
5277 * Returns +true+ if the stream is associated with a terminal device (tty),
5278 * +false+ otherwise:
5279 *
5280 * f = File.new('t.txt').isatty #=> false
5281 * f.close
5282 * f = File.new('/dev/tty').isatty #=> true
5283 * f.close
5284 *
5285 */
5286
5287static VALUE
5288rb_io_isatty(VALUE io)
5289{
5290 rb_io_t *fptr;
5291
5292 GetOpenFile(io, fptr);
5293 return RBOOL(isatty(fptr->fd) != 0);
5294}
5295
5296#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5297/*
5298 * call-seq:
5299 * close_on_exec? -> true or false
5300 *
5301 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5302 *
5303 * f = File.open('t.txt')
5304 * f.close_on_exec? # => true
5305 * f.close_on_exec = false
5306 * f.close_on_exec? # => false
5307 * f.close
5308 *
5309 */
5310
5311static VALUE
5312rb_io_close_on_exec_p(VALUE io)
5313{
5314 rb_io_t *fptr;
5315 VALUE write_io;
5316 int fd, ret;
5317
5318 write_io = GetWriteIO(io);
5319 if (io != write_io) {
5320 GetOpenFile(write_io, fptr);
5321 if (fptr && 0 <= (fd = fptr->fd)) {
5322 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5323 if (!(ret & FD_CLOEXEC)) return Qfalse;
5324 }
5325 }
5326
5327 GetOpenFile(io, fptr);
5328 if (fptr && 0 <= (fd = fptr->fd)) {
5329 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5330 if (!(ret & FD_CLOEXEC)) return Qfalse;
5331 }
5332 return Qtrue;
5333}
5334#else
5335#define rb_io_close_on_exec_p rb_f_notimplement
5336#endif
5337
5338#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5339/*
5340 * call-seq:
5341 * self.close_on_exec = bool -> true or false
5342 *
5343 * Sets a close-on-exec flag.
5344 *
5345 * f = File.open(File::NULL)
5346 * f.close_on_exec = true
5347 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5348 * f.closed? #=> false
5349 *
5350 * Ruby sets close-on-exec flags of all file descriptors by default
5351 * since Ruby 2.0.0.
5352 * So you don't need to set by yourself.
5353 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5354 * if another thread use fork() and exec() (via system() method for example).
5355 * If you really needs file descriptor inheritance to child process,
5356 * use spawn()'s argument such as fd=>fd.
5357 */
5358
5359static VALUE
5360rb_io_set_close_on_exec(VALUE io, VALUE arg)
5361{
5362 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5363 rb_io_t *fptr;
5364 VALUE write_io;
5365 int fd, ret;
5366
5367 write_io = GetWriteIO(io);
5368 if (io != write_io) {
5369 GetOpenFile(write_io, fptr);
5370 if (fptr && 0 <= (fd = fptr->fd)) {
5371 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5372 if ((ret & FD_CLOEXEC) != flag) {
5373 ret = (ret & ~FD_CLOEXEC) | flag;
5374 ret = fcntl(fd, F_SETFD, ret);
5375 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5376 }
5377 }
5378
5379 }
5380
5381 GetOpenFile(io, fptr);
5382 if (fptr && 0 <= (fd = fptr->fd)) {
5383 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5384 if ((ret & FD_CLOEXEC) != flag) {
5385 ret = (ret & ~FD_CLOEXEC) | flag;
5386 ret = fcntl(fd, F_SETFD, ret);
5387 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5388 }
5389 }
5390 return Qnil;
5391}
5392#else
5393#define rb_io_set_close_on_exec rb_f_notimplement
5394#endif
5395
5396#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5397#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5398
5399static VALUE
5400finish_writeconv(rb_io_t *fptr, int noalloc)
5401{
5402 unsigned char *ds, *dp, *de;
5403 rb_econv_result_t res;
5404
5405 if (!fptr->wbuf.ptr) {
5406 unsigned char buf[1024];
5407
5408 res = econv_destination_buffer_full;
5409 while (res == econv_destination_buffer_full) {
5410 ds = dp = buf;
5411 de = buf + sizeof(buf);
5412 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5413 while (dp-ds) {
5414 size_t remaining = dp-ds;
5415 long result = rb_io_write_memory(fptr, ds, remaining);
5416
5417 if (result > 0) {
5418 ds += result;
5419 if ((size_t)result == remaining) break;
5420 }
5421 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5422 if (fptr->fd < 0)
5423 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5424 }
5425 else {
5426 return noalloc ? Qtrue : INT2NUM(errno);
5427 }
5428 }
5429 if (res == econv_invalid_byte_sequence ||
5430 res == econv_incomplete_input ||
5431 res == econv_undefined_conversion) {
5432 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5433 }
5434 }
5435
5436 return Qnil;
5437 }
5438
5439 res = econv_destination_buffer_full;
5440 while (res == econv_destination_buffer_full) {
5441 if (fptr->wbuf.len == fptr->wbuf.capa) {
5442 if (io_fflush(fptr) < 0) {
5443 return noalloc ? Qtrue : INT2NUM(errno);
5444 }
5445 }
5446
5447 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5448 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5449 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5450 fptr->wbuf.len += (int)(dp - ds);
5451 if (res == econv_invalid_byte_sequence ||
5452 res == econv_incomplete_input ||
5453 res == econv_undefined_conversion) {
5454 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5455 }
5456 }
5457 return Qnil;
5458}
5459
5460 struct finish_writeconv_arg {
5461 rb_io_t *fptr;
5462 int noalloc;
5463};
5464
5465static VALUE
5466finish_writeconv_sync(VALUE arg)
5467{
5468 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5469 return finish_writeconv(p->fptr, p->noalloc);
5470}
5471
5472static void*
5473nogvl_close(void *ptr)
5474{
5475 int *fd = ptr;
5476
5477 return (void*)(intptr_t)close(*fd);
5478}
5479
5480static int
5481maygvl_close(int fd, int keepgvl)
5482{
5483 if (keepgvl)
5484 return close(fd);
5485
5486 /*
5487 * close() may block for certain file types (NFS, SO_LINGER sockets,
5488 * inotify), so let other threads run.
5489 */
5490 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5491}
5492
5493static void*
5494nogvl_fclose(void *ptr)
5495{
5496 FILE *file = ptr;
5497
5498 return (void*)(intptr_t)fclose(file);
5499}
5500
5501static int
5502maygvl_fclose(FILE *file, int keepgvl)
5503{
5504 if (keepgvl)
5505 return fclose(file);
5506
5507 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5508}
5509
5510static void free_io_buffer(rb_io_buffer_t *buf);
5511
5512static void
5513fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5514 struct rb_io_close_wait_list *busy)
5515{
5516 VALUE error = Qnil;
5517 int fd = fptr->fd;
5518 FILE *stdio_file = fptr->stdio_file;
5519 int mode = fptr->mode;
5520
5521 if (fptr->writeconv) {
5522 if (!NIL_P(fptr->write_lock) && !noraise) {
5523 struct finish_writeconv_arg arg;
5524 arg.fptr = fptr;
5525 arg.noalloc = noraise;
5526 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5527 }
5528 else {
5529 error = finish_writeconv(fptr, noraise);
5530 }
5531 }
5532 if (fptr->wbuf.len) {
5533 if (noraise) {
5534 io_flush_buffer_sync(fptr);
5535 }
5536 else {
5537 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5538 error = INT2NUM(errno);
5539 }
5540 }
5541 }
5542
5543 int done = 0;
5544
5545 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5546 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5547 done = 1;
5548 }
5549
5550 fptr->fd = -1;
5551 fptr->stdio_file = 0;
5552 fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
5553
5554 // Ensure waiting_fd users do not hit EBADF.
5555 if (busy) {
5556 // Wait for them to exit before we call close().
5557 rb_notify_fd_close_wait(busy);
5558 }
5559
5560 // Disable for now.
5561 // if (!done && fd >= 0) {
5562 // VALUE scheduler = rb_fiber_scheduler_current();
5563 // if (scheduler != Qnil) {
5564 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5565 // if (!UNDEF_P(result)) done = 1;
5566 // }
5567 // }
5568
5569 if (!done && stdio_file) {
5570 // stdio_file is deallocated anyway even if fclose failed.
5571 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5572 if (!noraise) {
5573 error = INT2NUM(errno);
5574 }
5575 }
5576
5577 done = 1;
5578 }
5579
5580 if (!done && fd >= 0) {
5581 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5582 // We assumes it is closed.
5583
5584 keepgvl |= !(mode & FMODE_WRITABLE);
5585 keepgvl |= noraise;
5586 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5587 if (!noraise) {
5588 error = INT2NUM(errno);
5589 }
5590 }
5591
5592 done = 1;
5593 }
5594
5595 if (!NIL_P(error) && !noraise) {
5596 if (RB_INTEGER_TYPE_P(error))
5597 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5598 else
5599 rb_exc_raise(error);
5600 }
5601}
5602
5603static void
5604fptr_finalize(rb_io_t *fptr, int noraise)
5605{
5606 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5607 free_io_buffer(&fptr->rbuf);
5608 free_io_buffer(&fptr->wbuf);
5609 clear_codeconv(fptr);
5610}
5611
5612static void
5613rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5614{
5615 if (fptr->finalize) {
5616 (*fptr->finalize)(fptr, noraise);
5617 }
5618 else {
5619 fptr_finalize(fptr, noraise);
5620 }
5621}
5622
5623static void
5624free_io_buffer(rb_io_buffer_t *buf)
5625{
5626 if (buf->ptr) {
5627 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5628 buf->ptr = NULL;
5629 }
5630}
5631
5632static void
5633clear_readconv(rb_io_t *fptr)
5634{
5635 if (fptr->readconv) {
5636 rb_econv_close(fptr->readconv);
5637 fptr->readconv = NULL;
5638 }
5639 free_io_buffer(&fptr->cbuf);
5640}
5641
5642static void
5643clear_writeconv(rb_io_t *fptr)
5644{
5645 if (fptr->writeconv) {
5646 rb_econv_close(fptr->writeconv);
5647 fptr->writeconv = NULL;
5648 }
5649 fptr->writeconv_initialized = 0;
5650}
5651
5652static void
5653clear_codeconv(rb_io_t *fptr)
5654{
5655 clear_readconv(fptr);
5656 clear_writeconv(fptr);
5657}
5658
5659static void
5660rb_io_fptr_cleanup_all(rb_io_t *fptr)
5661{
5662 fptr->pathv = Qnil;
5663 if (0 <= fptr->fd)
5664 rb_io_fptr_cleanup(fptr, TRUE);
5665 fptr->write_lock = Qnil;
5666 free_io_buffer(&fptr->rbuf);
5667 free_io_buffer(&fptr->wbuf);
5668 clear_codeconv(fptr);
5669}
5670
5671void
5672rb_io_fptr_finalize_internal(void *ptr)
5673{
5674 if (!ptr) return;
5675 rb_io_fptr_cleanup_all(ptr);
5676 free(ptr);
5677}
5678
5679#undef rb_io_fptr_finalize
5680int
5681rb_io_fptr_finalize(rb_io_t *fptr)
5682{
5683 if (!fptr) {
5684 return 0;
5685 }
5686 else {
5687 rb_io_fptr_finalize_internal(fptr);
5688 return 1;
5689 }
5690}
5691#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5692
5693size_t
5694rb_io_memsize(const rb_io_t *fptr)
5695{
5696 size_t size = sizeof(rb_io_t);
5697 size += fptr->rbuf.capa;
5698 size += fptr->wbuf.capa;
5699 size += fptr->cbuf.capa;
5700 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5701 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5702 return size;
5703}
5704
5705#ifdef _WIN32
5706/* keep GVL while closing to prevent crash on Windows */
5707# define KEEPGVL TRUE
5708#else
5709# define KEEPGVL FALSE
5710#endif
5711
5712static rb_io_t *
5713io_close_fptr(VALUE io)
5714{
5715 rb_io_t *fptr;
5716 VALUE write_io;
5717 rb_io_t *write_fptr;
5718 struct rb_io_close_wait_list busy;
5719
5720 write_io = GetWriteIO(io);
5721 if (io != write_io) {
5722 write_fptr = RFILE(write_io)->fptr;
5723 if (write_fptr && 0 <= write_fptr->fd) {
5724 rb_io_fptr_cleanup(write_fptr, TRUE);
5725 }
5726 }
5727
5728 fptr = RFILE(io)->fptr;
5729 if (!fptr) return 0;
5730 if (fptr->fd < 0) return 0;
5731
5732 if (rb_notify_fd_close(fptr->fd, &busy)) {
5733 /* calls close(fptr->fd): */
5734 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5735 }
5736 rb_io_fptr_cleanup(fptr, FALSE);
5737 return fptr;
5738}
5739
5740static void
5741fptr_waitpid(rb_io_t *fptr, int nohang)
5742{
5743 int status;
5744 if (fptr->pid) {
5745 rb_last_status_clear();
5746 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5747 fptr->pid = 0;
5748 }
5749}
5750
5751 VALUE
5752rb_io_close(VALUE io)
5753{
5754 rb_io_t *fptr = io_close_fptr(io);
5755 if (fptr) fptr_waitpid(fptr, 0);
5756 return Qnil;
5757}
5758
5759/*
5760 * call-seq:
5761 * close -> nil
5762 *
5763 * Closes the stream for both reading and writing
5764 * if open for either or both; returns +nil+.
5765 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5766 *
5767 * If the stream is open for writing, flushes any buffered writes
5768 * to the operating system before closing.
5769 *
5770 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5771 * (child exit status).
5772 *
5773 * It is not an error to close an IO object that has already been closed.
5774 * It just returns nil.
5775 *
5776 * Example:
5777 *
5778 * IO.popen('ruby', 'r+') do |pipe|
5779 * puts pipe.closed?
5780 * pipe.close
5781 * puts $?
5782 * puts pipe.closed?
5783 * end
5784 *
5785 * Output:
5786 *
5787 * false
5788 * pid 13760 exit 0
5789 * true
5790 *
5791 * Related: IO#close_read, IO#close_write, IO#closed?.
5792 */
5793
5794static VALUE
5795rb_io_close_m(VALUE io)
5796{
5797 rb_io_t *fptr = rb_io_get_fptr(io);
5798 if (fptr->fd < 0) {
5799 return Qnil;
5800 }
5801 rb_io_close(io);
5802 return Qnil;
5803}
5804
5805static VALUE
5806io_call_close(VALUE io)
5807{
5808 rb_check_funcall(io, rb_intern("close"), 0, 0);
5809 return io;
5810}
5811
5812static VALUE
5813ignore_closed_stream(VALUE io, VALUE exc)
5814{
5815 enum {mesg_len = sizeof(closed_stream)-1};
5816 VALUE mesg = rb_attr_get(exc, idMesg);
5817 if (!RB_TYPE_P(mesg, T_STRING) ||
5818 RSTRING_LEN(mesg) != mesg_len ||
5819 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5820 rb_exc_raise(exc);
5821 }
5822 return io;
5823}
5824
5825static VALUE
5826io_close(VALUE io)
5827{
5828 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5829 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5830 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5831 rb_eIOError, (VALUE)0);
5832 return io;
5833}
5834
5835/*
5836 * call-seq:
5837 * closed? -> true or false
5838 *
5839 * Returns +true+ if the stream is closed for both reading and writing,
5840 * +false+ otherwise.
5841 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5842 *
5843 * IO.popen('ruby', 'r+') do |pipe|
5844 * puts pipe.closed?
5845 * pipe.close_read
5846 * puts pipe.closed?
5847 * pipe.close_write
5848 * puts pipe.closed?
5849 * end
5850 *
5851 * Output:
5852 *
5853 * false
5854 * false
5855 * true
5856 *
5857 * Related: IO#close_read, IO#close_write, IO#close.
5858 */
5859 VALUE
5860rb_io_closed_p(VALUE io)
5861{
5862 rb_io_t *fptr;
5863 VALUE write_io;
5864 rb_io_t *write_fptr;
5865
5866 write_io = GetWriteIO(io);
5867 if (io != write_io) {
5868 write_fptr = RFILE(write_io)->fptr;
5869 if (write_fptr && 0 <= write_fptr->fd) {
5870 return Qfalse;
5871 }
5872 }
5873
5874 fptr = rb_io_get_fptr(io);
5875 return RBOOL(0 > fptr->fd);
5876}
5877
5878/*
5879 * call-seq:
5880 * close_read -> nil
5881 *
5882 * Closes the stream for reading if open for reading;
5883 * returns +nil+.
5884 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5885 *
5886 * If the stream was opened by IO.popen and is also closed for writing,
5887 * sets global variable <tt>$?</tt> (child exit status).
5888 *
5889 * Example:
5890 *
5891 * IO.popen('ruby', 'r+') do |pipe|
5892 * puts pipe.closed?
5893 * pipe.close_write
5894 * puts pipe.closed?
5895 * pipe.close_read
5896 * puts $?
5897 * puts pipe.closed?
5898 * end
5899 *
5900 * Output:
5901 *
5902 * false
5903 * false
5904 * pid 14748 exit 0
5905 * true
5906 *
5907 * Related: IO#close, IO#close_write, IO#closed?.
5908 */
5909
5910static VALUE
5911rb_io_close_read(VALUE io)
5912{
5913 rb_io_t *fptr;
5914 VALUE write_io;
5915
5916 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5917 if (fptr->fd < 0) return Qnil;
5918 if (is_socket(fptr->fd, fptr->pathv)) {
5919#ifndef SHUT_RD
5920# define SHUT_RD 0
5921#endif
5922 if (shutdown(fptr->fd, SHUT_RD) < 0)
5923 rb_sys_fail_path(fptr->pathv);
5924 fptr->mode &= ~FMODE_READABLE;
5925 if (!(fptr->mode & FMODE_WRITABLE))
5926 return rb_io_close(io);
5927 return Qnil;
5928 }
5929
5930 write_io = GetWriteIO(io);
5931 if (io != write_io) {
5932 rb_io_t *wfptr;
5933 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5934 wfptr->pid = fptr->pid;
5935 fptr->pid = 0;
5936 RFILE(io)->fptr = wfptr;
5937 /* bind to write_io temporarily to get rid of memory/fd leak */
5938 fptr->tied_io_for_writing = 0;
5939 RFILE(write_io)->fptr = fptr;
5940 rb_io_fptr_cleanup(fptr, FALSE);
5941 /* should not finalize fptr because another thread may be reading it */
5942 return Qnil;
5943 }
5944
5945 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5946 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5947 }
5948 return rb_io_close(io);
5949}
5950
5951/*
5952 * call-seq:
5953 * close_write -> nil
5954 *
5955 * Closes the stream for writing if open for writing;
5956 * returns +nil+.
5957 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5958 *
5959 * Flushes any buffered writes to the operating system before closing.
5960 *
5961 * If the stream was opened by IO.popen and is also closed for reading,
5962 * sets global variable <tt>$?</tt> (child exit status).
5963 *
5964 * IO.popen('ruby', 'r+') do |pipe|
5965 * puts pipe.closed?
5966 * pipe.close_read
5967 * puts pipe.closed?
5968 * pipe.close_write
5969 * puts $?
5970 * puts pipe.closed?
5971 * end
5972 *
5973 * Output:
5974 *
5975 * false
5976 * false
5977 * pid 15044 exit 0
5978 * true
5979 *
5980 * Related: IO#close, IO#close_read, IO#closed?.
5981 */
5982
5983static VALUE
5984rb_io_close_write(VALUE io)
5985{
5986 rb_io_t *fptr;
5987 VALUE write_io;
5988
5989 write_io = GetWriteIO(io);
5990 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5991 if (fptr->fd < 0) return Qnil;
5992 if (is_socket(fptr->fd, fptr->pathv)) {
5993#ifndef SHUT_WR
5994# define SHUT_WR 1
5995#endif
5996 if (shutdown(fptr->fd, SHUT_WR) < 0)
5997 rb_sys_fail_path(fptr->pathv);
5998 fptr->mode &= ~FMODE_WRITABLE;
5999 if (!(fptr->mode & FMODE_READABLE))
6000 return rb_io_close(write_io);
6001 return Qnil;
6002 }
6003
6004 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6005 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6006 }
6007
6008 if (io != write_io) {
6009 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6010 fptr->tied_io_for_writing = 0;
6011 }
6012 rb_io_close(write_io);
6013 return Qnil;
6014}
6015
6016/*
6017 * call-seq:
6018 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6019 *
6020 * Behaves like IO#seek, except that it:
6021 *
6022 * - Uses low-level system functions.
6023 * - Returns the new position.
6024 *
6025 */
6026
6027static VALUE
6028rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6029{
6030 VALUE offset, ptrname;
6031 int whence = SEEK_SET;
6032 rb_io_t *fptr;
6033 rb_off_t pos;
6034
6035 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6036 whence = interpret_seek_whence(ptrname);
6037 }
6038 pos = NUM2OFFT(offset);
6039 GetOpenFile(io, fptr);
6040 if ((fptr->mode & FMODE_READABLE) &&
6041 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6042 rb_raise(rb_eIOError, "sysseek for buffered IO");
6043 }
6044 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6045 rb_warn("sysseek for buffered IO");
6046 }
6047 errno = 0;
6048 pos = lseek(fptr->fd, pos, whence);
6049 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6050
6051 return OFFT2NUM(pos);
6052}
6053
6054/*
6055 * call-seq:
6056 * syswrite(object) -> integer
6057 *
6058 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6059 * returns the number bytes written.
6060 * If +object+ is not a string is converted via method to_s:
6061 *
6062 * f = File.new('t.tmp', 'w')
6063 * f.syswrite('foo') # => 3
6064 * f.syswrite(30) # => 2
6065 * f.syswrite(:foo) # => 3
6066 * f.close
6067 *
6068 * This methods should not be used with other stream-writer methods.
6069 *
6070 */
6071
6072static VALUE
6073rb_io_syswrite(VALUE io, VALUE str)
6074{
6075 VALUE tmp;
6076 rb_io_t *fptr;
6077 long n, len;
6078 const char *ptr;
6079
6080 if (!RB_TYPE_P(str, T_STRING))
6081 str = rb_obj_as_string(str);
6082
6083 io = GetWriteIO(io);
6084 GetOpenFile(io, fptr);
6085 rb_io_check_writable(fptr);
6086
6087 if (fptr->wbuf.len) {
6088 rb_warn("syswrite for buffered IO");
6089 }
6090
6091 tmp = rb_str_tmp_frozen_acquire(str);
6092 RSTRING_GETMEM(tmp, ptr, len);
6093 n = rb_io_write_memory(fptr, ptr, len);
6094 if (n < 0) rb_sys_fail_path(fptr->pathv);
6095 rb_str_tmp_frozen_release(str, tmp);
6096
6097 return LONG2FIX(n);
6098}
6099
6100/*
6101 * call-seq:
6102 * sysread(maxlen) -> string
6103 * sysread(maxlen, out_string) -> string
6104 *
6105 * Behaves like IO#readpartial, except that it uses low-level system functions.
6106 *
6107 * This method should not be used with other stream-reader methods.
6108 *
6109 */
6110
6111static VALUE
6112rb_io_sysread(int argc, VALUE *argv, VALUE io)
6113{
6114 VALUE len, str;
6115 rb_io_t *fptr;
6116 long n, ilen;
6117 struct io_internal_read_struct iis;
6118 int shrinkable;
6119
6120 rb_scan_args(argc, argv, "11", &len, &str);
6121 ilen = NUM2LONG(len);
6122
6123 shrinkable = io_setstrbuf(&str, ilen);
6124 if (ilen == 0) return str;
6125
6126 GetOpenFile(io, fptr);
6127 rb_io_check_byte_readable(fptr);
6128
6129 if (READ_DATA_BUFFERED(fptr)) {
6130 rb_raise(rb_eIOError, "sysread for buffered IO");
6131 }
6132
6133 rb_io_check_closed(fptr);
6134
6135 io_setstrbuf(&str, ilen);
6136 iis.th = rb_thread_current();
6137 iis.fptr = fptr;
6138 iis.nonblock = 0;
6139 iis.fd = fptr->fd;
6140 iis.buf = RSTRING_PTR(str);
6141 iis.capa = ilen;
6142 iis.timeout = NULL;
6143 n = io_read_memory_locktmp(str, &iis);
6144
6145 if (n < 0) {
6146 rb_sys_fail_path(fptr->pathv);
6147 }
6148
6149 io_set_read_length(str, n, shrinkable);
6150
6151 if (n == 0 && ilen > 0) {
6152 rb_eof_error();
6153 }
6154
6155 return str;
6156}
6157
6158 struct prdwr_internal_arg {
6159 struct rb_io *io;
6160 int fd;
6161 void *buf;
6162 size_t count;
6163 rb_off_t offset;
6164};
6165
6166static VALUE
6167internal_pread_func(void *_arg)
6168{
6169 struct prdwr_internal_arg *arg = _arg;
6170
6171 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6172}
6173
6174static VALUE
6175pread_internal_call(VALUE _arg)
6176{
6177 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6178
6179 VALUE scheduler = rb_fiber_scheduler_current();
6180 if (scheduler != Qnil) {
6181 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6182
6183 if (!UNDEF_P(result)) {
6184 return rb_fiber_scheduler_io_result_apply(result);
6185 }
6186 }
6187
6188 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6189}
6190
6191/*
6192 * call-seq:
6193 * pread(maxlen, offset) -> string
6194 * pread(maxlen, offset, out_string) -> string
6195 *
6196 * Behaves like IO#readpartial, except that it:
6197 *
6198 * - Reads at the given +offset+ (in bytes).
6199 * - Disregards, and does not modify, the stream's position
6200 * (see {Position}[rdoc-ref:IO@Position]).
6201 * - Bypasses any user space buffering in the stream.
6202 *
6203 * Because this method does not disturb the stream's state
6204 * (its position, in particular), +pread+ allows multiple threads and processes
6205 * to use the same \IO object for reading at various offsets.
6206 *
6207 * f = File.open('t.txt')
6208 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6209 * f.pos # => 52
6210 * # Read 12 bytes at offset 0.
6211 * f.pread(12, 0) # => "First line\n"
6212 * # Read 9 bytes at offset 8.
6213 * f.pread(9, 8) # => "ne\nSecon"
6214 * f.close
6215 *
6216 * Not available on some platforms.
6217 *
6218 */
6219static VALUE
6220rb_io_pread(int argc, VALUE *argv, VALUE io)
6221{
6222 VALUE len, offset, str;
6223 rb_io_t *fptr;
6224 ssize_t n;
6225 struct prdwr_internal_arg arg;
6226 int shrinkable;
6227
6228 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6229 arg.count = NUM2SIZET(len);
6230 arg.offset = NUM2OFFT(offset);
6231
6232 shrinkable = io_setstrbuf(&str, (long)arg.count);
6233 if (arg.count == 0) return str;
6234 arg.buf = RSTRING_PTR(str);
6235
6236 GetOpenFile(io, fptr);
6237 rb_io_check_byte_readable(fptr);
6238
6239 arg.io = fptr;
6240 arg.fd = fptr->fd;
6241 rb_io_check_closed(fptr);
6242
6243 rb_str_locktmp(str);
6244 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6245
6246 if (n < 0) {
6247 rb_sys_fail_path(fptr->pathv);
6248 }
6249 io_set_read_length(str, n, shrinkable);
6250 if (n == 0 && arg.count > 0) {
6251 rb_eof_error();
6252 }
6253
6254 return str;
6255}
6256
6257static VALUE
6258internal_pwrite_func(void *_arg)
6259{
6260 struct prdwr_internal_arg *arg = _arg;
6261
6262 VALUE scheduler = rb_fiber_scheduler_current();
6263 if (scheduler != Qnil) {
6264 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6265
6266 if (!UNDEF_P(result)) {
6267 return rb_fiber_scheduler_io_result_apply(result);
6268 }
6269 }
6270
6271
6272 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6273}
6274
6275/*
6276 * call-seq:
6277 * pwrite(object, offset) -> integer
6278 *
6279 * Behaves like IO#write, except that it:
6280 *
6281 * - Writes at the given +offset+ (in bytes).
6282 * - Disregards, and does not modify, the stream's position
6283 * (see {Position}[rdoc-ref:IO@Position]).
6284 * - Bypasses any user space buffering in the stream.
6285 *
6286 * Because this method does not disturb the stream's state
6287 * (its position, in particular), +pwrite+ allows multiple threads and processes
6288 * to use the same \IO object for writing at various offsets.
6289 *
6290 * f = File.open('t.tmp', 'w+')
6291 * # Write 6 bytes at offset 3.
6292 * f.pwrite('ABCDEF', 3) # => 6
6293 * f.rewind
6294 * f.read # => "\u0000\u0000\u0000ABCDEF"
6295 * f.close
6296 *
6297 * Not available on some platforms.
6298 *
6299 */
6300static VALUE
6301rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6302{
6303 rb_io_t *fptr;
6304 ssize_t n;
6305 struct prdwr_internal_arg arg;
6306 VALUE tmp;
6307
6308 if (!RB_TYPE_P(str, T_STRING))
6309 str = rb_obj_as_string(str);
6310
6311 arg.offset = NUM2OFFT(offset);
6312
6313 io = GetWriteIO(io);
6314 GetOpenFile(io, fptr);
6315 rb_io_check_writable(fptr);
6316
6317 arg.io = fptr;
6318 arg.fd = fptr->fd;
6319
6320 tmp = rb_str_tmp_frozen_acquire(str);
6321 arg.buf = RSTRING_PTR(tmp);
6322 arg.count = (size_t)RSTRING_LEN(tmp);
6323
6324 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
6325 if (n < 0) rb_sys_fail_path(fptr->pathv);
6326 rb_str_tmp_frozen_release(str, tmp);
6327
6328 return SSIZET2NUM(n);
6329}
6330
6331 VALUE
6332rb_io_binmode(VALUE io)
6333{
6334 rb_io_t *fptr;
6335
6336 GetOpenFile(io, fptr);
6337 if (fptr->readconv)
6338 rb_econv_binmode(fptr->readconv);
6339 if (fptr->writeconv)
6340 rb_econv_binmode(fptr->writeconv);
6341 fptr->mode |= FMODE_BINMODE;
6342 fptr->mode &= ~FMODE_TEXTMODE;
6343 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6344#ifdef O_BINARY
6345 if (!fptr->readconv) {
6346 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6347 }
6348 else {
6349 setmode(fptr->fd, O_BINARY);
6350 }
6351#endif
6352 return io;
6353}
6354
6355static void
6356io_ascii8bit_binmode(rb_io_t *fptr)
6357{
6358 if (fptr->readconv) {
6359 rb_econv_close(fptr->readconv);
6360 fptr->readconv = NULL;
6361 }
6362 if (fptr->writeconv) {
6363 rb_econv_close(fptr->writeconv);
6364 fptr->writeconv = NULL;
6365 }
6366 fptr->mode |= FMODE_BINMODE;
6367 fptr->mode &= ~FMODE_TEXTMODE;
6368 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6369
6370 fptr->encs.enc = rb_ascii8bit_encoding();
6371 fptr->encs.enc2 = NULL;
6372 fptr->encs.ecflags = 0;
6373 fptr->encs.ecopts = Qnil;
6374 clear_codeconv(fptr);
6375}
6376
6377 VALUE
6378rb_io_ascii8bit_binmode(VALUE io)
6379{
6380 rb_io_t *fptr;
6381
6382 GetOpenFile(io, fptr);
6383 io_ascii8bit_binmode(fptr);
6384
6385 return io;
6386}
6387
6388/*
6389 * call-seq:
6390 * binmode -> self
6391 *
6392 * Sets the stream's data mode as binary
6393 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6394 *
6395 * A stream's data mode may not be changed from binary to text.
6396 *
6397 */
6398
6399static VALUE
6400rb_io_binmode_m(VALUE io)
6401{
6402 VALUE write_io;
6403
6404 rb_io_ascii8bit_binmode(io);
6405
6406 write_io = GetWriteIO(io);
6407 if (write_io != io)
6408 rb_io_ascii8bit_binmode(write_io);
6409 return io;
6410}
6411
6412/*
6413 * call-seq:
6414 * binmode? -> true or false
6415 *
6416 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6417 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6418 *
6419 */
6420static VALUE
6421rb_io_binmode_p(VALUE io)
6422{
6423 rb_io_t *fptr;
6424 GetOpenFile(io, fptr);
6425 return RBOOL(fptr->mode & FMODE_BINMODE);
6426}
6427
6428static const char*
6429rb_io_fmode_modestr(int fmode)
6430{
6431 if (fmode & FMODE_APPEND) {
6432 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6433 return MODE_BTMODE("a+", "ab+", "at+");
6434 }
6435 return MODE_BTMODE("a", "ab", "at");
6436 }
6437 switch (fmode & FMODE_READWRITE) {
6438 default:
6439 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6440 case FMODE_READABLE:
6441 return MODE_BTMODE("r", "rb", "rt");
6442 case FMODE_WRITABLE:
6443 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6444 case FMODE_READWRITE:
6445 if (fmode & FMODE_CREATE) {
6446 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6447 }
6448 return MODE_BTMODE("r+", "rb+", "rt+");
6449 }
6450}
6451
6452static const char bom_prefix[] = "bom|";
6453static const char utf_prefix[] = "utf-";
6454enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6455enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6456
6457static int
6458io_encname_bom_p(const char *name, long len)
6459{
6460 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6461}
6462
6463int
6464rb_io_modestr_fmode(const char *modestr)
6465{
6466 int fmode = 0;
6467 const char *m = modestr, *p = NULL;
6468
6469 switch (*m++) {
6470 case 'r':
6471 fmode |= FMODE_READABLE;
6472 break;
6473 case 'w':
6474 fmode |= FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE;
6475 break;
6476 case 'a':
6477 fmode |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
6478 break;
6479 default:
6480 goto error;
6481 }
6482
6483 while (*m) {
6484 switch (*m++) {
6485 case 'b':
6486 fmode |= FMODE_BINMODE;
6487 break;
6488 case 't':
6489 fmode |= FMODE_TEXTMODE;
6490 break;
6491 case '+':
6492 fmode |= FMODE_READWRITE;
6493 break;
6494 case 'x':
6495 if (modestr[0] != 'w')
6496 goto error;
6497 fmode |= FMODE_EXCL;
6498 break;
6499 default:
6500 goto error;
6501 case ':':
6502 p = strchr(m, ':');
6503 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6504 fmode |= FMODE_SETENC_BY_BOM;
6505 goto finished;
6506 }
6507 }
6508
6509 finished:
6510 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6511 goto error;
6512
6513 return fmode;
6514
6515 error:
6516 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6517 UNREACHABLE_RETURN(Qundef);
6518}
6519
6520int
6521rb_io_oflags_fmode(int oflags)
6522{
6523 int fmode = 0;
6524
6525 switch (oflags & O_ACCMODE) {
6526 case O_RDONLY:
6527 fmode = FMODE_READABLE;
6528 break;
6529 case O_WRONLY:
6530 fmode = FMODE_WRITABLE;
6531 break;
6532 case O_RDWR:
6533 fmode = FMODE_READWRITE;
6534 break;
6535 }
6536
6537 if (oflags & O_APPEND) {
6538 fmode |= FMODE_APPEND;
6539 }
6540 if (oflags & O_TRUNC) {
6541 fmode |= FMODE_TRUNC;
6542 }
6543 if (oflags & O_CREAT) {
6544 fmode |= FMODE_CREATE;
6545 }
6546 if (oflags & O_EXCL) {
6547 fmode |= FMODE_EXCL;
6548 }
6549#ifdef O_BINARY
6550 if (oflags & O_BINARY) {
6551 fmode |= FMODE_BINMODE;
6552 }
6553#endif
6554
6555 return fmode;
6556}
6557
6558static int
6559rb_io_fmode_oflags(int fmode)
6560{
6561 int oflags = 0;
6562
6563 switch (fmode & FMODE_READWRITE) {
6564 case FMODE_READABLE:
6565 oflags |= O_RDONLY;
6566 break;
6567 case FMODE_WRITABLE:
6568 oflags |= O_WRONLY;
6569 break;
6570 case FMODE_READWRITE:
6571 oflags |= O_RDWR;
6572 break;
6573 }
6574
6575 if (fmode & FMODE_APPEND) {
6576 oflags |= O_APPEND;
6577 }
6578 if (fmode & FMODE_TRUNC) {
6579 oflags |= O_TRUNC;
6580 }
6581 if (fmode & FMODE_CREATE) {
6582 oflags |= O_CREAT;
6583 }
6584 if (fmode & FMODE_EXCL) {
6585 oflags |= O_EXCL;
6586 }
6587#ifdef O_BINARY
6588 if (fmode & FMODE_BINMODE) {
6589 oflags |= O_BINARY;
6590 }
6591#endif
6592
6593 return oflags;
6594}
6595
6596int
6597rb_io_modestr_oflags(const char *modestr)
6598{
6599 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6600}
6601
6602static const char*
6603rb_io_oflags_modestr(int oflags)
6604{
6605#ifdef O_BINARY
6606# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6607#else
6608# define MODE_BINARY(a,b) (a)
6609#endif
6610 int accmode;
6611 if (oflags & O_EXCL) {
6612 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6613 }
6614 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6615 if (oflags & O_APPEND) {
6616 if (accmode == O_WRONLY) {
6617 return MODE_BINARY("a", "ab");
6618 }
6619 if (accmode == O_RDWR) {
6620 return MODE_BINARY("a+", "ab+");
6621 }
6622 }
6623 switch (accmode) {
6624 default:
6625 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6626 case O_RDONLY:
6627 return MODE_BINARY("r", "rb");
6628 case O_WRONLY:
6629 return MODE_BINARY("w", "wb");
6630 case O_RDWR:
6631 if (oflags & O_TRUNC) {
6632 return MODE_BINARY("w+", "wb+");
6633 }
6634 return MODE_BINARY("r+", "rb+");
6635 }
6636}
6637
6638/*
6639 * Convert external/internal encodings to enc/enc2
6640 * NULL => use default encoding
6641 * Qnil => no encoding specified (internal only)
6642 */
6643static void
6644rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6645{
6646 int default_ext = 0;
6647
6648 if (ext == NULL) {
6649 ext = rb_default_external_encoding();
6650 default_ext = 1;
6651 }
6652 if (rb_is_ascii8bit_enc(ext)) {
6653 /* If external is ASCII-8BIT, no transcoding */
6654 intern = NULL;
6655 }
6656 else if (intern == NULL) {
6657 intern = rb_default_internal_encoding();
6658 }
6659 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6660 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6661 /* No internal encoding => use external + no transcoding */
6662 *enc = (default_ext && intern != ext) ? NULL : ext;
6663 *enc2 = NULL;
6664 }
6665 else {
6666 *enc = intern;
6667 *enc2 = ext;
6668 }
6669}
6670
6671static void
6672unsupported_encoding(const char *name, rb_encoding *enc)
6673{
6674 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6675}
6676
6677static void
6678parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6679 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6680{
6681 const char *p;
6682 char encname[ENCODING_MAXNAMELEN+1];
6683 int idx, idx2;
6684 int fmode = fmode_p ? *fmode_p : 0;
6685 rb_encoding *ext_enc, *int_enc;
6686 long len;
6687
6688 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6689
6690 p = strrchr(estr, ':');
6691 len = p ? (p++ - estr) : (long)strlen(estr);
6692 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6693 estr += bom_prefix_len;
6694 len -= bom_prefix_len;
6695 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6696 fmode |= FMODE_SETENC_BY_BOM;
6697 }
6698 else {
6699 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6700 fmode &= ~FMODE_SETENC_BY_BOM;
6701 }
6702 }
6703 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6704 idx = -1;
6705 }
6706 else {
6707 if (p) {
6708 memcpy(encname, estr, len);
6709 encname[len] = '\0';
6710 estr = encname;
6711 }
6712 idx = rb_enc_find_index(estr);
6713 }
6714 if (fmode_p) *fmode_p = fmode;
6715
6716 if (idx >= 0)
6717 ext_enc = rb_enc_from_index(idx);
6718 else {
6719 if (idx != -2)
6720 unsupported_encoding(estr, estr_enc);
6721 ext_enc = NULL;
6722 }
6723
6724 int_enc = NULL;
6725 if (p) {
6726 if (*p == '-' && *(p+1) == '\0') {
6727 /* Special case - "-" => no transcoding */
6728 int_enc = (rb_encoding *)Qnil;
6729 }
6730 else {
6731 idx2 = rb_enc_find_index(p);
6732 if (idx2 < 0)
6733 unsupported_encoding(p, estr_enc);
6734 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6735 int_enc = (rb_encoding *)Qnil;
6736 }
6737 else
6738 int_enc = rb_enc_from_index(idx2);
6739 }
6740 }
6741
6742 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6743}
6744
6745int
6746rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6747{
6748 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6749 int extracted = 0;
6750 rb_encoding *extencoding = NULL;
6751 rb_encoding *intencoding = NULL;
6752
6753 if (!NIL_P(opt)) {
6754 VALUE v;
6755 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6756 if (v != Qnil) encoding = v;
6757 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6758 if (v != Qnil) extenc = v;
6759 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6760 if (!UNDEF_P(v)) intenc = v;
6761 }
6762 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6763 if (!NIL_P(ruby_verbose)) {
6764 int idx = rb_to_encoding_index(encoding);
6765 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6766 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6767 encoding, UNDEF_P(extenc) ? "internal" : "external");
6768 }
6769 encoding = Qnil;
6770 }
6771 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6772 extencoding = rb_to_encoding(extenc);
6773 }
6774 if (!UNDEF_P(intenc)) {
6775 if (NIL_P(intenc)) {
6776 /* internal_encoding: nil => no transcoding */
6777 intencoding = (rb_encoding *)Qnil;
6778 }
6779 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6780 char *p = StringValueCStr(tmp);
6781
6782 if (*p == '-' && *(p+1) == '\0') {
6783 /* Special case - "-" => no transcoding */
6784 intencoding = (rb_encoding *)Qnil;
6785 }
6786 else {
6787 intencoding = rb_to_encoding(intenc);
6788 }
6789 }
6790 else {
6791 intencoding = rb_to_encoding(intenc);
6792 }
6793 if (extencoding == intencoding) {
6794 intencoding = (rb_encoding *)Qnil;
6795 }
6796 }
6797 if (!NIL_P(encoding)) {
6798 extracted = 1;
6799 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6800 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6801 enc_p, enc2_p, fmode_p);
6802 }
6803 else {
6804 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6805 }
6806 }
6807 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6808 extracted = 1;
6809 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6810 }
6811 return extracted;
6812}
6813
6814static void
6815validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6816{
6817 int fmode = *fmode_p;
6818
6819 if ((fmode & FMODE_READABLE) &&
6820 !enc2 &&
6821 !(fmode & FMODE_BINMODE) &&
6822 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6823 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6824
6825 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6826 rb_raise(rb_eArgError, "newline decorator with binary mode");
6827 }
6828 if (!(fmode & FMODE_BINMODE) &&
6829 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6830 fmode |= FMODE_TEXTMODE;
6831 *fmode_p = fmode;
6832 }
6833#if !DEFAULT_TEXTMODE
6834 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6835 fmode &= ~FMODE_TEXTMODE;
6836 *fmode_p = fmode;
6837 }
6838#endif
6839}
6840
6841static void
6842extract_binmode(VALUE opthash, int *fmode)
6843{
6844 if (!NIL_P(opthash)) {
6845 VALUE v;
6846 v = rb_hash_aref(opthash, sym_textmode);
6847 if (!NIL_P(v)) {
6848 if (*fmode & FMODE_TEXTMODE)
6849 rb_raise(rb_eArgError, "textmode specified twice");
6850 if (*fmode & FMODE_BINMODE)
6851 rb_raise(rb_eArgError, "both textmode and binmode specified");
6852 if (RTEST(v))
6853 *fmode |= FMODE_TEXTMODE;
6854 }
6855 v = rb_hash_aref(opthash, sym_binmode);
6856 if (!NIL_P(v)) {
6857 if (*fmode & FMODE_BINMODE)
6858 rb_raise(rb_eArgError, "binmode specified twice");
6859 if (*fmode & FMODE_TEXTMODE)
6860 rb_raise(rb_eArgError, "both textmode and binmode specified");
6861 if (RTEST(v))
6862 *fmode |= FMODE_BINMODE;
6863 }
6864
6865 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6866 rb_raise(rb_eArgError, "both textmode and binmode specified");
6867 }
6868}
6869
6870void
6871rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6872 int *oflags_p, int *fmode_p, struct rb_io_encoding *convconfig_p)
6873{
6874 VALUE vmode;
6875 int oflags, fmode;
6876 rb_encoding *enc, *enc2;
6877 int ecflags;
6878 VALUE ecopts;
6879 int has_enc = 0, has_vmode = 0;
6880 VALUE intmode;
6881
6882 vmode = *vmode_p;
6883
6884 /* Set to defaults */
6885 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6886
6887 vmode_handle:
6888 if (NIL_P(vmode)) {
6889 fmode = FMODE_READABLE;
6890 oflags = O_RDONLY;
6891 }
6892 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6893 vmode = intmode;
6894 oflags = NUM2INT(intmode);
6895 fmode = rb_io_oflags_fmode(oflags);
6896 }
6897 else {
6898 const char *p;
6899
6900 StringValue(vmode);
6901 p = StringValueCStr(vmode);
6902 fmode = rb_io_modestr_fmode(p);
6903 oflags = rb_io_fmode_oflags(fmode);
6904 p = strchr(p, ':');
6905 if (p) {
6906 has_enc = 1;
6907 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6908 }
6909 else {
6910 rb_encoding *e;
6911
6912 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6913 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6914 }
6915 }
6916
6917 if (NIL_P(opthash)) {
6918 ecflags = (fmode & FMODE_READABLE) ?
6919 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6920 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6921#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6922 ecflags |= (fmode & FMODE_WRITABLE) ?
6923 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6924 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6925#endif
6926 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6927 ecopts = Qnil;
6928 if (fmode & FMODE_BINMODE) {
6929#ifdef O_BINARY
6930 oflags |= O_BINARY;
6931#endif
6932 if (!has_enc)
6933 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6934 }
6935#if DEFAULT_TEXTMODE
6936 else if (NIL_P(vmode)) {
6937 fmode |= DEFAULT_TEXTMODE;
6938 }
6939#endif
6940 }
6941 else {
6942 VALUE v;
6943 if (!has_vmode) {
6944 v = rb_hash_aref(opthash, sym_mode);
6945 if (!NIL_P(v)) {
6946 if (!NIL_P(vmode)) {
6947 rb_raise(rb_eArgError, "mode specified twice");
6948 }
6949 has_vmode = 1;
6950 vmode = v;
6951 goto vmode_handle;
6952 }
6953 }
6954 v = rb_hash_aref(opthash, sym_flags);
6955 if (!NIL_P(v)) {
6956 v = rb_to_int(v);
6957 oflags |= NUM2INT(v);
6958 vmode = INT2NUM(oflags);
6959 fmode = rb_io_oflags_fmode(oflags);
6960 }
6961 extract_binmode(opthash, &fmode);
6962 if (fmode & FMODE_BINMODE) {
6963#ifdef O_BINARY
6964 oflags |= O_BINARY;
6965#endif
6966 if (!has_enc)
6967 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6968 }
6969#if DEFAULT_TEXTMODE
6970 else if (NIL_P(vmode)) {
6971 fmode |= DEFAULT_TEXTMODE;
6972 }
6973#endif
6974 v = rb_hash_aref(opthash, sym_perm);
6975 if (!NIL_P(v)) {
6976 if (vperm_p) {
6977 if (!NIL_P(*vperm_p)) {
6978 rb_raise(rb_eArgError, "perm specified twice");
6979 }
6980 *vperm_p = v;
6981 }
6982 else {
6983 /* perm no use, just ignore */
6984 }
6985 }
6986 ecflags = (fmode & FMODE_READABLE) ?
6987 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6988 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6989#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6990 ecflags |= (fmode & FMODE_WRITABLE) ?
6991 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6992 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6993#endif
6994
6995 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6996 if (has_enc) {
6997 rb_raise(rb_eArgError, "encoding specified twice");
6998 }
6999 }
7000 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7001 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7002 }
7003
7004 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7005
7006 *vmode_p = vmode;
7007
7008 *oflags_p = oflags;
7009 *fmode_p = fmode;
7010 convconfig_p->enc = enc;
7011 convconfig_p->enc2 = enc2;
7012 convconfig_p->ecflags = ecflags;
7013 convconfig_p->ecopts = ecopts;
7014}
7015
7016 struct sysopen_struct {
7017 VALUE fname;
7018 int oflags;
7019 mode_t perm;
7020};
7021
7022static void *
7023sysopen_func(void *ptr)
7024{
7025 const struct sysopen_struct *data = ptr;
7026 const char *fname = RSTRING_PTR(data->fname);
7027 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7028}
7029
7030static inline int
7031rb_sysopen_internal(struct sysopen_struct *data)
7032{
7033 int fd;
7034 do {
7035 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7036 } while (fd < 0 && errno == EINTR);
7037 if (0 <= fd)
7038 rb_update_max_fd(fd);
7039 return fd;
7040}
7041
7042static int
7043rb_sysopen(VALUE fname, int oflags, mode_t perm)
7044{
7045 int fd = -1;
7046 struct sysopen_struct data;
7047
7048 data.fname = rb_str_encode_ospath(fname);
7049 StringValueCStr(data.fname);
7050 data.oflags = oflags;
7051 data.perm = perm;
7052
7053 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7054 rb_syserr_fail_path(first_errno, fname);
7055 }
7056 return fd;
7057}
7058
7059static inline FILE *
7060fdopen_internal(int fd, const char *modestr)
7061{
7062 FILE *file;
7063
7064#if defined(__sun)
7065 errno = 0;
7066#endif
7067 file = fdopen(fd, modestr);
7068 if (!file) {
7069#ifdef _WIN32
7070 if (errno == 0) errno = EINVAL;
7071#elif defined(__sun)
7072 if (errno == 0) errno = EMFILE;
7073#endif
7074 }
7075 return file;
7076}
7077
7078FILE *
7079rb_fdopen(int fd, const char *modestr)
7080{
7081 FILE *file = 0;
7082
7083 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7084 rb_syserr_fail(first_errno, 0);
7085 }
7086
7087 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7088#ifdef USE_SETVBUF
7089 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7090 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7091#endif
7092 return file;
7093}
7094
7095static int
7096io_check_tty(rb_io_t *fptr)
7097{
7098 int t = isatty(fptr->fd);
7099 if (t)
7100 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7101 return t;
7102}
7103
7104static VALUE rb_io_internal_encoding(VALUE);
7105static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7106
7107static int
7108io_strip_bom(VALUE io)
7109{
7110 VALUE b1, b2, b3, b4;
7111 rb_io_t *fptr;
7112
7113 GetOpenFile(io, fptr);
7114 if (!(fptr->mode & FMODE_READABLE)) return 0;
7115 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7116 switch (b1) {
7117 case INT2FIX(0xEF):
7118 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7119 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7120 if (b3 == INT2FIX(0xBF)) {
7121 return rb_utf8_encindex();
7122 }
7123 rb_io_ungetbyte(io, b3);
7124 }
7125 rb_io_ungetbyte(io, b2);
7126 break;
7127
7128 case INT2FIX(0xFE):
7129 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7130 if (b2 == INT2FIX(0xFF)) {
7131 return ENCINDEX_UTF_16BE;
7132 }
7133 rb_io_ungetbyte(io, b2);
7134 break;
7135
7136 case INT2FIX(0xFF):
7137 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7138 if (b2 == INT2FIX(0xFE)) {
7139 b3 = rb_io_getbyte(io);
7140 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7141 if (b4 == INT2FIX(0)) {
7142 return ENCINDEX_UTF_32LE;
7143 }
7144 rb_io_ungetbyte(io, b4);
7145 }
7146 rb_io_ungetbyte(io, b3);
7147 return ENCINDEX_UTF_16LE;
7148 }
7149 rb_io_ungetbyte(io, b2);
7150 break;
7151
7152 case INT2FIX(0):
7153 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7154 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7155 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7156 if (b4 == INT2FIX(0xFF)) {
7157 return ENCINDEX_UTF_32BE;
7158 }
7159 rb_io_ungetbyte(io, b4);
7160 }
7161 rb_io_ungetbyte(io, b3);
7162 }
7163 rb_io_ungetbyte(io, b2);
7164 break;
7165 }
7166 rb_io_ungetbyte(io, b1);
7167 return 0;
7168}
7169
7170static rb_encoding *
7171io_set_encoding_by_bom(VALUE io)
7172{
7173 int idx = io_strip_bom(io);
7174 rb_io_t *fptr;
7175 rb_encoding *extenc = NULL;
7176
7177 GetOpenFile(io, fptr);
7178 if (idx) {
7179 extenc = rb_enc_from_index(idx);
7180 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7181 rb_io_internal_encoding(io), Qnil);
7182 }
7183 else {
7184 fptr->encs.enc2 = NULL;
7185 }
7186 return extenc;
7187}
7188
7189static VALUE
7190rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7191 const struct rb_io_encoding *convconfig, mode_t perm)
7192{
7193 VALUE pathv;
7194 rb_io_t *fptr;
7195 struct rb_io_encoding cc;
7196 if (!convconfig) {
7197 /* Set to default encodings */
7198 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7199 cc.ecflags = 0;
7200 cc.ecopts = Qnil;
7201 convconfig = &cc;
7202 }
7203 validate_enc_binmode(&fmode, convconfig->ecflags,
7204 convconfig->enc, convconfig->enc2);
7205
7206 MakeOpenFile(io, fptr);
7207 fptr->mode = fmode;
7208 fptr->encs = *convconfig;
7209 pathv = rb_str_new_frozen(filename);
7210#ifdef O_TMPFILE
7211 if (!(oflags & O_TMPFILE)) {
7212 fptr->pathv = pathv;
7213 }
7214#else
7215 fptr->pathv = pathv;
7216#endif
7217 fptr->fd = rb_sysopen(pathv, oflags, perm);
7218 io_check_tty(fptr);
7219 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7220
7221 return io;
7222}
7223
7224static VALUE
7225rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7226{
7227 int fmode = rb_io_modestr_fmode(modestr);
7228 const char *p = strchr(modestr, ':');
7229 struct rb_io_encoding convconfig;
7230
7231 if (p) {
7232 parse_mode_enc(p+1, rb_usascii_encoding(),
7233 &convconfig.enc, &convconfig.enc2, &fmode);
7234 }
7235 else {
7236 rb_encoding *e;
7237 /* Set to default encodings */
7238
7239 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7240 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7241 }
7242
7243 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7244 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
7245 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
7246#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7247 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7248 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7249 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7250#endif
7251 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7252 convconfig.ecopts = Qnil;
7253
7254 return rb_file_open_generic(io, filename,
7255 rb_io_fmode_oflags(fmode),
7256 fmode,
7257 &convconfig,
7258 0666);
7259}
7260
7261 VALUE
7262rb_file_open_str(VALUE fname, const char *modestr)
7263{
7264 FilePathValue(fname);
7265 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7266}
7267
7268 VALUE
7269rb_file_open(const char *fname, const char *modestr)
7270{
7271 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7272}
7273
7274#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7275 static struct pipe_list {
7276 rb_io_t *fptr;
7277 struct pipe_list *next;
7278} *pipe_list;
7279
7280static void
7281pipe_add_fptr(rb_io_t *fptr)
7282{
7283 struct pipe_list *list;
7284
7285 list = ALLOC(struct pipe_list);
7286 list->fptr = fptr;
7287 list->next = pipe_list;
7288 pipe_list = list;
7289}
7290
7291static void
7292pipe_del_fptr(rb_io_t *fptr)
7293{
7294 struct pipe_list **prev = &pipe_list;
7295 struct pipe_list *tmp;
7296
7297 while ((tmp = *prev) != 0) {
7298 if (tmp->fptr == fptr) {
7299 *prev = tmp->next;
7300 free(tmp);
7301 return;
7302 }
7303 prev = &tmp->next;
7304 }
7305}
7306
7307#if defined (_WIN32) || defined(__CYGWIN__)
7308static void
7309pipe_atexit(void)
7310{
7311 struct pipe_list *list = pipe_list;
7312 struct pipe_list *tmp;
7313
7314 while (list) {
7315 tmp = list->next;
7316 rb_io_fptr_finalize(list->fptr);
7317 list = tmp;
7318 }
7319}
7320#endif
7321
7322static void
7323pipe_finalize(rb_io_t *fptr, int noraise)
7324{
7325#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7326 int status = 0;
7327 if (fptr->stdio_file) {
7328 status = pclose(fptr->stdio_file);
7329 }
7330 fptr->fd = -1;
7331 fptr->stdio_file = 0;
7332 rb_last_status_set(status, fptr->pid);
7333#else
7334 fptr_finalize(fptr, noraise);
7335#endif
7336 pipe_del_fptr(fptr);
7337}
7338#endif
7339
7340static void
7341fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7342{
7343#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7344 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7345
7346 if (old_finalize == orig->finalize) return;
7347#endif
7348
7349 fptr->finalize = orig->finalize;
7350
7351#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7352 if (old_finalize != pipe_finalize) {
7353 struct pipe_list *list;
7354 for (list = pipe_list; list; list = list->next) {
7355 if (list->fptr == fptr) break;
7356 }
7357 if (!list) pipe_add_fptr(fptr);
7358 }
7359 else {
7360 pipe_del_fptr(fptr);
7361 }
7362#endif
7363}
7364
7365void
7366rb_io_synchronized(rb_io_t *fptr)
7367{
7368 rb_io_check_initialized(fptr);
7369 fptr->mode |= FMODE_SYNC;
7370}
7371
7372void
7373rb_io_unbuffered(rb_io_t *fptr)
7374{
7375 rb_io_synchronized(fptr);
7376}
7377
7378int
7379rb_pipe(int *pipes)
7380{
7381 int ret;
7382 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7383 if (ret == 0) {
7384 rb_update_max_fd(pipes[0]);
7385 rb_update_max_fd(pipes[1]);
7386 }
7387 return ret;
7388}
7389
7390#ifdef _WIN32
7391#define HAVE_SPAWNV 1
7392#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7393#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7394#endif
7395
7396#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7397struct popen_arg {
7398 VALUE execarg_obj;
7399 struct rb_execarg *eargp;
7400 int modef;
7401 int pair[2];
7402 int write_pair[2];
7403};
7404#endif
7405
7406#ifdef HAVE_WORKING_FORK
7407# ifndef __EMSCRIPTEN__
7408static void
7409popen_redirect(struct popen_arg *p)
7410{
7411 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7412 close(p->write_pair[1]);
7413 if (p->write_pair[0] != 0) {
7414 dup2(p->write_pair[0], 0);
7415 close(p->write_pair[0]);
7416 }
7417 close(p->pair[0]);
7418 if (p->pair[1] != 1) {
7419 dup2(p->pair[1], 1);
7420 close(p->pair[1]);
7421 }
7422 }
7423 else if (p->modef & FMODE_READABLE) {
7424 close(p->pair[0]);
7425 if (p->pair[1] != 1) {
7426 dup2(p->pair[1], 1);
7427 close(p->pair[1]);
7428 }
7429 }
7430 else {
7431 close(p->pair[1]);
7432 if (p->pair[0] != 0) {
7433 dup2(p->pair[0], 0);
7434 close(p->pair[0]);
7435 }
7436 }
7437}
7438# endif
7439
7440#if defined(__linux__)
7441/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7442 * Since /proc may not be available, linux_get_maxfd is just a hint.
7443 * This function, linux_get_maxfd, must be async-signal-safe.
7444 * I.e. opendir() is not usable.
7445 *
7446 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7447 * However they are easy to re-implement in async-signal-safe manner.
7448 * (Also note that there is missing/memcmp.c.)
7449 */
7450static int
7451linux_get_maxfd(void)
7452{
7453 int fd;
7454 char buf[4096], *p, *np, *e;
7455 ssize_t ss;
7456 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7457 if (fd < 0) return fd;
7458 ss = read(fd, buf, sizeof(buf));
7459 if (ss < 0) goto err;
7460 p = buf;
7461 e = buf + ss;
7462 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7463 (np = memchr(p, '\n', e-p)) != NULL) {
7464 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7465 int fdsize;
7466 p += sizeof("FDSize:")-1;
7467 *np = '\0';
7468 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7469 close(fd);
7470 return fdsize;
7471 }
7472 p = np+1;
7473 }
7474 /* fall through */
7475
7476 err:
7477 close(fd);
7478 return (int)ss;
7479}
7480#endif
7481
7482/* This function should be async-signal-safe. */
7483void
7484 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7485{
7486#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7487 int fd, ret;
7488 int max = (int)max_file_descriptor;
7489# ifdef F_MAXFD
7490 /* F_MAXFD is available since NetBSD 2.0. */
7491 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7492 if (ret != -1)
7493 maxhint = max = ret;
7494# elif defined(__linux__)
7495 ret = linux_get_maxfd();
7496 if (maxhint < ret)
7497 maxhint = ret;
7498 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7499# endif
7500 if (max < maxhint)
7501 max = maxhint;
7502 for (fd = lowfd; fd <= max; fd++) {
7503 if (!NIL_P(noclose_fds) &&
7504 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7505 continue;
7506 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7507 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7508 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7509 }
7510# define CONTIGUOUS_CLOSED_FDS 20
7511 if (ret != -1) {
7512 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7513 max = fd + CONTIGUOUS_CLOSED_FDS;
7514 }
7515 }
7516#endif
7517}
7518
7519# ifndef __EMSCRIPTEN__
7520static int
7521popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7522{
7523 struct popen_arg *p = (struct popen_arg*)pp;
7524
7525 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7526}
7527# endif
7528#endif
7529
7530#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7531static VALUE
7532rb_execarg_fixup_v(VALUE execarg_obj)
7533{
7534 rb_execarg_parent_start(execarg_obj);
7535 return Qnil;
7536}
7537#else
7538char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7539#endif
7540
7541#ifndef __EMSCRIPTEN__
7542static VALUE
7543pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7544 const struct rb_io_encoding *convconfig)
7545{
7546 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7547 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7548 rb_pid_t pid = 0;
7549 rb_io_t *fptr;
7550 VALUE port;
7551 rb_io_t *write_fptr;
7552 VALUE write_port;
7553#if defined(HAVE_WORKING_FORK)
7554 int status;
7555 char errmsg[80] = { '\0' };
7556#endif
7557#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7558 int state;
7559 struct popen_arg arg;
7560#endif
7561 int e = 0;
7562#if defined(HAVE_SPAWNV)
7563# if defined(HAVE_SPAWNVE)
7564# define DO_SPAWN(cmd, args, envp) ((args) ? \
7565 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7566 spawne(P_NOWAIT, (cmd), (envp)))
7567# else
7568# define DO_SPAWN(cmd, args, envp) ((args) ? \
7569 spawnv(P_NOWAIT, (cmd), (args)) : \
7570 spawn(P_NOWAIT, (cmd)))
7571# endif
7572# if !defined(HAVE_WORKING_FORK)
7573 char **args = NULL;
7574# if defined(HAVE_SPAWNVE)
7575 char **envp = NULL;
7576# endif
7577# endif
7578#endif
7579#if !defined(HAVE_WORKING_FORK)
7580 struct rb_execarg sarg, *sargp = &sarg;
7581#endif
7582 FILE *fp = 0;
7583 int fd = -1;
7584 int write_fd = -1;
7585#if !defined(HAVE_WORKING_FORK)
7586 const char *cmd = 0;
7587
7588 if (prog)
7589 cmd = StringValueCStr(prog);
7590#endif
7591
7592#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7593 arg.execarg_obj = execarg_obj;
7594 arg.eargp = eargp;
7595 arg.modef = fmode;
7596 arg.pair[0] = arg.pair[1] = -1;
7597 arg.write_pair[0] = arg.write_pair[1] = -1;
7598# if !defined(HAVE_WORKING_FORK)
7599 if (eargp && !eargp->use_shell) {
7600 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7601 }
7602# endif
7603 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7604 case FMODE_READABLE|FMODE_WRITABLE:
7605 if (rb_pipe(arg.write_pair) < 0)
7606 rb_sys_fail_str(prog);
7607 if (rb_pipe(arg.pair) < 0) {
7608 e = errno;
7609 close(arg.write_pair[0]);
7610 close(arg.write_pair[1]);
7611 rb_syserr_fail_str(e, prog);
7612 }
7613 if (eargp) {
7614 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7615 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7616 }
7617 break;
7618 case FMODE_READABLE:
7619 if (rb_pipe(arg.pair) < 0)
7620 rb_sys_fail_str(prog);
7621 if (eargp)
7622 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7623 break;
7624 case FMODE_WRITABLE:
7625 if (rb_pipe(arg.pair) < 0)
7626 rb_sys_fail_str(prog);
7627 if (eargp)
7628 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7629 break;
7630 default:
7631 rb_sys_fail_str(prog);
7632 }
7633 if (!NIL_P(execarg_obj)) {
7634 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7635 if (state) {
7636 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7637 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7638 if (0 <= arg.pair[0]) close(arg.pair[0]);
7639 if (0 <= arg.pair[1]) close(arg.pair[1]);
7640 rb_execarg_parent_end(execarg_obj);
7641 rb_jump_tag(state);
7642 }
7643
7644# if defined(HAVE_WORKING_FORK)
7645 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7646# else
7647 rb_execarg_run_options(eargp, sargp, NULL, 0);
7648# if defined(HAVE_SPAWNVE)
7649 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7650# endif
7651 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7652 /* exec failed */
7653 switch (e = errno) {
7654 case EAGAIN:
7655# if EWOULDBLOCK != EAGAIN
7656 case EWOULDBLOCK:
7657# endif
7658 rb_thread_sleep(1);
7659 continue;
7660 }
7661 break;
7662 }
7663 if (eargp)
7664 rb_execarg_run_options(sargp, NULL, NULL, 0);
7665# endif
7666 rb_execarg_parent_end(execarg_obj);
7667 }
7668 else {
7669# if defined(HAVE_WORKING_FORK)
7670 pid = rb_call_proc__fork();
7671 if (pid == 0) { /* child */
7672 popen_redirect(&arg);
7673 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7674 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7675 return Qnil;
7676 }
7677# else
7678 rb_notimplement();
7679# endif
7680 }
7681
7682 /* parent */
7683 if (pid < 0) {
7684# if defined(HAVE_WORKING_FORK)
7685 e = errno;
7686# endif
7687 close(arg.pair[0]);
7688 close(arg.pair[1]);
7689 if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) {
7690 close(arg.write_pair[0]);
7691 close(arg.write_pair[1]);
7692 }
7693# if defined(HAVE_WORKING_FORK)
7694 if (errmsg[0])
7695 rb_syserr_fail(e, errmsg);
7696# endif
7697 rb_syserr_fail_str(e, prog);
7698 }
7699 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7700 close(arg.pair[1]);
7701 fd = arg.pair[0];
7702 close(arg.write_pair[0]);
7703 write_fd = arg.write_pair[1];
7704 }
7705 else if (fmode & FMODE_READABLE) {
7706 close(arg.pair[1]);
7707 fd = arg.pair[0];
7708 }
7709 else {
7710 close(arg.pair[0]);
7711 fd = arg.pair[1];
7712 }
7713#else
7714 cmd = rb_execarg_commandline(eargp, &prog);
7715 if (!NIL_P(execarg_obj)) {
7716 rb_execarg_parent_start(execarg_obj);
7717 rb_execarg_run_options(eargp, sargp, NULL, 0);
7718 }
7719 fp = popen(cmd, modestr);
7720 e = errno;
7721 if (eargp) {
7722 rb_execarg_parent_end(execarg_obj);
7723 rb_execarg_run_options(sargp, NULL, NULL, 0);
7724 }
7725 if (!fp) rb_syserr_fail_path(e, prog);
7726 fd = fileno(fp);
7727#endif
7728
7729 port = io_alloc(rb_cIO);
7730 MakeOpenFile(port, fptr);
7731 fptr->fd = fd;
7732 fptr->stdio_file = fp;
7733 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7734 if (convconfig) {
7735 fptr->encs = *convconfig;
7736#if RUBY_CRLF_ENVIRONMENT
7737 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
7738 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7739 }
7740#endif
7741 }
7742 else {
7743 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7744 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7745 }
7746#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7747 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7748 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7749 }
7750#endif
7751 }
7752 fptr->pid = pid;
7753
7754 if (0 <= write_fd) {
7755 write_port = io_alloc(rb_cIO);
7756 MakeOpenFile(write_port, write_fptr);
7757 write_fptr->fd = write_fd;
7758 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7759 fptr->mode &= ~FMODE_WRITABLE;
7760 fptr->tied_io_for_writing = write_port;
7761 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7762 }
7763
7764#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7765 fptr->finalize = pipe_finalize;
7766 pipe_add_fptr(fptr);
7767#endif
7768 return port;
7769}
7770#else
7771static VALUE
7772pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7773 const struct rb_io_encoding *convconfig)
7774{
7775 rb_raise(rb_eNotImpError, "popen() is not available");
7776}
7777#endif
7778
7779static int
7780is_popen_fork(VALUE prog)
7781{
7782 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7783#if !defined(HAVE_WORKING_FORK)
7784 rb_raise(rb_eNotImpError,
7785 "fork() function is unimplemented on this machine");
7786#else
7787 return TRUE;
7788#endif
7789 }
7790 return FALSE;
7791}
7792
7793static VALUE
7794pipe_open_s(VALUE prog, const char *modestr, int fmode,
7795 const struct rb_io_encoding *convconfig)
7796{
7797 int argc = 1;
7798 VALUE *argv = &prog;
7799 VALUE execarg_obj = Qnil;
7800
7801 if (!is_popen_fork(prog))
7802 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7803 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7804}
7805
7806static VALUE
7807pipe_close(VALUE io)
7808{
7809 rb_io_t *fptr = io_close_fptr(io);
7810 if (fptr) {
7811 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7812 }
7813 return Qnil;
7814}
7815
7816static VALUE popen_finish(VALUE port, VALUE klass);
7817
7818/*
7819 * call-seq:
7820 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7821 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7822 *
7823 * Executes the given command +cmd+ as a subprocess
7824 * whose $stdin and $stdout are connected to a new stream +io+.
7825 *
7826 * This method has potential security vulnerabilities if called with untrusted input;
7827 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7828 *
7829 * If no block is given, returns the new stream,
7830 * which depending on given +mode+ may be open for reading, writing, or both.
7831 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7832 *
7833 * If a block is given, the stream is passed to the block
7834 * (again, open for reading, writing, or both);
7835 * when the block exits, the stream is closed,
7836 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7837 *
7838 * Optional argument +mode+ may be any valid \IO mode.
7839 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7840 *
7841 * Required argument +cmd+ determines which of the following occurs:
7842 *
7843 * - The process forks.
7844 * - A specified program runs in a shell.
7845 * - A specified program runs with specified arguments.
7846 * - A specified program runs with specified arguments and a specified +argv0+.
7847 *
7848 * Each of these is detailed below.
7849 *
7850 * The optional hash argument +env+ specifies name/value pairs that are to be added
7851 * to the environment variables for the subprocess:
7852 *
7853 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7854 * pipe.puts 'puts ENV["FOO"]'
7855 * pipe.close_write
7856 * pipe.gets
7857 * end => "bar\n"
7858 *
7859 * Optional keyword arguments +opts+ specify:
7860 *
7861 * - {Open options}[rdoc-ref:IO@Open+Options].
7862 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7863 * - Options for Kernel#spawn.
7864 *
7865 * <b>Forked \Process</b>
7866 *
7867 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7868 * IO.popen('-') do |pipe|
7869 * if pipe
7870 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7871 * else
7872 * $stderr.puts "In child, pid is #{$$}\n"
7873 * end
7874 * end
7875 *
7876 * Output:
7877 *
7878 * In parent, child pid is 26253
7879 * In child, pid is 26253
7880 *
7881 * Note that this is not supported on all platforms.
7882 *
7883 * <b>Shell Subprocess</b>
7884 *
7885 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7886 * the program named +cmd+ is run as a shell command:
7887 *
7888 * IO.popen('uname') do |pipe|
7889 * pipe.readlines
7890 * end
7891 *
7892 * Output:
7893 *
7894 * ["Linux\n"]
7895 *
7896 * Another example:
7897 *
7898 * IO.popen('/bin/sh', 'r+') do |pipe|
7899 * pipe.puts('ls')
7900 * pipe.close_write
7901 * $stderr.puts pipe.readlines.size
7902 * end
7903 *
7904 * Output:
7905 *
7906 * 213
7907 *
7908 * <b>Program Subprocess</b>
7909 *
7910 * When argument +cmd+ is an array of strings,
7911 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7912 *
7913 * IO.popen(['du', '..', '.']) do |pipe|
7914 * $stderr.puts pipe.readlines.size
7915 * end
7916 *
7917 * Output:
7918 *
7919 * 1111
7920 *
7921 * <b>Program Subprocess with <tt>argv0</tt></b>
7922 *
7923 * When argument +cmd+ is an array whose first element is a 2-element string array
7924 * and whose remaining elements (if any) are strings:
7925 *
7926 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7927 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7928 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7929 *
7930 * Example (sets <tt>$0</tt> to 'foo'):
7931 *
7932 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7933 *
7934 * <b>Some Special Examples</b>
7935 *
7936 * # Set IO encoding.
7937 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7938 * euc_jp_string = nkf_io.read
7939 * }
7940 *
7941 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7942 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7943 * ls_result_with_error = io.read
7944 * end
7945 *
7946 * # Use mixture of spawn options and IO options.
7947 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7948 * ls_result_with_error = io.read
7949 * end
7950 *
7951 * f = IO.popen("uname")
7952 * p f.readlines
7953 * f.close
7954 * puts "Parent is #{Process.pid}"
7955 * IO.popen("date") {|f| puts f.gets }
7956 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7957 * p $?
7958 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7959 * f.puts "bar"; f.close_write; puts f.gets
7960 * }
7961 *
7962 * Output (from last section):
7963 *
7964 * ["Linux\n"]
7965 * Parent is 21346
7966 * Thu Jan 15 22:41:19 JST 2009
7967 * 21346 is here, f is #<IO:fd 3>
7968 * 21352 is here, f is nil
7969 * #<Process::Status: pid 21352 exit 0>
7970 * <foo>bar;zot;
7971 *
7972 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7973 *
7974 */
7975
7976static VALUE
7977rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7978{
7979 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7980
7981 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7982 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7983 switch (argc) {
7984 case 2:
7985 pmode = argv[1];
7986 case 1:
7987 pname = argv[0];
7988 break;
7989 default:
7990 {
7991 int ex = !NIL_P(opt);
7992 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7993 }
7994 }
7995 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7996}
7997
7998 VALUE
7999rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8000{
8001 const char *modestr;
8002 VALUE tmp, execarg_obj = Qnil;
8003 int oflags, fmode;
8004 struct rb_io_encoding convconfig;
8005
8006 tmp = rb_check_array_type(pname);
8007 if (!NIL_P(tmp)) {
8008 long len = RARRAY_LEN(tmp);
8009#if SIZEOF_LONG > SIZEOF_INT
8010 if (len > INT_MAX) {
8011 rb_raise(rb_eArgError, "too many arguments");
8012 }
8013#endif
8014 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8015 RB_GC_GUARD(tmp);
8016 }
8017 else {
8018 StringValue(pname);
8019 execarg_obj = Qnil;
8020 if (!is_popen_fork(pname))
8021 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8022 }
8023 if (!NIL_P(execarg_obj)) {
8024 if (!NIL_P(opt))
8025 opt = rb_execarg_extract_options(execarg_obj, opt);
8026 if (!NIL_P(env))
8027 rb_execarg_setenv(execarg_obj, env);
8028 }
8029 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8030 modestr = rb_io_oflags_modestr(oflags);
8031
8032 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8033}
8034
8035static VALUE
8036popen_finish(VALUE port, VALUE klass)
8037{
8038 if (NIL_P(port)) {
8039 /* child */
8040 if (rb_block_given_p()) {
8041 rb_yield(Qnil);
8042 rb_io_flush(rb_ractor_stdout());
8043 rb_io_flush(rb_ractor_stderr());
8044 _exit(0);
8045 }
8046 return Qnil;
8047 }
8048 RBASIC_SET_CLASS(port, klass);
8049 if (rb_block_given_p()) {
8050 return rb_ensure(rb_yield, port, pipe_close, port);
8051 }
8052 return port;
8053}
8054
8055#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8056struct popen_writer_arg {
8057 char *const *argv;
8058 struct popen_arg popen;
8059};
8060
8061static int
8062exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8063{
8064 struct popen_writer_arg *pw = arg;
8065 pw->popen.modef = FMODE_WRITABLE;
8066 popen_redirect(&pw->popen);
8067 execv(pw->argv[0], pw->argv);
8068 strlcpy(errmsg, strerror(errno), buflen);
8069 return -1;
8070}
8071#endif
8072
8073FILE *
8074ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8075{
8076#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8077# ifdef HAVE_WORKING_FORK
8078 struct popen_writer_arg pw;
8079 int *const write_pair = pw.popen.pair;
8080# else
8081 int write_pair[2];
8082# endif
8083
8084 int result = rb_cloexec_pipe(write_pair);
8085 *pid = -1;
8086 if (result == 0) {
8087# ifdef HAVE_WORKING_FORK
8088 pw.argv = argv;
8089 int status;
8090 char errmsg[80] = {'\0'};
8091 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8092# else
8093 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8094 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8095# endif
8096 close(write_pair[0]);
8097 if (*pid < 0) {
8098 close(write_pair[1]);
8099 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8100 }
8101 else {
8102 return fdopen(write_pair[1], "w");
8103 }
8104 }
8105#endif
8106 return NULL;
8107}
8108
8109static VALUE
8110rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8111{
8112 struct rb_io_encoding convconfig;
8113 int oflags, fmode;
8114 mode_t perm;
8115
8116 FilePathValue(fname);
8117
8118 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8119 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8120
8121 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8122
8123 return io;
8124}
8125
8126/*
8127 * Document-method: File::open
8128 *
8129 * call-seq:
8130 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8131 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8132 *
8133 * Creates a new File object, via File.new with the given arguments.
8134 *
8135 * With no block given, returns the File object.
8136 *
8137 * With a block given, calls the block with the File object
8138 * and returns the block's value.
8139 *
8140 */
8141
8142/*
8143 * Document-method: IO::open
8144 *
8145 * call-seq:
8146 * IO.open(fd, mode = 'r', **opts) -> io
8147 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8148 *
8149 * Creates a new \IO object, via IO.new with the given arguments.
8150 *
8151 * With no block given, returns the \IO object.
8152 *
8153 * With a block given, calls the block with the \IO object
8154 * and returns the block's value.
8155 *
8156 */
8157
8158static VALUE
8159rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8160{
8161 VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
8162
8163 if (rb_block_given_p()) {
8164 return rb_ensure(rb_yield, io, io_close, io);
8165 }
8166
8167 return io;
8168}
8169
8170/*
8171 * call-seq:
8172 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8173 *
8174 * Opens the file at the given path with the given mode and permissions;
8175 * returns the integer file descriptor.
8176 *
8177 * If the file is to be readable, it must exist;
8178 * if the file is to be writable and does not exist,
8179 * it is created with the given permissions:
8180 *
8181 * File.write('t.tmp', '') # => 0
8182 * IO.sysopen('t.tmp') # => 8
8183 * IO.sysopen('t.tmp', 'w') # => 9
8184 *
8185 *
8186 */
8187
8188static VALUE
8189rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8190{
8191 VALUE fname, vmode, vperm;
8192 VALUE intmode;
8193 int oflags, fd;
8194 mode_t perm;
8195
8196 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8197 FilePathValue(fname);
8198
8199 if (NIL_P(vmode))
8200 oflags = O_RDONLY;
8201 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8202 oflags = NUM2INT(intmode);
8203 else {
8204 StringValue(vmode);
8205 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8206 }
8207 if (NIL_P(vperm)) perm = 0666;
8208 else perm = NUM2MODET(vperm);
8209
8210 RB_GC_GUARD(fname) = rb_str_new4(fname);
8211 fd = rb_sysopen(fname, oflags, perm);
8212 return INT2NUM(fd);
8213}
8214
8215static VALUE
8216check_pipe_command(VALUE filename_or_command)
8217{
8218 char *s = RSTRING_PTR(filename_or_command);
8219 long l = RSTRING_LEN(filename_or_command);
8220 char *e = s + l;
8221 int chlen;
8222
8223 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8224 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8225 return cmd;
8226 }
8227 return Qnil;
8228}
8229
8230/*
8231 * call-seq:
8232 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8233 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8234 *
8235 * Creates an IO object connected to the given file.
8236 *
8237 * This method has potential security vulnerabilities if called with untrusted input;
8238 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8239 *
8240 * With no block given, file stream is returned:
8241 *
8242 * open('t.txt') # => #<File:t.txt>
8243 *
8244 * With a block given, calls the block with the open file stream,
8245 * then closes the stream:
8246 *
8247 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8248 *
8249 * Output:
8250 *
8251 * #<File:t.txt>
8252 *
8253 * See File.open for details.
8254 *
8255 */
8256
8257static VALUE
8258rb_f_open(int argc, VALUE *argv, VALUE _)
8259{
8260 ID to_open = 0;
8261 int redirect = FALSE;
8262
8263 if (argc >= 1) {
8264 CONST_ID(to_open, "to_open");
8265 if (rb_respond_to(argv[0], to_open)) {
8266 redirect = TRUE;
8267 }
8268 else {
8269 VALUE tmp = argv[0];
8270 FilePathValue(tmp);
8271 if (NIL_P(tmp)) {
8272 redirect = TRUE;
8273 }
8274 else {
8275 VALUE cmd = check_pipe_command(tmp);
8276 if (!NIL_P(cmd)) {
8277 // TODO: when removed in 4.0, update command_injection.rdoc
8278 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8279 argv[0] = cmd;
8280 return rb_io_s_popen(argc, argv, rb_cIO);
8281 }
8282 }
8283 }
8284 }
8285 if (redirect) {
8286 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8287
8288 if (rb_block_given_p()) {
8289 return rb_ensure(rb_yield, io, io_close, io);
8290 }
8291 return io;
8292 }
8293 return rb_io_s_open(argc, argv, rb_cFile);
8294}
8295
8296static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const struct rb_io_encoding *, mode_t);
8297
8298static VALUE
8299rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8300{
8301 int oflags, fmode;
8302 struct rb_io_encoding convconfig;
8303 mode_t perm;
8304
8305 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8306 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8307 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8308}
8309
8310static VALUE
8311rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8312 const struct rb_io_encoding *convconfig, mode_t perm)
8313{
8314 VALUE cmd;
8315 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8316 // TODO: when removed in 4.0, update command_injection.rdoc
8317 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8318 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8319 }
8320 else {
8321 return rb_file_open_generic(io_alloc(klass), filename,
8322 oflags, fmode, convconfig, perm);
8323 }
8324}
8325
8326static VALUE
8327io_reopen(VALUE io, VALUE nfile)
8328{
8329 rb_io_t *fptr, *orig;
8330 int fd, fd2;
8331 rb_off_t pos = 0;
8332
8333 nfile = rb_io_get_io(nfile);
8334 GetOpenFile(io, fptr);
8335 GetOpenFile(nfile, orig);
8336
8337 if (fptr == orig) return io;
8338 if (RUBY_IO_EXTERNAL_P(fptr)) {
8339 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8340 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8341 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8342 rb_raise(rb_eArgError,
8343 "%s can't change access mode from \"%s\" to \"%s\"",
8344 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8345 rb_io_fmode_modestr(orig->mode));
8346 }
8347 }
8348 if (fptr->mode & FMODE_WRITABLE) {
8349 if (io_fflush(fptr) < 0)
8350 rb_sys_fail_on_write(fptr);
8351 }
8352 else {
8353 flush_before_seek(fptr, true);
8354 }
8355 if (orig->mode & FMODE_READABLE) {
8356 pos = io_tell(orig);
8357 }
8358 if (orig->mode & FMODE_WRITABLE) {
8359 if (io_fflush(orig) < 0)
8360 rb_sys_fail_on_write(fptr);
8361 }
8362
8363 /* copy rb_io_t structure */
8364 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8365 fptr->encs = orig->encs;
8366 fptr->pid = orig->pid;
8367 fptr->lineno = orig->lineno;
8368 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8369 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8370 fptr_copy_finalizer(fptr, orig);
8371
8372 fd = fptr->fd;
8373 fd2 = orig->fd;
8374 if (fd != fd2) {
8375 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8376 /* need to keep FILE objects of stdin, stdout and stderr */
8377 if (rb_cloexec_dup2(fd2, fd) < 0)
8378 rb_sys_fail_path(orig->pathv);
8379 rb_update_max_fd(fd);
8380 }
8381 else {
8382 fclose(fptr->stdio_file);
8383 fptr->stdio_file = 0;
8384 fptr->fd = -1;
8385 if (rb_cloexec_dup2(fd2, fd) < 0)
8386 rb_sys_fail_path(orig->pathv);
8387 rb_update_max_fd(fd);
8388 fptr->fd = fd;
8389 }
8390 rb_thread_fd_close(fd);
8391 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8392 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8393 rb_sys_fail_path(fptr->pathv);
8394 }
8395 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8396 rb_sys_fail_path(orig->pathv);
8397 }
8398 }
8399 }
8400
8401 if (fptr->mode & FMODE_BINMODE) {
8402 rb_io_binmode(io);
8403 }
8404
8405 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8406 return io;
8407}
8408
8409#ifdef _WIN32
8410int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8411#else
8412static int
8413rb_freopen(VALUE fname, const char *mode, FILE *fp)
8414{
8415 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8416 RB_GC_GUARD(fname);
8417 return errno;
8418 }
8419 return 0;
8420}
8421#endif
8422
8423/*
8424 * call-seq:
8425 * reopen(other_io) -> self
8426 * reopen(path, mode = 'r', **opts) -> self
8427 *
8428 * Reassociates the stream with another stream,
8429 * which may be of a different class.
8430 * This method may be used to redirect an existing stream
8431 * to a new destination.
8432 *
8433 * With argument +other_io+ given, reassociates with that stream:
8434 *
8435 * # Redirect $stdin from a file.
8436 * f = File.open('t.txt')
8437 * $stdin.reopen(f)
8438 * f.close
8439 *
8440 * # Redirect $stdout to a file.
8441 * f = File.open('t.tmp', 'w')
8442 * $stdout.reopen(f)
8443 * f.close
8444 *
8445 * With argument +path+ given, reassociates with a new stream to that file path:
8446 *
8447 * $stdin.reopen('t.txt')
8448 * $stdout.reopen('t.tmp', 'w')
8449 *
8450 * Optional keyword arguments +opts+ specify:
8451 *
8452 * - {Open Options}[rdoc-ref:IO@Open+Options].
8453 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8454 *
8455 */
8456
8457static VALUE
8458rb_io_reopen(int argc, VALUE *argv, VALUE file)
8459{
8460 VALUE fname, nmode, opt;
8461 int oflags;
8462 rb_io_t *fptr;
8463
8464 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8465 VALUE tmp = rb_io_check_io(fname);
8466 if (!NIL_P(tmp)) {
8467 return io_reopen(file, tmp);
8468 }
8469 }
8470
8471 FilePathValue(fname);
8472 rb_io_taint_check(file);
8473 fptr = RFILE(file)->fptr;
8474 if (!fptr) {
8475 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8476 }
8477
8478 if (!NIL_P(nmode) || !NIL_P(opt)) {
8479 int fmode;
8480 struct rb_io_encoding convconfig;
8481
8482 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8483 if (RUBY_IO_EXTERNAL_P(fptr) &&
8484 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8485 (fptr->mode & FMODE_READWRITE)) {
8486 rb_raise(rb_eArgError,
8487 "%s can't change access mode from \"%s\" to \"%s\"",
8488 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8489 rb_io_fmode_modestr(fmode));
8490 }
8491 fptr->mode = fmode;
8492 fptr->encs = convconfig;
8493 }
8494 else {
8495 oflags = rb_io_fmode_oflags(fptr->mode);
8496 }
8497
8498 fptr->pathv = fname;
8499 if (fptr->fd < 0) {
8500 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8501 fptr->stdio_file = 0;
8502 return file;
8503 }
8504
8505 if (fptr->mode & FMODE_WRITABLE) {
8506 if (io_fflush(fptr) < 0)
8507 rb_sys_fail_on_write(fptr);
8508 }
8509 fptr->rbuf.off = fptr->rbuf.len = 0;
8510
8511 if (fptr->stdio_file) {
8512 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8513 rb_io_oflags_modestr(oflags),
8514 fptr->stdio_file);
8515 if (e) rb_syserr_fail_path(e, fptr->pathv);
8516 fptr->fd = fileno(fptr->stdio_file);
8517 rb_fd_fix_cloexec(fptr->fd);
8518#ifdef USE_SETVBUF
8519 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8520 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8521#endif
8522 if (fptr->stdio_file == stderr) {
8523 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8524 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8525 }
8526 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8527 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8528 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8529 }
8530 }
8531 else {
8532 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8533 int err = 0;
8534 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8535 err = errno;
8536 (void)close(tmpfd);
8537 if (err) {
8538 rb_syserr_fail_path(err, fptr->pathv);
8539 }
8540 }
8541
8542 return file;
8543}
8544
8545/* :nodoc: */
8546static VALUE
8547rb_io_init_copy(VALUE dest, VALUE io)
8548{
8549 rb_io_t *fptr, *orig;
8550 int fd;
8551 VALUE write_io;
8552 rb_off_t pos;
8553
8554 io = rb_io_get_io(io);
8555 if (!OBJ_INIT_COPY(dest, io)) return dest;
8556 GetOpenFile(io, orig);
8557 MakeOpenFile(dest, fptr);
8558
8559 rb_io_flush(io);
8560
8561 /* copy rb_io_t structure */
8562 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8563 fptr->encs = orig->encs;
8564 fptr->pid = orig->pid;
8565 fptr->lineno = orig->lineno;
8566 fptr->timeout = orig->timeout;
8567 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8568 fptr_copy_finalizer(fptr, orig);
8569
8570 fd = ruby_dup(orig->fd);
8571 fptr->fd = fd;
8572 pos = io_tell(orig);
8573 if (0 <= pos)
8574 io_seek(fptr, pos, SEEK_SET);
8575 if (fptr->mode & FMODE_BINMODE) {
8576 rb_io_binmode(dest);
8577 }
8578
8579 write_io = GetWriteIO(io);
8580 if (io != write_io) {
8581 write_io = rb_obj_dup(write_io);
8582 fptr->tied_io_for_writing = write_io;
8583 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8584 }
8585
8586 return dest;
8587}
8588
8589/*
8590 * call-seq:
8591 * printf(format_string, *objects) -> nil
8592 *
8593 * Formats and writes +objects+ to the stream.
8594 *
8595 * For details on +format_string+, see
8596 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8597 *
8598 */
8599
8600 VALUE
8601rb_io_printf(int argc, const VALUE *argv, VALUE out)
8602{
8603 rb_io_write(out, rb_f_sprintf(argc, argv));
8604 return Qnil;
8605}
8606
8607/*
8608 * call-seq:
8609 * printf(format_string, *objects) -> nil
8610 * printf(io, format_string, *objects) -> nil
8611 *
8612 * Equivalent to:
8613 *
8614 * io.write(sprintf(format_string, *objects))
8615 *
8616 * For details on +format_string+, see
8617 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8618 *
8619 * With the single argument +format_string+, formats +objects+ into the string,
8620 * then writes the formatted string to $stdout:
8621 *
8622 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8623 *
8624 * Output (on $stdout):
8625 *
8626 * 0024 24 24.00#
8627 *
8628 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8629 * then writes the formatted string to +io+:
8630 *
8631 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8632 *
8633 * Output (on $stderr):
8634 *
8635 * 0024 24 24.00# => nil
8636 *
8637 * With no arguments, does nothing.
8638 *
8639 */
8640
8641static VALUE
8642rb_f_printf(int argc, VALUE *argv, VALUE _)
8643{
8644 VALUE out;
8645
8646 if (argc == 0) return Qnil;
8647 if (RB_TYPE_P(argv[0], T_STRING)) {
8648 out = rb_ractor_stdout();
8649 }
8650 else {
8651 out = argv[0];
8652 argv++;
8653 argc--;
8654 }
8655 rb_io_write(out, rb_f_sprintf(argc, argv));
8656
8657 return Qnil;
8658}
8659
8660static void
8661deprecated_str_setter(VALUE val, ID id, VALUE *var)
8662{
8663 rb_str_setter(val, id, &val);
8664 if (!NIL_P(val)) {
8665 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8666 }
8667 *var = val;
8668}
8669
8670/*
8671 * call-seq:
8672 * print(*objects) -> nil
8673 *
8674 * Writes the given objects to the stream; returns +nil+.
8675 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8676 * (<tt>$\</tt>), if it is not +nil+.
8677 * See {Line IO}[rdoc-ref:IO@Line+IO].
8678 *
8679 * With argument +objects+ given, for each object:
8680 *
8681 * - Converts via its method +to_s+ if not a string.
8682 * - Writes to the stream.
8683 * - If not the last object, writes the output field separator
8684 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8685 *
8686 * With default separators:
8687 *
8688 * f = File.open('t.tmp', 'w+')
8689 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8690 * p $OUTPUT_RECORD_SEPARATOR
8691 * p $OUTPUT_FIELD_SEPARATOR
8692 * f.print(*objects)
8693 * f.rewind
8694 * p f.read
8695 * f.close
8696 *
8697 * Output:
8698 *
8699 * nil
8700 * nil
8701 * "00.00/10+0izerozero"
8702 *
8703 * With specified separators:
8704 *
8705 * $\ = "\n"
8706 * $, = ','
8707 * f.rewind
8708 * f.print(*objects)
8709 * f.rewind
8710 * p f.read
8711 *
8712 * Output:
8713 *
8714 * "0,0.0,0/1,0+0i,zero,zero\n"
8715 *
8716 * With no argument given, writes the content of <tt>$_</tt>
8717 * (which is usually the most recent user input):
8718 *
8719 * f = File.open('t.tmp', 'w+')
8720 * gets # Sets $_ to the most recent user input.
8721 * f.print
8722 * f.close
8723 *
8724 */
8725
8726 VALUE
8727rb_io_print(int argc, const VALUE *argv, VALUE out)
8728{
8729 int i;
8730 VALUE line;
8731
8732 /* if no argument given, print `$_' */
8733 if (argc == 0) {
8734 argc = 1;
8735 line = rb_lastline_get();
8736 argv = &line;
8737 }
8738 if (argc > 1 && !NIL_P(rb_output_fs)) {
8739 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8740 }
8741 for (i=0; i<argc; i++) {
8742 if (!NIL_P(rb_output_fs) && i>0) {
8743 rb_io_write(out, rb_output_fs);
8744 }
8745 rb_io_write(out, argv[i]);
8746 }
8747 if (argc > 0 && !NIL_P(rb_output_rs)) {
8748 rb_io_write(out, rb_output_rs);
8749 }
8750
8751 return Qnil;
8752}
8753
8754/*
8755 * call-seq:
8756 * print(*objects) -> nil
8757 *
8758 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8759 * this method is the straightforward way to write to <tt>$stdout</tt>.
8760 *
8761 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8762 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8763 * <tt>$\</tt>), if it is not +nil+.
8764 *
8765 * With argument +objects+ given, for each object:
8766 *
8767 * - Converts via its method +to_s+ if not a string.
8768 * - Writes to <tt>stdout</tt>.
8769 * - If not the last object, writes the output field separator
8770 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8771 *
8772 * With default separators:
8773 *
8774 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8775 * $OUTPUT_RECORD_SEPARATOR
8776 * $OUTPUT_FIELD_SEPARATOR
8777 * print(*objects)
8778 *
8779 * Output:
8780 *
8781 * nil
8782 * nil
8783 * 00.00/10+0izerozero
8784 *
8785 * With specified separators:
8786 *
8787 * $OUTPUT_RECORD_SEPARATOR = "\n"
8788 * $OUTPUT_FIELD_SEPARATOR = ','
8789 * print(*objects)
8790 *
8791 * Output:
8792 *
8793 * 0,0.0,0/1,0+0i,zero,zero
8794 *
8795 * With no argument given, writes the content of <tt>$_</tt>
8796 * (which is usually the most recent user input):
8797 *
8798 * gets # Sets $_ to the most recent user input.
8799 * print # Prints $_.
8800 *
8801 */
8802
8803static VALUE
8804rb_f_print(int argc, const VALUE *argv, VALUE _)
8805{
8806 rb_io_print(argc, argv, rb_ractor_stdout());
8807 return Qnil;
8808}
8809
8810/*
8811 * call-seq:
8812 * putc(object) -> object
8813 *
8814 * Writes a character to the stream.
8815 * See {Character IO}[rdoc-ref:IO@Character+IO].
8816 *
8817 * If +object+ is numeric, converts to integer if necessary,
8818 * then writes the character whose code is the
8819 * least significant byte;
8820 * if +object+ is a string, writes the first character:
8821 *
8822 * $stdout.putc "A"
8823 * $stdout.putc 65
8824 *
8825 * Output:
8826 *
8827 * AA
8828 *
8829 */
8830
8831static VALUE
8832rb_io_putc(VALUE io, VALUE ch)
8833{
8834 VALUE str;
8835 if (RB_TYPE_P(ch, T_STRING)) {
8836 str = rb_str_substr(ch, 0, 1);
8837 }
8838 else {
8839 char c = NUM2CHR(ch);
8840 str = rb_str_new(&c, 1);
8841 }
8842 rb_io_write(io, str);
8843 return ch;
8844}
8845
8846#define forward(obj, id, argc, argv) \
8847 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8848#define forward_public(obj, id, argc, argv) \
8849 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8850#define forward_current(id, argc, argv) \
8851 forward_public(ARGF.current_file, id, argc, argv)
8852
8853/*
8854 * call-seq:
8855 * putc(int) -> int
8856 *
8857 * Equivalent to:
8858 *
8859 * $stdout.putc(int)
8860 *
8861 * See IO#putc for important information regarding multi-byte characters.
8862 *
8863 */
8864
8865static VALUE
8866rb_f_putc(VALUE recv, VALUE ch)
8867{
8868 VALUE r_stdout = rb_ractor_stdout();
8869 if (recv == r_stdout) {
8870 return rb_io_putc(recv, ch);
8871 }
8872 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8873}
8874
8875
8876int
8877rb_str_end_with_asciichar(VALUE str, int c)
8878{
8879 long len = RSTRING_LEN(str);
8880 const char *ptr = RSTRING_PTR(str);
8881 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8882 int n;
8883
8884 if (len == 0) return 0;
8885 if ((n = rb_enc_mbminlen(enc)) == 1) {
8886 return ptr[len - 1] == c;
8887 }
8888 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8889}
8890
8891static VALUE
8892io_puts_ary(VALUE ary, VALUE out, int recur)
8893{
8894 VALUE tmp;
8895 long i;
8896
8897 if (recur) {
8898 tmp = rb_str_new2("[...]");
8899 rb_io_puts(1, &tmp, out);
8900 return Qtrue;
8901 }
8902 ary = rb_check_array_type(ary);
8903 if (NIL_P(ary)) return Qfalse;
8904 for (i=0; i<RARRAY_LEN(ary); i++) {
8905 tmp = RARRAY_AREF(ary, i);
8906 rb_io_puts(1, &tmp, out);
8907 }
8908 return Qtrue;
8909}
8910
8911/*
8912 * call-seq:
8913 * puts(*objects) -> nil
8914 *
8915 * Writes the given +objects+ to the stream, which must be open for writing;
8916 * returns +nil+.\
8917 * Writes a newline after each that does not already end with a newline sequence.
8918 * If called without arguments, writes a newline.
8919 * See {Line IO}[rdoc-ref:IO@Line+IO].
8920 *
8921 * Note that each added newline is the character <tt>"\n"<//tt>,
8922 * not the output record separator (<tt>$\</tt>).
8923 *
8924 * Treatment for each object:
8925 *
8926 * - String: writes the string.
8927 * - Neither string nor array: writes <tt>object.to_s</tt>.
8928 * - Array: writes each element of the array; arrays may be nested.
8929 *
8930 * To keep these examples brief, we define this helper method:
8931 *
8932 * def show(*objects)
8933 * # Puts objects to file.
8934 * f = File.new('t.tmp', 'w+')
8935 * f.puts(objects)
8936 * # Return file content.
8937 * f.rewind
8938 * p f.read
8939 * f.close
8940 * end
8941 *
8942 * # Strings without newlines.
8943 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8944 * # Strings, some with newlines.
8945 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8946 *
8947 * # Neither strings nor arrays:
8948 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8949 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8950 *
8951 * # Array of strings.
8952 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8953 * # Nested arrays.
8954 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8955 *
8956 */
8957
8958 VALUE
8959rb_io_puts(int argc, const VALUE *argv, VALUE out)
8960{
8961 VALUE line, args[2];
8962
8963 /* if no argument given, print newline. */
8964 if (argc == 0) {
8965 rb_io_write(out, rb_default_rs);
8966 return Qnil;
8967 }
8968 for (int i = 0; i < argc; i++) {
8969 // Convert the argument to a string:
8970 if (RB_TYPE_P(argv[i], T_STRING)) {
8971 line = argv[i];
8972 }
8973 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8974 continue;
8975 }
8976 else {
8977 line = rb_obj_as_string(argv[i]);
8978 }
8979
8980 // Write the line:
8981 int n = 0;
8982 if (RSTRING_LEN(line) == 0) {
8983 args[n++] = rb_default_rs;
8984 }
8985 else {
8986 args[n++] = line;
8987 if (!rb_str_end_with_asciichar(line, '\n')) {
8988 args[n++] = rb_default_rs;
8989 }
8990 }
8991
8992 rb_io_writev(out, n, args);
8993 }
8994
8995 return Qnil;
8996}
8997
8998/*
8999 * call-seq:
9000 * puts(*objects) -> nil
9001 *
9002 * Equivalent to
9003 *
9004 * $stdout.puts(objects)
9005 */
9006
9007static VALUE
9008rb_f_puts(int argc, VALUE *argv, VALUE recv)
9009{
9010 VALUE r_stdout = rb_ractor_stdout();
9011 if (recv == r_stdout) {
9012 return rb_io_puts(argc, argv, recv);
9013 }
9014 return forward(r_stdout, rb_intern("puts"), argc, argv);
9015}
9016
9017static VALUE
9018rb_p_write(VALUE str)
9019{
9020 VALUE args[2];
9021 args[0] = str;
9022 args[1] = rb_default_rs;
9023 VALUE r_stdout = rb_ractor_stdout();
9024 if (RB_TYPE_P(r_stdout, T_FILE) &&
9025 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9026 io_writev(2, args, r_stdout);
9027 }
9028 else {
9029 rb_io_writev(r_stdout, 2, args);
9030 }
9031 return Qnil;
9032}
9033
9034void
9035rb_p(VALUE obj) /* for debug print within C code */
9036{
9037 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9038}
9039
9040static VALUE
9041rb_p_result(int argc, const VALUE *argv)
9042{
9043 VALUE ret = Qnil;
9044
9045 if (argc == 1) {
9046 ret = argv[0];
9047 }
9048 else if (argc > 1) {
9049 ret = rb_ary_new4(argc, argv);
9050 }
9051 VALUE r_stdout = rb_ractor_stdout();
9052 if (RB_TYPE_P(r_stdout, T_FILE)) {
9053 rb_uninterruptible(rb_io_flush, r_stdout);
9054 }
9055 return ret;
9056}
9057
9058/*
9059 * call-seq:
9060 * p(object) -> obj
9061 * p(*objects) -> array of objects
9062 * p -> nil
9063 *
9064 * For each object +obj+, executes:
9065 *
9066 * $stdout.write(obj.inspect, "\n")
9067 *
9068 * With one object given, returns the object;
9069 * with multiple objects given, returns an array containing the objects;
9070 * with no object given, returns +nil+.
9071 *
9072 * Examples:
9073 *
9074 * r = Range.new(0, 4)
9075 * p r # => 0..4
9076 * p [r, r, r] # => [0..4, 0..4, 0..4]
9077 * p # => nil
9078 *
9079 * Output:
9080 *
9081 * 0..4
9082 * [0..4, 0..4, 0..4]
9083 *
9084 * Kernel#p is designed for debugging purposes.
9085 * Ruby implementations may define Kernel#p to be uninterruptible
9086 * in whole or in part.
9087 * On CRuby, Kernel#p's writing of data is uninterruptible.
9088 */
9089
9090static VALUE
9091rb_f_p(int argc, VALUE *argv, VALUE self)
9092{
9093 int i;
9094 for (i=0; i<argc; i++) {
9095 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9096 rb_uninterruptible(rb_p_write, inspected);
9097 }
9098 return rb_p_result(argc, argv);
9099}
9100
9101/*
9102 * call-seq:
9103 * display(port = $>) -> nil
9104 *
9105 * Writes +self+ on the given port:
9106 *
9107 * 1.display
9108 * "cat".display
9109 * [ 4, 5, 6 ].display
9110 * puts
9111 *
9112 * Output:
9113 *
9114 * 1cat[4, 5, 6]
9115 *
9116 */
9117
9118static VALUE
9119rb_obj_display(int argc, VALUE *argv, VALUE self)
9120{
9121 VALUE out;
9122
9123 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9124 rb_io_write(out, self);
9125
9126 return Qnil;
9127}
9128
9129static int
9130rb_stderr_to_original_p(VALUE err)
9131{
9132 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9133}
9134
9135void
9136rb_write_error2(const char *mesg, long len)
9137{
9138 VALUE out = rb_ractor_stderr();
9139 if (rb_stderr_to_original_p(out)) {
9140#ifdef _WIN32
9141 if (isatty(fileno(stderr))) {
9142 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9143 }
9144#endif
9145 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9146 /* failed to write to stderr, what can we do? */
9147 return;
9148 }
9149 }
9150 else {
9151 rb_io_write(out, rb_str_new(mesg, len));
9152 }
9153}
9154
9155void
9156rb_write_error(const char *mesg)
9157{
9158 rb_write_error2(mesg, strlen(mesg));
9159}
9160
9161void
9162rb_write_error_str(VALUE mesg)
9163{
9164 VALUE out = rb_ractor_stderr();
9165 /* a stopgap measure for the time being */
9166 if (rb_stderr_to_original_p(out)) {
9167 size_t len = (size_t)RSTRING_LEN(mesg);
9168#ifdef _WIN32
9169 if (isatty(fileno(stderr))) {
9170 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9171 }
9172#endif
9173 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9174 RB_GC_GUARD(mesg);
9175 return;
9176 }
9177 }
9178 else {
9179 /* may unlock GVL, and */
9180 rb_io_write(out, mesg);
9181 }
9182}
9183
9184int
9185rb_stderr_tty_p(void)
9186{
9187 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9188 return isatty(fileno(stderr));
9189 return 0;
9190}
9191
9192static void
9193must_respond_to(ID mid, VALUE val, ID id)
9194{
9195 if (!rb_respond_to(val, mid)) {
9196 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9197 rb_id2str(id), rb_id2str(mid),
9198 rb_obj_class(val));
9199 }
9200}
9201
9202static void
9203stdin_setter(VALUE val, ID id, VALUE *ptr)
9204{
9205 rb_ractor_stdin_set(val);
9206}
9207
9208static VALUE
9209stdin_getter(ID id, VALUE *ptr)
9210{
9211 return rb_ractor_stdin();
9212}
9213
9214static void
9215stdout_setter(VALUE val, ID id, VALUE *ptr)
9216{
9217 must_respond_to(id_write, val, id);
9218 rb_ractor_stdout_set(val);
9219}
9220
9221static VALUE
9222stdout_getter(ID id, VALUE *ptr)
9223{
9224 return rb_ractor_stdout();
9225}
9226
9227static void
9228stderr_setter(VALUE val, ID id, VALUE *ptr)
9229{
9230 must_respond_to(id_write, val, id);
9231 rb_ractor_stderr_set(val);
9232}
9233
9234static VALUE
9235stderr_getter(ID id, VALUE *ptr)
9236{
9237 return rb_ractor_stderr();
9238}
9239
9240static VALUE
9241allocate_and_open_new_file(VALUE klass)
9242{
9243 VALUE self = io_alloc(klass);
9244 rb_io_make_open_file(self);
9245 return self;
9246}
9247
9248 VALUE
9249rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9250{
9251 int state;
9252 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9253 if (state) {
9254 /* if we raised an exception allocating an IO object, but the caller
9255 intended to transfer ownership of this FD to us, close the fd before
9256 raising the exception. Otherwise, we would leak a FD - the caller
9257 expects GC to close the file, but we never got around to assigning
9258 it to a rb_io. */
9259 if (!(mode & FMODE_EXTERNAL)) {
9260 maygvl_close(descriptor, 0);
9261 }
9262 rb_jump_tag(state);
9263 }
9264
9265
9266 rb_io_t *io = RFILE(self)->fptr;
9267 io->self = self;
9268 io->fd = descriptor;
9269 io->mode = mode;
9270
9271 /* At this point, Ruby fully owns the descriptor, and will close it when
9272 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9273 in the rest of this method. */
9274
9275 if (NIL_P(path)) {
9276 io->pathv = Qnil;
9277 }
9278 else {
9279 StringValue(path);
9280 io->pathv = rb_str_new_frozen(path);
9281 }
9282
9283 io->timeout = timeout;
9284
9285 if (encoding) {
9286 io->encs = *encoding;
9287 }
9288
9289 rb_update_max_fd(descriptor);
9290
9291 return self;
9292}
9293
9294static VALUE
9295prep_io(int fd, int fmode, VALUE klass, const char *path)
9296{
9297 VALUE path_value = Qnil;
9298 rb_encoding *e;
9299 struct rb_io_encoding convconfig;
9300
9301 if (path) {
9302 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9303 }
9304
9305 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9306 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9307 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9308 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
9309 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
9310#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9311 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9312 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9313 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9314#endif
9315 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9316 convconfig.ecopts = Qnil;
9317
9318 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9319 rb_io_t*io = RFILE(self)->fptr;
9320
9321 if (!io_check_tty(io)) {
9322#ifdef __CYGWIN__
9323 io->mode |= FMODE_BINMODE;
9324 setmode(fd, O_BINARY);
9325#endif
9326 }
9327
9328 return self;
9329}
9330
9331 VALUE
9332rb_io_fdopen(int fd, int oflags, const char *path)
9333{
9334 VALUE klass = rb_cIO;
9335
9336 if (path && strcmp(path, "-")) klass = rb_cFile;
9337 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9338}
9339
9340static VALUE
9341prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9342{
9343 rb_io_t *fptr;
9344 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9345
9346 GetOpenFile(io, fptr);
9347 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
9348#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9349 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9350 if (fmode & FMODE_READABLE) {
9351 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
9352 }
9353#endif
9354 fptr->stdio_file = f;
9355
9356 return io;
9357}
9358
9359 VALUE
9360rb_io_prep_stdin(void)
9361{
9362 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9363}
9364
9365 VALUE
9366rb_io_prep_stdout(void)
9367{
9368 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9369}
9370
9371 VALUE
9372rb_io_prep_stderr(void)
9373{
9374 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9375}
9376
9377FILE *
9378rb_io_stdio_file(rb_io_t *fptr)
9379{
9380 if (!fptr->stdio_file) {
9381 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9382 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9383 }
9384 return fptr->stdio_file;
9385}
9386
9387static inline void
9388rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9389{
9390 buf->ptr = NULL;
9391 buf->off = 0;
9392 buf->len = 0;
9393 buf->capa = 0;
9394}
9395
9396static inline rb_io_t *
9397rb_io_fptr_new(void)
9398{
9399 rb_io_t *fp = ALLOC(rb_io_t);
9400 fp->self = Qnil;
9401 fp->fd = -1;
9402 fp->stdio_file = NULL;
9403 fp->mode = 0;
9404 fp->pid = 0;
9405 fp->lineno = 0;
9406 fp->pathv = Qnil;
9407 fp->finalize = 0;
9408 rb_io_buffer_init(&fp->wbuf);
9409 rb_io_buffer_init(&fp->rbuf);
9410 rb_io_buffer_init(&fp->cbuf);
9411 fp->readconv = NULL;
9412 fp->writeconv = NULL;
9413 fp->writeconv_asciicompat = Qnil;
9414 fp->writeconv_pre_ecflags = 0;
9415 fp->writeconv_pre_ecopts = Qnil;
9416 fp->writeconv_initialized = 0;
9417 fp->tied_io_for_writing = 0;
9418 fp->encs.enc = NULL;
9419 fp->encs.enc2 = NULL;
9420 fp->encs.ecflags = 0;
9421 fp->encs.ecopts = Qnil;
9422 fp->write_lock = Qnil;
9423 fp->timeout = Qnil;
9424 return fp;
9425}
9426
9427rb_io_t *
9428rb_io_make_open_file(VALUE obj)
9429{
9430 rb_io_t *fp = 0;
9431
9432 Check_Type(obj, T_FILE);
9433 if (RFILE(obj)->fptr) {
9434 rb_io_close(obj);
9435 rb_io_fptr_finalize(RFILE(obj)->fptr);
9436 RFILE(obj)->fptr = 0;
9437 }
9438 fp = rb_io_fptr_new();
9439 fp->self = obj;
9440 RFILE(obj)->fptr = fp;
9441 return fp;
9442}
9443
9444static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9445
9446/*
9447 * call-seq:
9448 * IO.new(fd, mode = 'r', **opts) -> io
9449 *
9450 * Creates and returns a new \IO object (file stream) from a file descriptor.
9451 *
9452 * \IO.new may be useful for interaction with low-level libraries.
9453 * For higher-level interactions, it may be simpler to create
9454 * the file stream using File.open.
9455 *
9456 * Argument +fd+ must be a valid file descriptor (integer):
9457 *
9458 * path = 't.tmp'
9459 * fd = IO.sysopen(path) # => 3
9460 * IO.new(fd) # => #<IO:fd 3>
9461 *
9462 * The new \IO object does not inherit encoding
9463 * (because the integer file descriptor does not have an encoding):
9464 *
9465 * fd = IO.sysopen('t.rus', 'rb')
9466 * io = IO.new(fd)
9467 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9468 *
9469 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9470 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9471 *
9472 * IO.new(fd, 'w') # => #<IO:fd 3>
9473 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9474 *
9475 * Optional keyword arguments +opts+ specify:
9476 *
9477 * - {Open Options}[rdoc-ref:IO@Open+Options].
9478 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9479 *
9480 * Examples:
9481 *
9482 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9483 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9484 *
9485 */
9486
9487static VALUE
9488rb_io_initialize(int argc, VALUE *argv, VALUE io)
9489{
9490 VALUE fnum, vmode;
9491 VALUE opt;
9492
9493 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9494 return io_initialize(io, fnum, vmode, opt);
9495}
9496
9497static VALUE
9498io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9499{
9500 rb_io_t *fp;
9501 int fd, fmode, oflags = O_RDONLY;
9502 struct rb_io_encoding convconfig;
9503#if defined(HAVE_FCNTL) && defined(F_GETFL)
9504 int ofmode;
9505#else
9506 struct stat st;
9507#endif
9508
9509 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9510
9511 fd = NUM2INT(fnum);
9512 if (rb_reserved_fd_p(fd)) {
9513 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9514 }
9515#if defined(HAVE_FCNTL) && defined(F_GETFL)
9516 oflags = fcntl(fd, F_GETFL);
9517 if (oflags == -1) rb_sys_fail(0);
9518#else
9519 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9520#endif
9521 rb_update_max_fd(fd);
9522#if defined(HAVE_FCNTL) && defined(F_GETFL)
9523 ofmode = rb_io_oflags_fmode(oflags);
9524 if (NIL_P(vmode)) {
9525 fmode = ofmode;
9526 }
9527 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9528 VALUE error = INT2FIX(EINVAL);
9529 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
9530 }
9531#endif
9532 VALUE path = Qnil;
9533
9534 if (!NIL_P(opt)) {
9535 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9536 fmode |= FMODE_EXTERNAL;
9537 }
9538
9539 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9540 if (!NIL_P(path)) {
9541 StringValue(path);
9542 path = rb_str_new_frozen(path);
9543 }
9544 }
9545
9546 MakeOpenFile(io, fp);
9547 fp->self = io;
9548 fp->fd = fd;
9549 fp->mode = fmode;
9550 fp->encs = convconfig;
9551 fp->pathv = path;
9552 fp->timeout = Qnil;
9553 clear_codeconv(fp);
9554 io_check_tty(fp);
9555 if (fileno(stdin) == fd)
9556 fp->stdio_file = stdin;
9557 else if (fileno(stdout) == fd)
9558 fp->stdio_file = stdout;
9559 else if (fileno(stderr) == fd)
9560 fp->stdio_file = stderr;
9561
9562 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9563 return io;
9564}
9565
9566/*
9567 * call-seq:
9568 * set_encoding_by_bom -> encoding or nil
9569 *
9570 * If the stream begins with a BOM
9571 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9572 * consumes the BOM and sets the external encoding accordingly;
9573 * returns the result encoding if found, or +nil+ otherwise:
9574 *
9575 * File.write('t.tmp', "\u{FEFF}abc")
9576 * io = File.open('t.tmp', 'rb')
9577 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9578 * io.close
9579 *
9580 * File.write('t.tmp', 'abc')
9581 * io = File.open('t.tmp', 'rb')
9582 * io.set_encoding_by_bom # => nil
9583 * io.close
9584 *
9585 * Raises an exception if the stream is not binmode
9586 * or its encoding has already been set.
9587 *
9588 */
9589
9590static VALUE
9591rb_io_set_encoding_by_bom(VALUE io)
9592{
9593 rb_io_t *fptr;
9594
9595 GetOpenFile(io, fptr);
9596 if (!(fptr->mode & FMODE_BINMODE)) {
9597 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9598 }
9599 if (fptr->encs.enc2) {
9600 rb_raise(rb_eArgError, "encoding conversion is set");
9601 }
9602 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9603 rb_raise(rb_eArgError, "encoding is set to %s already",
9604 rb_enc_name(fptr->encs.enc));
9605 }
9606 if (!io_set_encoding_by_bom(io)) return Qnil;
9607 return rb_enc_from_encoding(fptr->encs.enc);
9608}
9609
9610/*
9611 * call-seq:
9612 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9613 *
9614 * Opens the file at the given +path+ according to the given +mode+;
9615 * creates and returns a new File object for that file.
9616 *
9617 * The new File object is buffered mode (or non-sync mode), unless
9618 * +filename+ is a tty.
9619 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9620 *
9621 * Argument +path+ must be a valid file path:
9622 *
9623 * f = File.new('/etc/fstab')
9624 * f.close
9625 * f = File.new('t.txt')
9626 * f.close
9627 *
9628 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9629 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9630 *
9631 * f = File.new('t.tmp', 'w')
9632 * f.close
9633 * f = File.new('t.tmp', File::RDONLY)
9634 * f.close
9635 *
9636 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9637 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9638 *
9639 * f = File.new('t.tmp', File::CREAT, 0644)
9640 * f.close
9641 * f = File.new('t.tmp', File::CREAT, 0444)
9642 * f.close
9643 *
9644 * Optional keyword arguments +opts+ specify:
9645 *
9646 * - {Open Options}[rdoc-ref:IO@Open+Options].
9647 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9648 *
9649 */
9650
9651static VALUE
9652rb_file_initialize(int argc, VALUE *argv, VALUE io)
9653{
9654 if (RFILE(io)->fptr) {
9655 rb_raise(rb_eRuntimeError, "reinitializing File");
9656 }
9657 VALUE fname, vmode, vperm, opt;
9658 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9659 if (posargc < 3) { /* perm is File only */
9660 VALUE fd = rb_check_to_int(fname);
9661
9662 if (!NIL_P(fd)) {
9663 return io_initialize(io, fd, vmode, opt);
9664 }
9665 }
9666 return rb_open_file(io, fname, vmode, vperm, opt);
9667}
9668
9669/* :nodoc: */
9670static VALUE
9671rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9672{
9673 if (rb_block_given_p()) {
9674 VALUE cname = rb_obj_as_string(klass);
9675
9676 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9677 cname, cname);
9678 }
9679 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9680}
9681
9682
9683/*
9684 * call-seq:
9685 * IO.for_fd(fd, mode = 'r', **opts) -> io
9686 *
9687 * Synonym for IO.new.
9688 *
9689 */
9690
9691static VALUE
9692rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9693{
9694 VALUE io = rb_obj_alloc(klass);
9695 rb_io_initialize(argc, argv, io);
9696 return io;
9697}
9698
9699/*
9700 * call-seq:
9701 * ios.autoclose? -> true or false
9702 *
9703 * Returns +true+ if the underlying file descriptor of _ios_ will be
9704 * closed at its finalization or at calling #close, otherwise +false+.
9705 */
9706
9707static VALUE
9708rb_io_autoclose_p(VALUE io)
9709{
9710 rb_io_t *fptr = RFILE(io)->fptr;
9711 rb_io_check_closed(fptr);
9712 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9713}
9714
9715/*
9716 * call-seq:
9717 * io.autoclose = bool -> true or false
9718 *
9719 * Sets auto-close flag.
9720 *
9721 * f = File.open(File::NULL)
9722 * IO.for_fd(f.fileno).close
9723 * f.gets # raises Errno::EBADF
9724 *
9725 * f = File.open(File::NULL)
9726 * g = IO.for_fd(f.fileno)
9727 * g.autoclose = false
9728 * g.close
9729 * f.gets # won't cause Errno::EBADF
9730 */
9731
9732static VALUE
9733rb_io_set_autoclose(VALUE io, VALUE autoclose)
9734{
9735 rb_io_t *fptr;
9736 GetOpenFile(io, fptr);
9737 if (!RTEST(autoclose))
9738 fptr->mode |= FMODE_EXTERNAL;
9739 else
9740 fptr->mode &= ~FMODE_EXTERNAL;
9741 return autoclose;
9742}
9743
9744static VALUE
9745io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9746{
9747 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9748
9749 if (!RB_TEST(result)) {
9750 return Qnil;
9751 }
9752
9753 int mask = RB_NUM2INT(result);
9754
9755 if (mask & event) {
9756 if (return_io)
9757 return io;
9758 else
9759 return result;
9760 }
9761 else {
9762 return Qfalse;
9763 }
9764}
9765
9766/*
9767 * call-seq:
9768 * io.wait_readable -> truthy or falsy
9769 * io.wait_readable(timeout) -> truthy or falsy
9770 *
9771 * Waits until IO is readable and returns a truthy value, or a falsy
9772 * value when times out. Returns a truthy value immediately when
9773 * buffered data is available.
9774 */
9775
9776static VALUE
9777io_wait_readable(int argc, VALUE *argv, VALUE io)
9778{
9779 rb_io_t *fptr;
9780
9781 RB_IO_POINTER(io, fptr);
9782 rb_io_check_readable(fptr);
9783
9784 if (rb_io_read_pending(fptr)) return Qtrue;
9785
9786 rb_check_arity(argc, 0, 1);
9787 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9788
9789 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9790}
9791
9792/*
9793 * call-seq:
9794 * io.wait_writable -> truthy or falsy
9795 * io.wait_writable(timeout) -> truthy or falsy
9796 *
9797 * Waits until IO is writable and returns a truthy value or a falsy
9798 * value when times out.
9799 */
9800static VALUE
9801io_wait_writable(int argc, VALUE *argv, VALUE io)
9802{
9803 rb_io_t *fptr;
9804
9805 RB_IO_POINTER(io, fptr);
9806 rb_io_check_writable(fptr);
9807
9808 rb_check_arity(argc, 0, 1);
9809 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9810
9811 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9812}
9813
9814/*
9815 * call-seq:
9816 * io.wait_priority -> truthy or falsy
9817 * io.wait_priority(timeout) -> truthy or falsy
9818 *
9819 * Waits until IO is priority and returns a truthy value or a falsy
9820 * value when times out. Priority data is sent and received using
9821 * the Socket::MSG_OOB flag and is typically limited to streams.
9822 */
9823static VALUE
9824io_wait_priority(int argc, VALUE *argv, VALUE io)
9825{
9826 rb_io_t *fptr = NULL;
9827
9828 RB_IO_POINTER(io, fptr);
9829 rb_io_check_readable(fptr);
9830
9831 if (rb_io_read_pending(fptr)) return Qtrue;
9832
9833 rb_check_arity(argc, 0, 1);
9834 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9835
9836 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9837}
9838
9839static int
9840wait_mode_sym(VALUE mode)
9841{
9842 if (mode == ID2SYM(rb_intern("r"))) {
9843 return RB_WAITFD_IN;
9844 }
9845 if (mode == ID2SYM(rb_intern("read"))) {
9846 return RB_WAITFD_IN;
9847 }
9848 if (mode == ID2SYM(rb_intern("readable"))) {
9849 return RB_WAITFD_IN;
9850 }
9851 if (mode == ID2SYM(rb_intern("w"))) {
9852 return RB_WAITFD_OUT;
9853 }
9854 if (mode == ID2SYM(rb_intern("write"))) {
9855 return RB_WAITFD_OUT;
9856 }
9857 if (mode == ID2SYM(rb_intern("writable"))) {
9858 return RB_WAITFD_OUT;
9859 }
9860 if (mode == ID2SYM(rb_intern("rw"))) {
9861 return RB_WAITFD_IN|RB_WAITFD_OUT;
9862 }
9863 if (mode == ID2SYM(rb_intern("read_write"))) {
9864 return RB_WAITFD_IN|RB_WAITFD_OUT;
9865 }
9866 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9867 return RB_WAITFD_IN|RB_WAITFD_OUT;
9868 }
9869
9870 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9871}
9872
9873static inline enum rb_io_event
9874io_event_from_value(VALUE value)
9875{
9876 int events = RB_NUM2INT(value);
9877
9878 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9879
9880 return events;
9881}
9882
9883/*
9884 * call-seq:
9885 * io.wait(events, timeout) -> event mask, false or nil
9886 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9887 *
9888 * Waits until the IO becomes ready for the specified events and returns the
9889 * subset of events that become ready, or a falsy value when times out.
9890 *
9891 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9892 * +IO::PRIORITY+.
9893 *
9894 * Returns an event mask (truthy value) immediately when buffered data is available.
9895 *
9896 * Optional parameter +mode+ is one of +:read+, +:write+, or
9897 * +:read_write+.
9898 */
9899
9900static VALUE
9901io_wait(int argc, VALUE *argv, VALUE io)
9902{
9903 VALUE timeout = Qundef;
9904 enum rb_io_event events = 0;
9905 int return_io = 0;
9906
9907 // The documented signature for this method is actually incorrect.
9908 // A single timeout is allowed in any position, and multiple symbols can be given.
9909 // Whether this is intentional or not, I don't know, and as such I consider this to
9910 // be a legacy/slow path.
9911 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9912 // We'd prefer to return the actual mask, but this form would return the io itself:
9913 return_io = 1;
9914
9915 // Slow/messy path:
9916 for (int i = 0; i < argc; i += 1) {
9917 if (RB_SYMBOL_P(argv[i])) {
9918 events |= wait_mode_sym(argv[i]);
9919 }
9920 else if (UNDEF_P(timeout)) {
9921 rb_time_interval(timeout = argv[i]);
9922 }
9923 else {
9924 rb_raise(rb_eArgError, "timeout given more than once");
9925 }
9926 }
9927
9928 if (UNDEF_P(timeout)) timeout = Qnil;
9929
9930 if (events == 0) {
9931 events = RUBY_IO_READABLE;
9932 }
9933 }
9934 else /* argc == 2 and neither are symbols */ {
9935 // This is the fast path:
9936 events = io_event_from_value(argv[0]);
9937 timeout = argv[1];
9938 }
9939
9940 if (events & RUBY_IO_READABLE) {
9941 rb_io_t *fptr = NULL;
9942 RB_IO_POINTER(io, fptr);
9943
9944 if (rb_io_read_pending(fptr)) {
9945 // This was the original behaviour:
9946 if (return_io) return Qtrue;
9947 // New behaviour always returns an event mask:
9948 else return RB_INT2NUM(RUBY_IO_READABLE);
9949 }
9950 }
9951
9952 return io_wait_event(io, events, timeout, return_io);
9953}
9954
9955static void
9956argf_mark(void *ptr)
9957{
9958 struct argf *p = ptr;
9959 rb_gc_mark(p->filename);
9960 rb_gc_mark(p->current_file);
9961 rb_gc_mark(p->argv);
9962 rb_gc_mark(p->inplace);
9963 rb_gc_mark(p->encs.ecopts);
9964}
9965
9966static size_t
9967argf_memsize(const void *ptr)
9968{
9969 const struct argf *p = ptr;
9970 size_t size = sizeof(*p);
9971 return size;
9972}
9973
9974static const rb_data_type_t argf_type = {
9975 "ARGF",
9976 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9977 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9978};
9979
9980static inline void
9981argf_init(struct argf *p, VALUE v)
9982{
9983 p->filename = Qnil;
9984 p->current_file = Qnil;
9985 p->lineno = 0;
9986 p->argv = v;
9987}
9988
9989static VALUE
9990argf_alloc(VALUE klass)
9991{
9992 struct argf *p;
9993 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9994
9995 argf_init(p, Qnil);
9996 return argf;
9997}
9998
9999#undef rb_argv
10000
10001/* :nodoc: */
10002static VALUE
10003argf_initialize(VALUE argf, VALUE argv)
10004{
10005 memset(&ARGF, 0, sizeof(ARGF));
10006 argf_init(&ARGF, argv);
10007
10008 return argf;
10009}
10010
10011/* :nodoc: */
10012static VALUE
10013argf_initialize_copy(VALUE argf, VALUE orig)
10014{
10015 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10016 ARGF = argf_of(orig);
10017 ARGF.argv = rb_obj_dup(ARGF.argv);
10018 return argf;
10019}
10020
10021/*
10022 * call-seq:
10023 * ARGF.lineno = integer -> integer
10024 *
10025 * Sets the line number of ARGF as a whole to the given Integer.
10026 *
10027 * ARGF sets the line number automatically as you read data, so normally
10028 * you will not need to set it explicitly. To access the current line number
10029 * use ARGF.lineno.
10030 *
10031 * For example:
10032 *
10033 * ARGF.lineno #=> 0
10034 * ARGF.readline #=> "This is line 1\n"
10035 * ARGF.lineno #=> 1
10036 * ARGF.lineno = 0 #=> 0
10037 * ARGF.lineno #=> 0
10038 */
10039static VALUE
10040argf_set_lineno(VALUE argf, VALUE val)
10041{
10042 ARGF.lineno = NUM2INT(val);
10043 ARGF.last_lineno = ARGF.lineno;
10044 return val;
10045}
10046
10047/*
10048 * call-seq:
10049 * ARGF.lineno -> integer
10050 *
10051 * Returns the current line number of ARGF as a whole. This value
10052 * can be set manually with ARGF.lineno=.
10053 *
10054 * For example:
10055 *
10056 * ARGF.lineno #=> 0
10057 * ARGF.readline #=> "This is line 1\n"
10058 * ARGF.lineno #=> 1
10059 */
10060static VALUE
10061argf_lineno(VALUE argf)
10062{
10063 return INT2FIX(ARGF.lineno);
10064}
10065
10066static VALUE
10067argf_forward(int argc, VALUE *argv, VALUE argf)
10068{
10069 return forward_current(rb_frame_this_func(), argc, argv);
10070}
10071
10072#define next_argv() argf_next_argv(argf)
10073#define ARGF_GENERIC_INPUT_P() \
10074 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10075#define ARGF_FORWARD(argc, argv) do {\
10076 if (ARGF_GENERIC_INPUT_P())\
10077 return argf_forward((argc), (argv), argf);\
10078} while (0)
10079#define NEXT_ARGF_FORWARD(argc, argv) do {\
10080 if (!next_argv()) return Qnil;\
10081 ARGF_FORWARD((argc), (argv));\
10082} while (0)
10083
10084static void
10085argf_close(VALUE argf)
10086{
10087 VALUE file = ARGF.current_file;
10088 if (file == rb_stdin) return;
10089 if (RB_TYPE_P(file, T_FILE)) {
10090 rb_io_set_write_io(file, Qnil);
10091 }
10092 io_close(file);
10093 ARGF.init_p = -1;
10094}
10095
10096static int
10097argf_next_argv(VALUE argf)
10098{
10099 char *fn;
10100 rb_io_t *fptr;
10101 int stdout_binmode = 0;
10102 int fmode;
10103
10104 VALUE r_stdout = rb_ractor_stdout();
10105
10106 if (RB_TYPE_P(r_stdout, T_FILE)) {
10107 GetOpenFile(r_stdout, fptr);
10108 if (fptr->mode & FMODE_BINMODE)
10109 stdout_binmode = 1;
10110 }
10111
10112 if (ARGF.init_p == 0) {
10113 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10114 ARGF.next_p = 1;
10115 }
10116 else {
10117 ARGF.next_p = -1;
10118 }
10119 ARGF.init_p = 1;
10120 }
10121 else {
10122 if (NIL_P(ARGF.argv)) {
10123 ARGF.next_p = -1;
10124 }
10125 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10126 ARGF.next_p = 1;
10127 }
10128 }
10129
10130 if (ARGF.next_p == 1) {
10131 if (ARGF.init_p == 1) argf_close(argf);
10132 retry:
10133 if (RARRAY_LEN(ARGF.argv) > 0) {
10134 VALUE filename = rb_ary_shift(ARGF.argv);
10135 FilePathValue(filename);
10136 ARGF.filename = filename;
10137 filename = rb_str_encode_ospath(filename);
10138 fn = StringValueCStr(filename);
10139 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10140 ARGF.current_file = rb_stdin;
10141 if (ARGF.inplace) {
10142 rb_warn("Can't do inplace edit for stdio; skipping");
10143 goto retry;
10144 }
10145 }
10146 else {
10147 VALUE write_io = Qnil;
10148 int fr = rb_sysopen(filename, O_RDONLY, 0);
10149
10150 if (ARGF.inplace) {
10151 struct stat st;
10152#ifndef NO_SAFE_RENAME
10153 struct stat st2;
10154#endif
10155 VALUE str;
10156 int fw;
10157
10158 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10159 rb_io_close(r_stdout);
10160 }
10161 fstat(fr, &st);
10162 str = filename;
10163 if (!NIL_P(ARGF.inplace)) {
10164 VALUE suffix = ARGF.inplace;
10165 str = rb_str_dup(str);
10166 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10167 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10168 rb_enc_get(suffix), 0, Qnil))) {
10169 rb_str_append(str, suffix);
10170 }
10171#ifdef NO_SAFE_RENAME
10172 (void)close(fr);
10173 (void)unlink(RSTRING_PTR(str));
10174 if (rename(fn, RSTRING_PTR(str)) < 0) {
10175 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10176 filename, str, strerror(errno));
10177 goto retry;
10178 }
10179 fr = rb_sysopen(str, O_RDONLY, 0);
10180#else
10181 if (rename(fn, RSTRING_PTR(str)) < 0) {
10182 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10183 filename, str, strerror(errno));
10184 close(fr);
10185 goto retry;
10186 }
10187#endif
10188 }
10189 else {
10190#ifdef NO_SAFE_RENAME
10191 rb_fatal("Can't do inplace edit without backup");
10192#else
10193 if (unlink(fn) < 0) {
10194 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10195 filename, strerror(errno));
10196 close(fr);
10197 goto retry;
10198 }
10199#endif
10200 }
10201 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10202#ifndef NO_SAFE_RENAME
10203 fstat(fw, &st2);
10204#ifdef HAVE_FCHMOD
10205 fchmod(fw, st.st_mode);
10206#else
10207 chmod(fn, st.st_mode);
10208#endif
10209 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10210 int err;
10211#ifdef HAVE_FCHOWN
10212 err = fchown(fw, st.st_uid, st.st_gid);
10213#else
10214 err = chown(fn, st.st_uid, st.st_gid);
10215#endif
10216 if (err && getuid() == 0 && st2.st_uid == 0) {
10217 const char *wkfn = RSTRING_PTR(filename);
10218 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10219 filename, str, strerror(errno));
10220 (void)close(fr);
10221 (void)close(fw);
10222 (void)unlink(wkfn);
10223 goto retry;
10224 }
10225 }
10226#endif
10227 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10228 rb_ractor_stdout_set(write_io);
10229 if (stdout_binmode) rb_io_binmode(rb_stdout);
10230 }
10231 fmode = FMODE_READABLE;
10232 if (!ARGF.binmode) {
10233 fmode |= DEFAULT_TEXTMODE;
10234 }
10235 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10236 if (!NIL_P(write_io)) {
10237 rb_io_set_write_io(ARGF.current_file, write_io);
10238 }
10239 RB_GC_GUARD(filename);
10240 }
10241 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10242 GetOpenFile(ARGF.current_file, fptr);
10243 if (ARGF.encs.enc) {
10244 fptr->encs = ARGF.encs;
10245 clear_codeconv(fptr);
10246 }
10247 else {
10248 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10249 if (!ARGF.binmode) {
10250 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
10251#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10252 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10253#endif
10254 }
10255 }
10256 ARGF.next_p = 0;
10257 }
10258 else {
10259 ARGF.next_p = 1;
10260 return FALSE;
10261 }
10262 }
10263 else if (ARGF.next_p == -1) {
10264 ARGF.current_file = rb_stdin;
10265 ARGF.filename = rb_str_new2("-");
10266 if (ARGF.inplace) {
10267 rb_warn("Can't do inplace edit for stdio");
10268 rb_ractor_stdout_set(orig_stdout);
10269 }
10270 }
10271 if (ARGF.init_p == -1) ARGF.init_p = 1;
10272 return TRUE;
10273}
10274
10275static VALUE
10276argf_getline(int argc, VALUE *argv, VALUE argf)
10277{
10278 VALUE line;
10279 long lineno = ARGF.lineno;
10280
10281 retry:
10282 if (!next_argv()) return Qnil;
10283 if (ARGF_GENERIC_INPUT_P()) {
10284 line = forward_current(idGets, argc, argv);
10285 }
10286 else {
10287 if (argc == 0 && rb_rs == rb_default_rs) {
10288 line = rb_io_gets(ARGF.current_file);
10289 }
10290 else {
10291 line = rb_io_getline(argc, argv, ARGF.current_file);
10292 }
10293 if (NIL_P(line) && ARGF.next_p != -1) {
10294 argf_close(argf);
10295 ARGF.next_p = 1;
10296 goto retry;
10297 }
10298 }
10299 if (!NIL_P(line)) {
10300 ARGF.lineno = ++lineno;
10301 ARGF.last_lineno = ARGF.lineno;
10302 }
10303 return line;
10304}
10305
10306static VALUE
10307argf_lineno_getter(ID id, VALUE *var)
10308{
10309 VALUE argf = *var;
10310 return INT2FIX(ARGF.last_lineno);
10311}
10312
10313static void
10314argf_lineno_setter(VALUE val, ID id, VALUE *var)
10315{
10316 VALUE argf = *var;
10317 int n = NUM2INT(val);
10318 ARGF.last_lineno = ARGF.lineno = n;
10319}
10320
10321void
10322rb_reset_argf_lineno(long n)
10323{
10324 ARGF.last_lineno = ARGF.lineno = n;
10325}
10326
10327static VALUE argf_gets(int, VALUE *, VALUE);
10328
10329/*
10330 * call-seq:
10331 * gets(sep=$/ [, getline_args]) -> string or nil
10332 * gets(limit [, getline_args]) -> string or nil
10333 * gets(sep, limit [, getline_args]) -> string or nil
10334 *
10335 * Returns (and assigns to <code>$_</code>) the next line from the list
10336 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10337 * no files are present on the command line. Returns +nil+ at end of
10338 * file. The optional argument specifies the record separator. The
10339 * separator is included with the contents of each record. A separator
10340 * of +nil+ reads the entire contents, and a zero-length separator
10341 * reads the input one paragraph at a time, where paragraphs are
10342 * divided by two consecutive newlines. If the first argument is an
10343 * integer, or optional second argument is given, the returning string
10344 * would not be longer than the given value in bytes. If multiple
10345 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10346 * the contents one file at a time.
10347 *
10348 * ARGV << "testfile"
10349 * print while gets
10350 *
10351 * <em>produces:</em>
10352 *
10353 * This is line one
10354 * This is line two
10355 * This is line three
10356 * And so on...
10357 *
10358 * The style of programming using <code>$_</code> as an implicit
10359 * parameter is gradually losing favor in the Ruby community.
10360 */
10361
10362static VALUE
10363rb_f_gets(int argc, VALUE *argv, VALUE recv)
10364{
10365 if (recv == argf) {
10366 return argf_gets(argc, argv, argf);
10367 }
10368 return forward(argf, idGets, argc, argv);
10369}
10370
10371/*
10372 * call-seq:
10373 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10374 * ARGF.gets(limit [, getline_args]) -> string or nil
10375 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10376 *
10377 * Returns the next line from the current file in ARGF.
10378 *
10379 * By default lines are assumed to be separated by <code>$/</code>;
10380 * to use a different character as a separator, supply it as a String
10381 * for the _sep_ argument.
10382 *
10383 * The optional _limit_ argument specifies how many characters of each line
10384 * to return. By default all characters are returned.
10385 *
10386 * See IO.readlines for details about getline_args.
10387 *
10388 */
10389static VALUE
10390argf_gets(int argc, VALUE *argv, VALUE argf)
10391{
10392 VALUE line;
10393
10394 line = argf_getline(argc, argv, argf);
10395 rb_lastline_set(line);
10396
10397 return line;
10398}
10399
10400 VALUE
10401rb_gets(void)
10402{
10403 VALUE line;
10404
10405 if (rb_rs != rb_default_rs) {
10406 return rb_f_gets(0, 0, argf);
10407 }
10408
10409 retry:
10410 if (!next_argv()) return Qnil;
10411 line = rb_io_gets(ARGF.current_file);
10412 if (NIL_P(line) && ARGF.next_p != -1) {
10413 rb_io_close(ARGF.current_file);
10414 ARGF.next_p = 1;
10415 goto retry;
10416 }
10417 rb_lastline_set(line);
10418 if (!NIL_P(line)) {
10419 ARGF.lineno++;
10420 ARGF.last_lineno = ARGF.lineno;
10421 }
10422
10423 return line;
10424}
10425
10426static VALUE argf_readline(int, VALUE *, VALUE);
10427
10428/*
10429 * call-seq:
10430 * readline(sep = $/, chomp: false) -> string
10431 * readline(limit, chomp: false) -> string
10432 * readline(sep, limit, chomp: false) -> string
10433 *
10434 * Equivalent to method Kernel#gets, except that it raises an exception
10435 * if called at end-of-stream:
10436 *
10437 * $ cat t.txt | ruby -e "p readlines; readline"
10438 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10439 * in `readline': end of file reached (EOFError)
10440 *
10441 * Optional keyword argument +chomp+ specifies whether line separators
10442 * are to be omitted.
10443 */
10444
10445static VALUE
10446rb_f_readline(int argc, VALUE *argv, VALUE recv)
10447{
10448 if (recv == argf) {
10449 return argf_readline(argc, argv, argf);
10450 }
10451 return forward(argf, rb_intern("readline"), argc, argv);
10452}
10453
10454
10455/*
10456 * call-seq:
10457 * ARGF.readline(sep=$/) -> string
10458 * ARGF.readline(limit) -> string
10459 * ARGF.readline(sep, limit) -> string
10460 *
10461 * Returns the next line from the current file in ARGF.
10462 *
10463 * By default lines are assumed to be separated by <code>$/</code>;
10464 * to use a different character as a separator, supply it as a String
10465 * for the _sep_ argument.
10466 *
10467 * The optional _limit_ argument specifies how many characters of each line
10468 * to return. By default all characters are returned.
10469 *
10470 * An EOFError is raised at the end of the file.
10471 */
10472static VALUE
10473argf_readline(int argc, VALUE *argv, VALUE argf)
10474{
10475 VALUE line;
10476
10477 if (!next_argv()) rb_eof_error();
10478 ARGF_FORWARD(argc, argv);
10479 line = argf_gets(argc, argv, argf);
10480 if (NIL_P(line)) {
10481 rb_eof_error();
10482 }
10483
10484 return line;
10485}
10486
10487static VALUE argf_readlines(int, VALUE *, VALUE);
10488
10489/*
10490 * call-seq:
10491 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10492 * readlines(limit, chomp: false, **enc_opts) -> array
10493 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10494 *
10495 * Returns an array containing the lines returned by calling
10496 * Kernel#gets until the end-of-stream is reached;
10497 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10498 *
10499 * With only string argument +sep+ given,
10500 * returns the remaining lines as determined by line separator +sep+,
10501 * or +nil+ if none;
10502 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10503 *
10504 * # Default separator.
10505 * $ cat t.txt | ruby -e "p readlines"
10506 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10507 *
10508 * # Specified separator.
10509 * $ cat t.txt | ruby -e "p readlines 'li'"
10510 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10511 *
10512 * # Get-all separator.
10513 * $ cat t.txt | ruby -e "p readlines nil"
10514 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10515 *
10516 * # Get-paragraph separator.
10517 * $ cat t.txt | ruby -e "p readlines ''"
10518 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10519 *
10520 * With only integer argument +limit+ given,
10521 * limits the number of bytes in the line;
10522 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10523 *
10524 * $cat t.txt | ruby -e "p readlines 10"
10525 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10526 *
10527 * $cat t.txt | ruby -e "p readlines 11"
10528 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10529 *
10530 * $cat t.txt | ruby -e "p readlines 12"
10531 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10532 *
10533 * With arguments +sep+ and +limit+ given,
10534 * combines the two behaviors
10535 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10536 *
10537 * Optional keyword argument +chomp+ specifies whether line separators
10538 * are to be omitted:
10539 *
10540 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10541 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10542 *
10543 * Optional keyword arguments +enc_opts+ specify encoding options;
10544 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10545 *
10546 */
10547
10548static VALUE
10549rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10550{
10551 if (recv == argf) {
10552 return argf_readlines(argc, argv, argf);
10553 }
10554 return forward(argf, rb_intern("readlines"), argc, argv);
10555}
10556
10557/*
10558 * call-seq:
10559 * ARGF.readlines(sep = $/, chomp: false) -> array
10560 * ARGF.readlines(limit, chomp: false) -> array
10561 * ARGF.readlines(sep, limit, chomp: false) -> array
10562 *
10563 * ARGF.to_a(sep = $/, chomp: false) -> array
10564 * ARGF.to_a(limit, chomp: false) -> array
10565 * ARGF.to_a(sep, limit, chomp: false) -> array
10566 *
10567 * Reads each file in ARGF in its entirety, returning an Array containing
10568 * lines from the files. Lines are assumed to be separated by _sep_.
10569 *
10570 * lines = ARGF.readlines
10571 * lines[0] #=> "This is line one\n"
10572 *
10573 * See +IO.readlines+ for a full description of all options.
10574 */
10575static VALUE
10576argf_readlines(int argc, VALUE *argv, VALUE argf)
10577{
10578 long lineno = ARGF.lineno;
10579 VALUE lines, ary;
10580
10581 ary = rb_ary_new();
10582 while (next_argv()) {
10583 if (ARGF_GENERIC_INPUT_P()) {
10584 lines = forward_current(rb_intern("readlines"), argc, argv);
10585 }
10586 else {
10587 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10588 argf_close(argf);
10589 }
10590 ARGF.next_p = 1;
10591 rb_ary_concat(ary, lines);
10592 ARGF.lineno = lineno + RARRAY_LEN(ary);
10593 ARGF.last_lineno = ARGF.lineno;
10594 }
10595 ARGF.init_p = 0;
10596 return ary;
10597}
10598
10599/*
10600 * call-seq:
10601 * `command` -> string
10602 *
10603 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10604 * sets global variable <tt>$?</tt> to the process status.
10605 *
10606 * This method has potential security vulnerabilities if called with untrusted input;
10607 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10608 *
10609 * Examples:
10610 *
10611 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10612 * $ `echo oops && exit 99` # => "oops\n"
10613 * $ $? # => #<Process::Status: pid 17088 exit 99>
10614 * $ $?.status # => 99>
10615 *
10616 * The built-in syntax <tt>%x{...}</tt> uses this method.
10617 *
10618 */
10619
10620static VALUE
10621rb_f_backquote(VALUE obj, VALUE str)
10622{
10623 VALUE port;
10624 VALUE result;
10625 rb_io_t *fptr;
10626
10627 StringValue(str);
10628 rb_last_status_clear();
10629 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10630 if (NIL_P(port)) return rb_str_new(0,0);
10631
10632 GetOpenFile(port, fptr);
10633 result = read_all(fptr, remain_size(fptr), Qnil);
10634 rb_io_close(port);
10635 rb_io_fptr_cleanup_all(fptr);
10636 RB_GC_GUARD(port);
10637
10638 return result;
10639}
10640
10641#ifdef HAVE_SYS_SELECT_H
10642#include <sys/select.h>
10643#endif
10644
10645static VALUE
10646select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10647{
10648 VALUE res, list;
10649 rb_fdset_t *rp, *wp, *ep;
10650 rb_io_t *fptr;
10651 long i;
10652 int max = 0, n;
10653 int pending = 0;
10654 struct timeval timerec;
10655
10656 if (!NIL_P(read)) {
10657 Check_Type(read, T_ARRAY);
10658 for (i=0; i<RARRAY_LEN(read); i++) {
10659 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10660 rb_fd_set(fptr->fd, &fds[0]);
10661 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10662 pending++;
10663 rb_fd_set(fptr->fd, &fds[3]);
10664 }
10665 if (max < fptr->fd) max = fptr->fd;
10666 }
10667 if (pending) { /* no blocking if there's buffered data */
10668 timerec.tv_sec = timerec.tv_usec = 0;
10669 tp = &timerec;
10670 }
10671 rp = &fds[0];
10672 }
10673 else
10674 rp = 0;
10675
10676 if (!NIL_P(write)) {
10677 Check_Type(write, T_ARRAY);
10678 for (i=0; i<RARRAY_LEN(write); i++) {
10679 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10680 GetOpenFile(write_io, fptr);
10681 rb_fd_set(fptr->fd, &fds[1]);
10682 if (max < fptr->fd) max = fptr->fd;
10683 }
10684 wp = &fds[1];
10685 }
10686 else
10687 wp = 0;
10688
10689 if (!NIL_P(except)) {
10690 Check_Type(except, T_ARRAY);
10691 for (i=0; i<RARRAY_LEN(except); i++) {
10692 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10693 VALUE write_io = GetWriteIO(io);
10694 GetOpenFile(io, fptr);
10695 rb_fd_set(fptr->fd, &fds[2]);
10696 if (max < fptr->fd) max = fptr->fd;
10697 if (io != write_io) {
10698 GetOpenFile(write_io, fptr);
10699 rb_fd_set(fptr->fd, &fds[2]);
10700 if (max < fptr->fd) max = fptr->fd;
10701 }
10702 }
10703 ep = &fds[2];
10704 }
10705 else {
10706 ep = 0;
10707 }
10708
10709 max++;
10710
10711 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10712 if (n < 0) {
10713 rb_sys_fail(0);
10714 }
10715 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10716
10717 res = rb_ary_new2(3);
10718 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10719 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10720 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10721
10722 if (rp) {
10723 list = RARRAY_AREF(res, 0);
10724 for (i=0; i< RARRAY_LEN(read); i++) {
10725 VALUE obj = rb_ary_entry(read, i);
10726 VALUE io = rb_io_get_io(obj);
10727 GetOpenFile(io, fptr);
10728 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10729 rb_fd_isset(fptr->fd, &fds[3])) {
10730 rb_ary_push(list, obj);
10731 }
10732 }
10733 }
10734
10735 if (wp) {
10736 list = RARRAY_AREF(res, 1);
10737 for (i=0; i< RARRAY_LEN(write); i++) {
10738 VALUE obj = rb_ary_entry(write, i);
10739 VALUE io = rb_io_get_io(obj);
10740 VALUE write_io = GetWriteIO(io);
10741 GetOpenFile(write_io, fptr);
10742 if (rb_fd_isset(fptr->fd, &fds[1])) {
10743 rb_ary_push(list, obj);
10744 }
10745 }
10746 }
10747
10748 if (ep) {
10749 list = RARRAY_AREF(res, 2);
10750 for (i=0; i< RARRAY_LEN(except); i++) {
10751 VALUE obj = rb_ary_entry(except, i);
10752 VALUE io = rb_io_get_io(obj);
10753 VALUE write_io = GetWriteIO(io);
10754 GetOpenFile(io, fptr);
10755 if (rb_fd_isset(fptr->fd, &fds[2])) {
10756 rb_ary_push(list, obj);
10757 }
10758 else if (io != write_io) {
10759 GetOpenFile(write_io, fptr);
10760 if (rb_fd_isset(fptr->fd, &fds[2])) {
10761 rb_ary_push(list, obj);
10762 }
10763 }
10764 }
10765 }
10766
10767 return res; /* returns an empty array on interrupt */
10768}
10769
10770 struct select_args {
10771 VALUE read, write, except;
10772 struct timeval *timeout;
10773 rb_fdset_t fdsets[4];
10774};
10775
10776static VALUE
10777select_call(VALUE arg)
10778{
10779 struct select_args *p = (struct select_args *)arg;
10780
10781 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10782}
10783
10784static VALUE
10785select_end(VALUE arg)
10786{
10787 struct select_args *p = (struct select_args *)arg;
10788 int i;
10789
10790 for (i = 0; i < numberof(p->fdsets); ++i)
10791 rb_fd_term(&p->fdsets[i]);
10792 return Qnil;
10793}
10794
10795static VALUE sym_normal, sym_sequential, sym_random,
10796 sym_willneed, sym_dontneed, sym_noreuse;
10797
10798#ifdef HAVE_POSIX_FADVISE
10799struct io_advise_struct {
10800 int fd;
10801 int advice;
10802 rb_off_t offset;
10803 rb_off_t len;
10804};
10805
10806static VALUE
10807io_advise_internal(void *arg)
10808{
10809 struct io_advise_struct *ptr = arg;
10810 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10811}
10812
10813static VALUE
10814io_advise_sym_to_const(VALUE sym)
10815{
10816#ifdef POSIX_FADV_NORMAL
10817 if (sym == sym_normal)
10818 return INT2NUM(POSIX_FADV_NORMAL);
10819#endif
10820
10821#ifdef POSIX_FADV_RANDOM
10822 if (sym == sym_random)
10823 return INT2NUM(POSIX_FADV_RANDOM);
10824#endif
10825
10826#ifdef POSIX_FADV_SEQUENTIAL
10827 if (sym == sym_sequential)
10828 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10829#endif
10830
10831#ifdef POSIX_FADV_WILLNEED
10832 if (sym == sym_willneed)
10833 return INT2NUM(POSIX_FADV_WILLNEED);
10834#endif
10835
10836#ifdef POSIX_FADV_DONTNEED
10837 if (sym == sym_dontneed)
10838 return INT2NUM(POSIX_FADV_DONTNEED);
10839#endif
10840
10841#ifdef POSIX_FADV_NOREUSE
10842 if (sym == sym_noreuse)
10843 return INT2NUM(POSIX_FADV_NOREUSE);
10844#endif
10845
10846 return Qnil;
10847}
10848
10849static VALUE
10850do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10851{
10852 int rv;
10853 struct io_advise_struct ias;
10854 VALUE num_adv;
10855
10856 num_adv = io_advise_sym_to_const(advice);
10857
10858 /*
10859 * The platform doesn't support this hint. We don't raise exception, instead
10860 * silently ignore it. Because IO::advise is only hint.
10861 */
10862 if (NIL_P(num_adv))
10863 return Qnil;
10864
10865 ias.fd = fptr->fd;
10866 ias.advice = NUM2INT(num_adv);
10867 ias.offset = offset;
10868 ias.len = len;
10869
10870 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10871 if (rv && rv != ENOSYS) {
10872 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10873 it returns the error code. */
10874 VALUE message = rb_sprintf("%"PRIsVALUE" "
10875 "(%"PRI_OFFT_PREFIX"d, "
10876 "%"PRI_OFFT_PREFIX"d, "
10877 "%"PRIsVALUE")",
10878 fptr->pathv, offset, len, advice);
10879 rb_syserr_fail_str(rv, message);
10880 }
10881
10882 return Qnil;
10883}
10884
10885#endif /* HAVE_POSIX_FADVISE */
10886
10887static void
10888advice_arg_check(VALUE advice)
10889{
10890 if (!SYMBOL_P(advice))
10891 rb_raise(rb_eTypeError, "advice must be a Symbol");
10892
10893 if (advice != sym_normal &&
10894 advice != sym_sequential &&
10895 advice != sym_random &&
10896 advice != sym_willneed &&
10897 advice != sym_dontneed &&
10898 advice != sym_noreuse) {
10899 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10900 }
10901}
10902
10903/*
10904 * call-seq:
10905 * advise(advice, offset = 0, len = 0) -> nil
10906 *
10907 * Invokes Posix system call
10908 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10909 * which announces an intention to access data from the current file
10910 * in a particular manner.
10911 *
10912 * The arguments and results are platform-dependent.
10913 *
10914 * The relevant data is specified by:
10915 *
10916 * - +offset+: The offset of the first byte of data.
10917 * - +len+: The number of bytes to be accessed;
10918 * if +len+ is zero, or is larger than the number of bytes remaining,
10919 * all remaining bytes will be accessed.
10920 *
10921 * Argument +advice+ is one of the following symbols:
10922 *
10923 * - +:normal+: The application has no advice to give
10924 * about its access pattern for the specified data.
10925 * If no advice is given for an open file, this is the default assumption.
10926 * - +:sequential+: The application expects to access the specified data sequentially
10927 * (with lower offsets read before higher ones).
10928 * - +:random+: The specified data will be accessed in random order.
10929 * - +:noreuse+: The specified data will be accessed only once.
10930 * - +:willneed+: The specified data will be accessed in the near future.
10931 * - +:dontneed+: The specified data will not be accessed in the near future.
10932 *
10933 * Not implemented on all platforms.
10934 *
10935 */
10936static VALUE
10937rb_io_advise(int argc, VALUE *argv, VALUE io)
10938{
10939 VALUE advice, offset, len;
10940 rb_off_t off, l;
10941 rb_io_t *fptr;
10942
10943 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10944 advice_arg_check(advice);
10945
10946 io = GetWriteIO(io);
10947 GetOpenFile(io, fptr);
10948
10949 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10950 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10951
10952#ifdef HAVE_POSIX_FADVISE
10953 return do_io_advise(fptr, advice, off, l);
10954#else
10955 ((void)off, (void)l); /* Ignore all hint */
10956 return Qnil;
10957#endif
10958}
10959
10960/*
10961 * call-seq:
10962 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10963 *
10964 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10965 * which monitors multiple file descriptors,
10966 * waiting until one or more of the file descriptors
10967 * becomes ready for some class of I/O operation.
10968 *
10969 * Not implemented on all platforms.
10970 *
10971 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10972 * is an array of IO objects.
10973 *
10974 * Argument +timeout+ is a numeric value (such as integer or float) timeout
10975 * interval in seconds.
10976 *
10977 * The method monitors the \IO objects given in all three arrays,
10978 * waiting for some to be ready;
10979 * returns a 3-element array whose elements are:
10980 *
10981 * - An array of the objects in +read_ios+ that are ready for reading.
10982 * - An array of the objects in +write_ios+ that are ready for writing.
10983 * - An array of the objects in +error_ios+ have pending exceptions.
10984 *
10985 * If no object becomes ready within the given +timeout+, +nil+ is returned.
10986 *
10987 * \IO.select peeks the buffer of \IO objects for testing readability.
10988 * If the \IO buffer is not empty, \IO.select immediately notifies
10989 * readability. This "peek" only happens for \IO objects. It does not
10990 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10991 *
10992 * The best way to use \IO.select is invoking it after non-blocking
10993 * methods such as #read_nonblock, #write_nonblock, etc. The methods
10994 * raise an exception which is extended by IO::WaitReadable or
10995 * IO::WaitWritable. The modules notify how the caller should wait
10996 * with \IO.select. If IO::WaitReadable is raised, the caller should
10997 * wait for reading. If IO::WaitWritable is raised, the caller should
10998 * wait for writing.
10999 *
11000 * So, blocking read (#readpartial) can be emulated using
11001 * #read_nonblock and \IO.select as follows:
11002 *
11003 * begin
11004 * result = io_like.read_nonblock(maxlen)
11005 * rescue IO::WaitReadable
11006 * IO.select([io_like])
11007 * retry
11008 * rescue IO::WaitWritable
11009 * IO.select(nil, [io_like])
11010 * retry
11011 * end
11012 *
11013 * Especially, the combination of non-blocking methods and \IO.select is
11014 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11015 * has #to_io method to return underlying IO object. IO.select calls
11016 * #to_io to obtain the file descriptor to wait.
11017 *
11018 * This means that readability notified by \IO.select doesn't mean
11019 * readability from OpenSSL::SSL::SSLSocket object.
11020 *
11021 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11022 * some data. \IO.select doesn't see the buffer. So \IO.select can
11023 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11024 *
11025 * However, several more complicated situations exist.
11026 *
11027 * SSL is a protocol which is sequence of records.
11028 * The record consists of multiple bytes.
11029 * So, the remote side of SSL sends a partial record, IO.select
11030 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11031 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11032 *
11033 * Also, the remote side can request SSL renegotiation which forces
11034 * the local SSL engine to write some data.
11035 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11036 * system call and it can block.
11037 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11038 * IO::WaitWritable instead of blocking.
11039 * So, the caller should wait for ready for writability as above
11040 * example.
11041 *
11042 * The combination of non-blocking methods and \IO.select is also useful
11043 * for streams such as tty, pipe socket socket when multiple processes
11044 * read from a stream.
11045 *
11046 * Finally, Linux kernel developers don't guarantee that
11047 * readability of select(2) means readability of following read(2) even
11048 * for a single process;
11049 * see {select(2)}[https://linux.die.net/man/2/select]
11050 *
11051 * Invoking \IO.select before IO#readpartial works well as usual.
11052 * However it is not the best way to use \IO.select.
11053 *
11054 * The writability notified by select(2) doesn't show
11055 * how many bytes are writable.
11056 * IO#write method blocks until given whole string is written.
11057 * So, <tt>IO#write(two or more bytes)</tt> can block after
11058 * writability is notified by \IO.select. IO#write_nonblock is required
11059 * to avoid the blocking.
11060 *
11061 * Blocking write (#write) can be emulated using #write_nonblock and
11062 * IO.select as follows: IO::WaitReadable should also be rescued for
11063 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11064 *
11065 * while 0 < string.bytesize
11066 * begin
11067 * written = io_like.write_nonblock(string)
11068 * rescue IO::WaitReadable
11069 * IO.select([io_like])
11070 * retry
11071 * rescue IO::WaitWritable
11072 * IO.select(nil, [io_like])
11073 * retry
11074 * end
11075 * string = string.byteslice(written..-1)
11076 * end
11077 *
11078 * Example:
11079 *
11080 * rp, wp = IO.pipe
11081 * mesg = "ping "
11082 * 100.times {
11083 * # IO.select follows IO#read. Not the best way to use IO.select.
11084 * rs, ws, = IO.select([rp], [wp])
11085 * if r = rs[0]
11086 * ret = r.read(5)
11087 * print ret
11088 * case ret
11089 * when /ping/
11090 * mesg = "pong\n"
11091 * when /pong/
11092 * mesg = "ping "
11093 * end
11094 * end
11095 * if w = ws[0]
11096 * w.write(mesg)
11097 * end
11098 * }
11099 *
11100 * Output:
11101 *
11102 * ping pong
11103 * ping pong
11104 * ping pong
11105 * (snipped)
11106 * ping
11107 *
11108 */
11109
11110static VALUE
11111rb_f_select(int argc, VALUE *argv, VALUE obj)
11112{
11113 VALUE scheduler = rb_fiber_scheduler_current();
11114 if (scheduler != Qnil) {
11115 // It's optionally supported.
11116 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11117 if (!UNDEF_P(result)) return result;
11118 }
11119
11120 VALUE timeout;
11121 struct select_args args;
11122 struct timeval timerec;
11123 int i;
11124
11125 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11126 if (NIL_P(timeout)) {
11127 args.timeout = 0;
11128 }
11129 else {
11130 timerec = rb_time_interval(timeout);
11131 args.timeout = &timerec;
11132 }
11133
11134 for (i = 0; i < numberof(args.fdsets); ++i)
11135 rb_fd_init(&args.fdsets[i]);
11136
11137 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11138}
11139
11140#ifdef IOCTL_REQ_TYPE
11141 typedef IOCTL_REQ_TYPE ioctl_req_t;
11142#else
11143 typedef int ioctl_req_t;
11144# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11145#endif
11146
11147#ifdef HAVE_IOCTL
11148struct ioctl_arg {
11149 int fd;
11150 ioctl_req_t cmd;
11151 long narg;
11152};
11153
11154static VALUE
11155nogvl_ioctl(void *ptr)
11156{
11157 struct ioctl_arg *arg = ptr;
11158
11159 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11160}
11161
11162static int
11163do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11164{
11165 int retval;
11166 struct ioctl_arg arg;
11167
11168 arg.fd = io->fd;
11169 arg.cmd = cmd;
11170 arg.narg = narg;
11171
11172 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11173
11174 return retval;
11175}
11176#endif
11177
11178#define DEFAULT_IOCTL_NARG_LEN (256)
11179
11180#if defined(__linux__) && defined(_IOC_SIZE)
11181static long
11182linux_iocparm_len(ioctl_req_t cmd)
11183{
11184 long len;
11185
11186 if ((cmd & 0xFFFF0000) == 0) {
11187 /* legacy and unstructured ioctl number. */
11188 return DEFAULT_IOCTL_NARG_LEN;
11189 }
11190
11191 len = _IOC_SIZE(cmd);
11192
11193 /* paranoia check for silly drivers which don't keep ioctl convention */
11194 if (len < DEFAULT_IOCTL_NARG_LEN)
11195 len = DEFAULT_IOCTL_NARG_LEN;
11196
11197 return len;
11198}
11199#endif
11200
11201#ifdef HAVE_IOCTL
11202static long
11203ioctl_narg_len(ioctl_req_t cmd)
11204{
11205 long len;
11206
11207#ifdef IOCPARM_MASK
11208#ifndef IOCPARM_LEN
11209#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11210#endif
11211#endif
11212#ifdef IOCPARM_LEN
11213 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11214#elif defined(__linux__) && defined(_IOC_SIZE)
11215 len = linux_iocparm_len(cmd);
11216#else
11217 /* otherwise guess at what's safe */
11218 len = DEFAULT_IOCTL_NARG_LEN;
11219#endif
11220
11221 return len;
11222}
11223#endif
11224
11225#ifdef HAVE_FCNTL
11226#ifdef __linux__
11227typedef long fcntl_arg_t;
11228#else
11229/* posix */
11230typedef int fcntl_arg_t;
11231#endif
11232
11233static long
11234fcntl_narg_len(ioctl_req_t cmd)
11235{
11236 long len;
11237
11238 switch (cmd) {
11239#ifdef F_DUPFD
11240 case F_DUPFD:
11241 len = sizeof(fcntl_arg_t);
11242 break;
11243#endif
11244#ifdef F_DUP2FD /* bsd specific */
11245 case F_DUP2FD:
11246 len = sizeof(int);
11247 break;
11248#endif
11249#ifdef F_DUPFD_CLOEXEC /* linux specific */
11250 case F_DUPFD_CLOEXEC:
11251 len = sizeof(fcntl_arg_t);
11252 break;
11253#endif
11254#ifdef F_GETFD
11255 case F_GETFD:
11256 len = 1;
11257 break;
11258#endif
11259#ifdef F_SETFD
11260 case F_SETFD:
11261 len = sizeof(fcntl_arg_t);
11262 break;
11263#endif
11264#ifdef F_GETFL
11265 case F_GETFL:
11266 len = 1;
11267 break;
11268#endif
11269#ifdef F_SETFL
11270 case F_SETFL:
11271 len = sizeof(fcntl_arg_t);
11272 break;
11273#endif
11274#ifdef F_GETOWN
11275 case F_GETOWN:
11276 len = 1;
11277 break;
11278#endif
11279#ifdef F_SETOWN
11280 case F_SETOWN:
11281 len = sizeof(fcntl_arg_t);
11282 break;
11283#endif
11284#ifdef F_GETOWN_EX /* linux specific */
11285 case F_GETOWN_EX:
11286 len = sizeof(struct f_owner_ex);
11287 break;
11288#endif
11289#ifdef F_SETOWN_EX /* linux specific */
11290 case F_SETOWN_EX:
11291 len = sizeof(struct f_owner_ex);
11292 break;
11293#endif
11294#ifdef F_GETLK
11295 case F_GETLK:
11296 len = sizeof(struct flock);
11297 break;
11298#endif
11299#ifdef F_SETLK
11300 case F_SETLK:
11301 len = sizeof(struct flock);
11302 break;
11303#endif
11304#ifdef F_SETLKW
11305 case F_SETLKW:
11306 len = sizeof(struct flock);
11307 break;
11308#endif
11309#ifdef F_READAHEAD /* bsd specific */
11310 case F_READAHEAD:
11311 len = sizeof(int);
11312 break;
11313#endif
11314#ifdef F_RDAHEAD /* Darwin specific */
11315 case F_RDAHEAD:
11316 len = sizeof(int);
11317 break;
11318#endif
11319#ifdef F_GETSIG /* linux specific */
11320 case F_GETSIG:
11321 len = 1;
11322 break;
11323#endif
11324#ifdef F_SETSIG /* linux specific */
11325 case F_SETSIG:
11326 len = sizeof(fcntl_arg_t);
11327 break;
11328#endif
11329#ifdef F_GETLEASE /* linux specific */
11330 case F_GETLEASE:
11331 len = 1;
11332 break;
11333#endif
11334#ifdef F_SETLEASE /* linux specific */
11335 case F_SETLEASE:
11336 len = sizeof(fcntl_arg_t);
11337 break;
11338#endif
11339#ifdef F_NOTIFY /* linux specific */
11340 case F_NOTIFY:
11341 len = sizeof(fcntl_arg_t);
11342 break;
11343#endif
11344
11345 default:
11346 len = 256;
11347 break;
11348 }
11349
11350 return len;
11351}
11352#else /* HAVE_FCNTL */
11353static long
11354fcntl_narg_len(ioctl_req_t cmd)
11355{
11356 return 0;
11357}
11358#endif /* HAVE_FCNTL */
11359
11360#define NARG_SENTINEL 17
11361
11362static long
11363setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11364{
11365 long narg = 0;
11366 VALUE arg = *argp;
11367
11368 if (!RTEST(arg)) {
11369 narg = 0;
11370 }
11371 else if (FIXNUM_P(arg)) {
11372 narg = FIX2LONG(arg);
11373 }
11374 else if (arg == Qtrue) {
11375 narg = 1;
11376 }
11377 else {
11378 VALUE tmp = rb_check_string_type(arg);
11379
11380 if (NIL_P(tmp)) {
11381 narg = NUM2LONG(arg);
11382 }
11383 else {
11384 char *ptr;
11385 long len, slen;
11386
11387 *argp = arg = tmp;
11388 len = narg_len(cmd);
11389 rb_str_modify(arg);
11390
11391 slen = RSTRING_LEN(arg);
11392 /* expand for data + sentinel. */
11393 if (slen < len+1) {
11394 rb_str_resize(arg, len+1);
11395 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11396 slen = len+1;
11397 }
11398 /* a little sanity check here */
11399 ptr = RSTRING_PTR(arg);
11400 ptr[slen - 1] = NARG_SENTINEL;
11401 narg = (long)(SIGNED_VALUE)ptr;
11402 }
11403 }
11404
11405 return narg;
11406}
11407
11408static VALUE
11409finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11410{
11411 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11412 if (RB_TYPE_P(arg, T_STRING)) {
11413 char *ptr;
11414 long slen;
11415 RSTRING_GETMEM(arg, ptr, slen);
11416 if (ptr[slen-1] != NARG_SENTINEL)
11417 rb_raise(rb_eArgError, "return value overflowed string");
11418 ptr[slen-1] = '\0';
11419 }
11420
11421 return INT2NUM(retval);
11422}
11423
11424#ifdef HAVE_IOCTL
11425static VALUE
11426rb_ioctl(VALUE io, VALUE req, VALUE arg)
11427{
11428 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11429 rb_io_t *fptr;
11430 long narg;
11431 int retval;
11432
11433 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11434 GetOpenFile(io, fptr);
11435 retval = do_ioctl(fptr, cmd, narg);
11436 return finish_narg(retval, arg, fptr);
11437}
11438
11439/*
11440 * call-seq:
11441 * ioctl(integer_cmd, argument) -> integer
11442 *
11443 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11444 * which issues a low-level command to an I/O device.
11445 *
11446 * Issues a low-level command to an I/O device.
11447 * The arguments and returned value are platform-dependent.
11448 * The effect of the call is platform-dependent.
11449 *
11450 * If argument +argument+ is an integer, it is passed directly;
11451 * if it is a string, it is interpreted as a binary sequence of bytes.
11452 *
11453 * Not implemented on all platforms.
11454 *
11455 */
11456
11457static VALUE
11458rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11459{
11460 VALUE req, arg;
11461
11462 rb_scan_args(argc, argv, "11", &req, &arg);
11463 return rb_ioctl(io, req, arg);
11464}
11465#else
11466#define rb_io_ioctl rb_f_notimplement
11467#endif
11468
11469#ifdef HAVE_FCNTL
11470struct fcntl_arg {
11471 int fd;
11472 int cmd;
11473 long narg;
11474};
11475
11476static VALUE
11477nogvl_fcntl(void *ptr)
11478{
11479 struct fcntl_arg *arg = ptr;
11480
11481#if defined(F_DUPFD)
11482 if (arg->cmd == F_DUPFD)
11483 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11484#endif
11485 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11486}
11487
11488static int
11489do_fcntl(struct rb_io *io, int cmd, long narg)
11490{
11491 int retval;
11492 struct fcntl_arg arg;
11493
11494 arg.fd = io->fd;
11495 arg.cmd = cmd;
11496 arg.narg = narg;
11497
11498 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11499 if (retval != -1) {
11500 switch (cmd) {
11501#if defined(F_DUPFD)
11502 case F_DUPFD:
11503#endif
11504#if defined(F_DUPFD_CLOEXEC)
11505 case F_DUPFD_CLOEXEC:
11506#endif
11507 rb_update_max_fd(retval);
11508 }
11509 }
11510
11511 return retval;
11512}
11513
11514static VALUE
11515rb_fcntl(VALUE io, VALUE req, VALUE arg)
11516{
11517 int cmd = NUM2INT(req);
11518 rb_io_t *fptr;
11519 long narg;
11520 int retval;
11521
11522 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11523 GetOpenFile(io, fptr);
11524 retval = do_fcntl(fptr, cmd, narg);
11525 return finish_narg(retval, arg, fptr);
11526}
11527
11528/*
11529 * call-seq:
11530 * fcntl(integer_cmd, argument) -> integer
11531 *
11532 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11533 * which provides a mechanism for issuing low-level commands to control or query
11534 * a file-oriented I/O stream. Arguments and results are platform
11535 * dependent.
11536 *
11537 * If +argument+ is a number, its value is passed directly;
11538 * if it is a string, it is interpreted as a binary sequence of bytes.
11539 * (Array#pack might be a useful way to build this string.)
11540 *
11541 * Not implemented on all platforms.
11542 *
11543 */
11544
11545static VALUE
11546rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11547{
11548 VALUE req, arg;
11549
11550 rb_scan_args(argc, argv, "11", &req, &arg);
11551 return rb_fcntl(io, req, arg);
11552}
11553#else
11554#define rb_io_fcntl rb_f_notimplement
11555#endif
11556
11557#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11558/*
11559 * call-seq:
11560 * syscall(integer_callno, *arguments) -> integer
11561 *
11562 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11563 * which calls a specified function.
11564 *
11565 * Calls the operating system function identified by +integer_callno+;
11566 * returns the result of the function or raises SystemCallError if it failed.
11567 * The effect of the call is platform-dependent.
11568 * The arguments and returned value are platform-dependent.
11569 *
11570 * For each of +arguments+: if it is an integer, it is passed directly;
11571 * if it is a string, it is interpreted as a binary sequence of bytes.
11572 * There may be as many as nine such arguments.
11573 *
11574 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11575 * are platform-dependent.
11576 *
11577 * Note: Method +syscall+ is essentially unsafe and unportable.
11578 * The DL (Fiddle) library is preferred for safer and a bit
11579 * more portable programming.
11580 *
11581 * Not implemented on all platforms.
11582 *
11583 */
11584
11585static VALUE
11586rb_f_syscall(int argc, VALUE *argv, VALUE _)
11587{
11588 VALUE arg[8];
11589#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11590# define SYSCALL __syscall
11591# define NUM2SYSCALLID(x) NUM2LONG(x)
11592# define RETVAL2NUM(x) LONG2NUM(x)
11593# if SIZEOF_LONG == 8
11594 long num, retval = -1;
11595# elif SIZEOF_LONG_LONG == 8
11596 long long num, retval = -1;
11597# else
11598# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11599# endif
11600#elif defined(__linux__)
11601# define SYSCALL syscall
11602# define NUM2SYSCALLID(x) NUM2LONG(x)
11603# define RETVAL2NUM(x) LONG2NUM(x)
11604 /*
11605 * Linux man page says, syscall(2) function prototype is below.
11606 *
11607 * int syscall(int number, ...);
11608 *
11609 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11610 */
11611 long num, retval = -1;
11612#else
11613# define SYSCALL syscall
11614# define NUM2SYSCALLID(x) NUM2INT(x)
11615# define RETVAL2NUM(x) INT2NUM(x)
11616 int num, retval = -1;
11617#endif
11618 int i;
11619
11620 if (RTEST(ruby_verbose)) {
11621 rb_category_warning(RB_WARN_CATEGORY_DEPRECATED,
11622 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11623 }
11624
11625 if (argc == 0)
11626 rb_raise(rb_eArgError, "too few arguments for syscall");
11627 if (argc > numberof(arg))
11628 rb_raise(rb_eArgError, "too many arguments for syscall");
11629 num = NUM2SYSCALLID(argv[0]); ++argv;
11630 for (i = argc - 1; i--; ) {
11631 VALUE v = rb_check_string_type(argv[i]);
11632
11633 if (!NIL_P(v)) {
11634 StringValue(v);
11635 rb_str_modify(v);
11636 arg[i] = (VALUE)StringValueCStr(v);
11637 }
11638 else {
11639 arg[i] = (VALUE)NUM2LONG(argv[i]);
11640 }
11641 }
11642
11643 switch (argc) {
11644 case 1:
11645 retval = SYSCALL(num);
11646 break;
11647 case 2:
11648 retval = SYSCALL(num, arg[0]);
11649 break;
11650 case 3:
11651 retval = SYSCALL(num, arg[0],arg[1]);
11652 break;
11653 case 4:
11654 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11655 break;
11656 case 5:
11657 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11658 break;
11659 case 6:
11660 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11661 break;
11662 case 7:
11663 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11664 break;
11665 case 8:
11666 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11667 break;
11668 }
11669
11670 if (retval == -1)
11671 rb_sys_fail(0);
11672 return RETVAL2NUM(retval);
11673#undef SYSCALL
11674#undef NUM2SYSCALLID
11675#undef RETVAL2NUM
11676}
11677#else
11678#define rb_f_syscall rb_f_notimplement
11679#endif
11680
11681static VALUE
11682io_new_instance(VALUE args)
11683{
11684 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11685}
11686
11687static rb_encoding *
11688find_encoding(VALUE v)
11689{
11690 rb_encoding *enc = rb_find_encoding(v);
11691 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11692 return enc;
11693}
11694
11695static void
11696io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11697{
11698 rb_encoding *enc, *enc2;
11699 int ecflags = fptr->encs.ecflags;
11700 VALUE ecopts, tmp;
11701
11702 if (!NIL_P(v2)) {
11703 enc2 = find_encoding(v1);
11704 tmp = rb_check_string_type(v2);
11705 if (!NIL_P(tmp)) {
11706 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11707 /* Special case - "-" => no transcoding */
11708 enc = enc2;
11709 enc2 = NULL;
11710 }
11711 else
11712 enc = find_encoding(v2);
11713 if (enc == enc2) {
11714 /* Special case - "-" => no transcoding */
11715 enc2 = NULL;
11716 }
11717 }
11718 else {
11719 enc = find_encoding(v2);
11720 if (enc == enc2) {
11721 /* Special case - "-" => no transcoding */
11722 enc2 = NULL;
11723 }
11724 }
11725 if (enc2 == rb_ascii8bit_encoding()) {
11726 /* If external is ASCII-8BIT, no transcoding */
11727 enc = enc2;
11728 enc2 = NULL;
11729 }
11730 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11731 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11732 }
11733 else {
11734 if (NIL_P(v1)) {
11735 /* Set to default encodings */
11736 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11737 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11738 ecopts = Qnil;
11739 }
11740 else {
11741 tmp = rb_check_string_type(v1);
11742 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11743 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11744 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11745 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11746 }
11747 else {
11748 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11749 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11750 ecopts = Qnil;
11751 }
11752 }
11753 }
11754 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11755 fptr->encs.enc = enc;
11756 fptr->encs.enc2 = enc2;
11757 fptr->encs.ecflags = ecflags;
11758 fptr->encs.ecopts = ecopts;
11759 clear_codeconv(fptr);
11760
11761}
11762
11763 struct io_encoding_set_args {
11764 rb_io_t *fptr;
11765 VALUE v1;
11766 VALUE v2;
11767 VALUE opt;
11768};
11769
11770static VALUE
11771io_encoding_set_v(VALUE v)
11772{
11773 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11774 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11775 return Qnil;
11776}
11777
11778static VALUE
11779pipe_pair_close(VALUE rw)
11780{
11781 VALUE *rwp = (VALUE *)rw;
11782 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11783}
11784
11785/*
11786 * call-seq:
11787 * IO.pipe(**opts) -> [read_io, write_io]
11788 * IO.pipe(enc, **opts) -> [read_io, write_io]
11789 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11790 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11791 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11792 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11793 *
11794 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11795 * connected to each other.
11796 *
11797 * If argument +enc_string+ is given, it must be a string containing one of:
11798 *
11799 * - The name of the encoding to be used as the external encoding.
11800 * - The colon-separated names of two encodings to be used as the external
11801 * and internal encodings.
11802 *
11803 * If argument +int_enc+ is given, it must be an Encoding object
11804 * or encoding name string that specifies the internal encoding to be used;
11805 * if argument +ext_enc+ is also given, it must be an Encoding object
11806 * or encoding name string that specifies the external encoding to be used.
11807 *
11808 * The string read from +read_io+ is tagged with the external encoding;
11809 * if an internal encoding is also specified, the string is converted
11810 * to, and tagged with, that encoding.
11811 *
11812 * If any encoding is specified,
11813 * optional hash arguments specify the conversion option.
11814 *
11815 * Optional keyword arguments +opts+ specify:
11816 *
11817 * - {Open Options}[rdoc-ref:IO@Open+Options].
11818 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11819 *
11820 * With no block given, returns the two endpoints in an array:
11821 *
11822 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11823 *
11824 * With a block given, calls the block with the two endpoints;
11825 * closes both endpoints and returns the value of the block:
11826 *
11827 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11828 *
11829 * Output:
11830 *
11831 * #<IO:fd 6>
11832 * #<IO:fd 7>
11833 *
11834 * Not available on all platforms.
11835 *
11836 * In the example below, the two processes close the ends of the pipe
11837 * that they are not using. This is not just a cosmetic nicety. The
11838 * read end of a pipe will not generate an end of file condition if
11839 * there are any writers with the pipe still open. In the case of the
11840 * parent process, the <tt>rd.read</tt> will never return if it
11841 * does not first issue a <tt>wr.close</tt>:
11842 *
11843 * rd, wr = IO.pipe
11844 *
11845 * if fork
11846 * wr.close
11847 * puts "Parent got: <#{rd.read}>"
11848 * rd.close
11849 * Process.wait
11850 * else
11851 * rd.close
11852 * puts 'Sending message to parent'
11853 * wr.write "Hi Dad"
11854 * wr.close
11855 * end
11856 *
11857 * <em>produces:</em>
11858 *
11859 * Sending message to parent
11860 * Parent got: <Hi Dad>
11861 *
11862 */
11863
11864static VALUE
11865rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11866{
11867 int pipes[2], state;
11868 VALUE r, w, args[3], v1, v2;
11869 VALUE opt;
11870 rb_io_t *fptr, *fptr2;
11871 struct io_encoding_set_args ies_args;
11872 int fmode = 0;
11873 VALUE ret;
11874
11875 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11876 if (rb_pipe(pipes) < 0)
11877 rb_sys_fail(0);
11878
11879 args[0] = klass;
11880 args[1] = INT2NUM(pipes[0]);
11881 args[2] = INT2FIX(O_RDONLY);
11882 r = rb_protect(io_new_instance, (VALUE)args, &state);
11883 if (state) {
11884 close(pipes[0]);
11885 close(pipes[1]);
11886 rb_jump_tag(state);
11887 }
11888 GetOpenFile(r, fptr);
11889
11890 ies_args.fptr = fptr;
11891 ies_args.v1 = v1;
11892 ies_args.v2 = v2;
11893 ies_args.opt = opt;
11894 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11895 if (state) {
11896 close(pipes[1]);
11897 io_close(r);
11898 rb_jump_tag(state);
11899 }
11900
11901 args[1] = INT2NUM(pipes[1]);
11902 args[2] = INT2FIX(O_WRONLY);
11903 w = rb_protect(io_new_instance, (VALUE)args, &state);
11904 if (state) {
11905 close(pipes[1]);
11906 if (!NIL_P(r)) rb_io_close(r);
11907 rb_jump_tag(state);
11908 }
11909 GetOpenFile(w, fptr2);
11910 rb_io_synchronized(fptr2);
11911
11912 extract_binmode(opt, &fmode);
11913
11914 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11915 rb_io_ascii8bit_binmode(r);
11916 rb_io_ascii8bit_binmode(w);
11917 }
11918
11919#if DEFAULT_TEXTMODE
11920 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11921 fptr->mode &= ~FMODE_TEXTMODE;
11922 setmode(fptr->fd, O_BINARY);
11923 }
11924#if RUBY_CRLF_ENVIRONMENT
11925 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
11926 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
11927 }
11928#endif
11929#endif
11930 fptr->mode |= fmode;
11931#if DEFAULT_TEXTMODE
11932 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11933 fptr2->mode &= ~FMODE_TEXTMODE;
11934 setmode(fptr2->fd, O_BINARY);
11935 }
11936#endif
11937 fptr2->mode |= fmode;
11938
11939 ret = rb_assoc_new(r, w);
11940 if (rb_block_given_p()) {
11941 VALUE rw[2];
11942 rw[0] = r;
11943 rw[1] = w;
11944 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11945 }
11946 return ret;
11947}
11948
11949 struct foreach_arg {
11950 int argc;
11951 VALUE *argv;
11952 VALUE io;
11953};
11954
11955static void
11956open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11957{
11958 VALUE path, v;
11959 VALUE vmode = Qnil, vperm = Qnil;
11960
11961 path = *argv++;
11962 argc--;
11963 FilePathValue(path);
11964 arg->io = 0;
11965 arg->argc = argc;
11966 arg->argv = argv;
11967 if (NIL_P(opt)) {
11968 vmode = INT2NUM(O_RDONLY);
11969 vperm = INT2FIX(0666);
11970 }
11971 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11972 int n;
11973
11974 v = rb_to_array_type(v);
11975 n = RARRAY_LENINT(v);
11976 rb_check_arity(n, 0, 3); /* rb_io_open */
11977 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11978 }
11979 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11980}
11981
11982static VALUE
11983io_s_foreach(VALUE v)
11984{
11985 struct getline_arg *arg = (void *)v;
11986 VALUE str;
11987
11988 if (arg->limit == 0)
11989 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
11990 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11991 rb_lastline_set(str);
11992 rb_yield(str);
11993 }
11994 rb_lastline_set(Qnil);
11995 return Qnil;
11996}
11997
11998/*
11999 * call-seq:
12000 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12001 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12002 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12003 * IO.foreach(...) -> an_enumerator
12004 *
12005 * Calls the block with each successive line read from the stream.
12006 *
12007 * When called from class \IO (but not subclasses of \IO),
12008 * this method has potential security vulnerabilities if called with untrusted input;
12009 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12010 *
12011 * The first argument must be a string that is the path to a file.
12012 *
12013 * With only argument +path+ given, parses lines from the file at the given +path+,
12014 * as determined by the default line separator,
12015 * and calls the block with each successive line:
12016 *
12017 * File.foreach('t.txt') {|line| p line }
12018 *
12019 * Output: the same as above.
12020 *
12021 * For both forms, command and path, the remaining arguments are the same.
12022 *
12023 * With argument +sep+ given, parses lines as determined by that line separator
12024 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12025 *
12026 * File.foreach('t.txt', 'li') {|line| p line }
12027 *
12028 * Output:
12029 *
12030 * "First li"
12031 * "ne\nSecond li"
12032 * "ne\n\nThird li"
12033 * "ne\nFourth li"
12034 * "ne\n"
12035 *
12036 * Each paragraph:
12037 *
12038 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12039 *
12040 * Output:
12041 *
12042 * "First line\nSecond line\n\n"
12043 * "Third line\nFourth line\n"
12044 *
12045 * With argument +limit+ given, parses lines as determined by the default
12046 * line separator and the given line-length limit
12047 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12048 *
12049 * File.foreach('t.txt', 7) {|line| p line }
12050 *
12051 * Output:
12052 *
12053 * "First l"
12054 * "ine\n"
12055 * "Second "
12056 * "line\n"
12057 * "\n"
12058 * "Third l"
12059 * "ine\n"
12060 * "Fourth l"
12061 * "line\n"
12062 *
12063 * With arguments +sep+ and +limit+ given,
12064 * combines the two behaviors
12065 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12066 *
12067 * Optional keyword arguments +opts+ specify:
12068 *
12069 * - {Open Options}[rdoc-ref:IO@Open+Options].
12070 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12071 * - {Line Options}[rdoc-ref:IO@Line+IO].
12072 *
12073 * Returns an Enumerator if no block is given.
12074 *
12075 */
12076
12077static VALUE
12078rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12079{
12080 VALUE opt;
12081 int orig_argc = argc;
12082 struct foreach_arg arg;
12083 struct getline_arg garg;
12084
12085 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12086 RETURN_ENUMERATOR(self, orig_argc, argv);
12087 extract_getline_args(argc-1, argv+1, &garg);
12088 open_key_args(self, argc, argv, opt, &arg);
12089 if (NIL_P(arg.io)) return Qnil;
12090 extract_getline_opts(opt, &garg);
12091 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12092 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12093}
12094
12095static VALUE
12096io_s_readlines(VALUE v)
12097{
12098 struct getline_arg *arg = (void *)v;
12099 return io_readlines(arg, arg->io);
12100}
12101
12102/*
12103 * call-seq:
12104 * IO.readlines(path, sep = $/, **opts) -> array
12105 * IO.readlines(path, limit, **opts) -> array
12106 * IO.readlines(path, sep, limit, **opts) -> array
12107 *
12108 * Returns an array of all lines read from the stream.
12109 *
12110 * When called from class \IO (but not subclasses of \IO),
12111 * this method has potential security vulnerabilities if called with untrusted input;
12112 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12113 *
12114 * The first argument must be a string that is the path to a file.
12115 *
12116 * With only argument +path+ given, parses lines from the file at the given +path+,
12117 * as determined by the default line separator,
12118 * and returns those lines in an array:
12119 *
12120 * IO.readlines('t.txt')
12121 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12122 *
12123 * With argument +sep+ given, parses lines as determined by that line separator
12124 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12125 *
12126 * # Ordinary separator.
12127 * IO.readlines('t.txt', 'li')
12128 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12129 * # Get-paragraphs separator.
12130 * IO.readlines('t.txt', '')
12131 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12132 * # Get-all separator.
12133 * IO.readlines('t.txt', nil)
12134 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12135 *
12136 * With argument +limit+ given, parses lines as determined by the default
12137 * line separator and the given line-length limit
12138 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12139 *
12140 * IO.readlines('t.txt', 7)
12141 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12142 *
12143 * With arguments +sep+ and +limit+ given,
12144 * combines the two behaviors
12145 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12146 *
12147 * Optional keyword arguments +opts+ specify:
12148 *
12149 * - {Open Options}[rdoc-ref:IO@Open+Options].
12150 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12151 * - {Line Options}[rdoc-ref:IO@Line+IO].
12152 *
12153 */
12154
12155static VALUE
12156rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12157{
12158 VALUE opt;
12159 struct foreach_arg arg;
12160 struct getline_arg garg;
12161
12162 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12163 extract_getline_args(argc-1, argv+1, &garg);
12164 open_key_args(io, argc, argv, opt, &arg);
12165 if (NIL_P(arg.io)) return Qnil;
12166 extract_getline_opts(opt, &garg);
12167 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12168 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12169}
12170
12171static VALUE
12172io_s_read(VALUE v)
12173{
12174 struct foreach_arg *arg = (void *)v;
12175 return io_read(arg->argc, arg->argv, arg->io);
12176}
12177
12178 struct seek_arg {
12179 VALUE io;
12180 VALUE offset;
12181 int mode;
12182};
12183
12184static VALUE
12185seek_before_access(VALUE argp)
12186{
12187 struct seek_arg *arg = (struct seek_arg *)argp;
12188 rb_io_binmode(arg->io);
12189 return rb_io_seek(arg->io, arg->offset, arg->mode);
12190}
12191
12192/*
12193 * call-seq:
12194 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12195 *
12196 * Opens the stream, reads and returns some or all of its content,
12197 * and closes the stream; returns +nil+ if no bytes were read.
12198 *
12199 * When called from class \IO (but not subclasses of \IO),
12200 * this method has potential security vulnerabilities if called with untrusted input;
12201 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12202 *
12203 * The first argument must be a string that is the path to a file.
12204 *
12205 * With only argument +path+ given, reads in text mode and returns the entire content
12206 * of the file at the given path:
12207 *
12208 * IO.read('t.txt')
12209 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12210 *
12211 * On Windows, text mode can terminate reading and leave bytes in the file
12212 * unread when encountering certain special bytes. Consider using
12213 * IO.binread if all bytes in the file should be read.
12214 *
12215 * With argument +length+, returns +length+ bytes if available:
12216 *
12217 * IO.read('t.txt', 7) # => "First l"
12218 * IO.read('t.txt', 700)
12219 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12220 *
12221 * With arguments +length+ and +offset+, returns +length+ bytes
12222 * if available, beginning at the given +offset+:
12223 *
12224 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12225 * IO.read('t.txt', 10, 200) # => nil
12226 *
12227 * Optional keyword arguments +opts+ specify:
12228 *
12229 * - {Open Options}[rdoc-ref:IO@Open+Options].
12230 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12231 *
12232 */
12233
12234static VALUE
12235rb_io_s_read(int argc, VALUE *argv, VALUE io)
12236{
12237 VALUE opt, offset;
12238 long off;
12239 struct foreach_arg arg;
12240
12241 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12242 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12243 rb_raise(rb_eArgError, "negative offset %ld given", off);
12244 }
12245 open_key_args(io, argc, argv, opt, &arg);
12246 if (NIL_P(arg.io)) return Qnil;
12247 if (!NIL_P(offset)) {
12248 struct seek_arg sarg;
12249 int state = 0;
12250 sarg.io = arg.io;
12251 sarg.offset = offset;
12252 sarg.mode = SEEK_SET;
12253 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12254 if (state) {
12255 rb_io_close(arg.io);
12256 rb_jump_tag(state);
12257 }
12258 if (arg.argc == 2) arg.argc = 1;
12259 }
12260 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12261}
12262
12263/*
12264 * call-seq:
12265 * IO.binread(path, length = nil, offset = 0) -> string or nil
12266 *
12267 * Behaves like IO.read, except that the stream is opened in binary mode
12268 * with ASCII-8BIT encoding.
12269 *
12270 * When called from class \IO (but not subclasses of \IO),
12271 * this method has potential security vulnerabilities if called with untrusted input;
12272 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12273 *
12274 */
12275
12276static VALUE
12277rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12278{
12279 VALUE offset;
12280 struct foreach_arg arg;
12281 enum {
12282 fmode = FMODE_READABLE|FMODE_BINMODE,
12283 oflags = O_RDONLY
12284#ifdef O_BINARY
12285 |O_BINARY
12286#endif
12287 };
12288 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12289
12290 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12291 FilePathValue(argv[0]);
12292 convconfig.enc = rb_ascii8bit_encoding();
12293 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12294 if (NIL_P(arg.io)) return Qnil;
12295 arg.argv = argv+1;
12296 arg.argc = (argc > 1) ? 1 : 0;
12297 if (!NIL_P(offset)) {
12298 struct seek_arg sarg;
12299 int state = 0;
12300 sarg.io = arg.io;
12301 sarg.offset = offset;
12302 sarg.mode = SEEK_SET;
12303 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12304 if (state) {
12305 rb_io_close(arg.io);
12306 rb_jump_tag(state);
12307 }
12308 }
12309 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12310}
12311
12312static VALUE
12313io_s_write0(VALUE v)
12314{
12315 struct write_arg *arg = (void *)v;
12316 return io_write(arg->io,arg->str,arg->nosync);
12317}
12318
12319static VALUE
12320io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12321{
12322 VALUE string, offset, opt;
12323 struct foreach_arg arg;
12324 struct write_arg warg;
12325
12326 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12327
12328 if (NIL_P(opt)) opt = rb_hash_new();
12329 else opt = rb_hash_dup(opt);
12330
12331
12332 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12333 int mode = O_WRONLY|O_CREAT;
12334#ifdef O_BINARY
12335 if (binary) mode |= O_BINARY;
12336#endif
12337 if (NIL_P(offset)) mode |= O_TRUNC;
12338 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12339 }
12340 open_key_args(klass, argc, argv, opt, &arg);
12341
12342#ifndef O_BINARY
12343 if (binary) rb_io_binmode_m(arg.io);
12344#endif
12345
12346 if (NIL_P(arg.io)) return Qnil;
12347 if (!NIL_P(offset)) {
12348 struct seek_arg sarg;
12349 int state = 0;
12350 sarg.io = arg.io;
12351 sarg.offset = offset;
12352 sarg.mode = SEEK_SET;
12353 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12354 if (state) {
12355 rb_io_close(arg.io);
12356 rb_jump_tag(state);
12357 }
12358 }
12359
12360 warg.io = arg.io;
12361 warg.str = string;
12362 warg.nosync = 0;
12363
12364 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12365}
12366
12367/*
12368 * call-seq:
12369 * IO.write(path, data, offset = 0, **opts) -> integer
12370 *
12371 * Opens the stream, writes the given +data+ to it,
12372 * and closes the stream; returns the number of bytes written.
12373 *
12374 * When called from class \IO (but not subclasses of \IO),
12375 * this method has potential security vulnerabilities if called with untrusted input;
12376 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12377 *
12378 * The first argument must be a string that is the path to a file.
12379 *
12380 * With only argument +path+ given, writes the given +data+ to the file at that path:
12381 *
12382 * IO.write('t.tmp', 'abc') # => 3
12383 * File.read('t.tmp') # => "abc"
12384 *
12385 * If +offset+ is zero (the default), the file is overwritten:
12386 *
12387 * IO.write('t.tmp', 'A') # => 1
12388 * File.read('t.tmp') # => "A"
12389 *
12390 * If +offset+ in within the file content, the file is partly overwritten:
12391 *
12392 * IO.write('t.tmp', 'abcdef') # => 3
12393 * File.read('t.tmp') # => "abcdef"
12394 * # Offset within content.
12395 * IO.write('t.tmp', '012', 2) # => 3
12396 * File.read('t.tmp') # => "ab012f"
12397 *
12398 * If +offset+ is outside the file content,
12399 * the file is padded with null characters <tt>"\u0000"</tt>:
12400 *
12401 * IO.write('t.tmp', 'xyz', 10) # => 3
12402 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12403 *
12404 * Optional keyword arguments +opts+ specify:
12405 *
12406 * - {Open Options}[rdoc-ref:IO@Open+Options].
12407 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12408 *
12409 */
12410
12411static VALUE
12412rb_io_s_write(int argc, VALUE *argv, VALUE io)
12413{
12414 return io_s_write(argc, argv, io, 0);
12415}
12416
12417/*
12418 * call-seq:
12419 * IO.binwrite(path, string, offset = 0) -> integer
12420 *
12421 * Behaves like IO.write, except that the stream is opened in binary mode
12422 * with ASCII-8BIT encoding.
12423 *
12424 * When called from class \IO (but not subclasses of \IO),
12425 * this method has potential security vulnerabilities if called with untrusted input;
12426 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12427 *
12428 */
12429
12430static VALUE
12431rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12432{
12433 return io_s_write(argc, argv, io, 1);
12434}
12435
12436 struct copy_stream_struct {
12437 VALUE src;
12438 VALUE dst;
12439 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12440 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12441
12442 rb_io_t *src_fptr;
12443 rb_io_t *dst_fptr;
12444 unsigned close_src : 1;
12445 unsigned close_dst : 1;
12446 int error_no;
12447 rb_off_t total;
12448 const char *syserr;
12449 const char *notimp;
12450 VALUE th;
12451 struct stat src_stat;
12452 struct stat dst_stat;
12453#ifdef HAVE_FCOPYFILE
12454 copyfile_state_t copyfile_state;
12455#endif
12456};
12457
12458static void *
12459exec_interrupts(void *arg)
12460{
12461 VALUE th = (VALUE)arg;
12462 rb_thread_execute_interrupts(th);
12463 return NULL;
12464}
12465
12466/*
12467 * returns TRUE if the preceding system call was interrupted
12468 * so we can continue. If the thread was interrupted, we
12469 * reacquire the GVL to execute interrupts before continuing.
12470 */
12471static int
12472maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12473{
12474 switch (errno) {
12475 case EINTR:
12476#if defined(ERESTART)
12477 case ERESTART:
12478#endif
12479 if (rb_thread_interrupted(stp->th)) {
12480 if (has_gvl)
12481 rb_thread_execute_interrupts(stp->th);
12482 else
12483 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12484 }
12485 return TRUE;
12486 }
12487 return FALSE;
12488}
12489
12490 struct fiber_scheduler_wait_for_arguments {
12491 VALUE scheduler;
12492
12493 rb_io_t *fptr;
12494 short events;
12495
12496 VALUE result;
12497};
12498
12499static void *
12500fiber_scheduler_wait_for(void * _arguments)
12501{
12502 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12503
12504 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12505
12506 return NULL;
12507}
12508
12509#if USE_POLL
12510# define IOWAIT_SYSCALL "poll"
12511STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12512STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12513static int
12514nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12515{
12516 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
12517 if (scheduler != Qnil) {
12518 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12519 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12520 return RTEST(args.result);
12521 }
12522
12523 int fd = fptr->fd;
12524 if (fd == -1) return 0;
12525
12526 struct pollfd fds;
12527
12528 fds.fd = fd;
12529 fds.events = events;
12530
12531 int timeout_milliseconds = -1;
12532
12533 if (timeout) {
12534 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12535 }
12536
12537 return poll(&fds, 1, timeout_milliseconds);
12538}
12539#else /* !USE_POLL */
12540# define IOWAIT_SYSCALL "select"
12541static int
12542nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12543{
12544 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
12545 if (scheduler != Qnil) {
12546 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12547 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12548 return RTEST(args.result);
12549 }
12550
12551 int fd = fptr->fd;
12552
12553 if (fd == -1) {
12554 errno = EBADF;
12555 return -1;
12556 }
12557
12558 rb_fdset_t fds;
12559 int ret;
12560
12561 rb_fd_init(&fds);
12562 rb_fd_set(fd, &fds);
12563
12564 switch (events) {
12565 case RB_WAITFD_IN:
12566 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12567 break;
12568 case RB_WAITFD_OUT:
12569 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12570 break;
12571 default:
12572 VM_UNREACHABLE(nogvl_wait_for);
12573 }
12574
12575 rb_fd_term(&fds);
12576
12577 // On timeout, this returns 0.
12578 return ret;
12579}
12580#endif /* !USE_POLL */
12581
12582static int
12583maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12584{
12585 int ret;
12586
12587 do {
12588 if (has_gvl) {
12589 ret = RB_NUM2INT(rb_io_wait(stp->src, RB_INT2NUM(RUBY_IO_READABLE), Qnil));
12590 }
12591 else {
12592 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12593 }
12594 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12595
12596 if (ret < 0) {
12597 stp->syserr = IOWAIT_SYSCALL;
12598 stp->error_no = errno;
12599 return ret;
12600 }
12601 return 0;
12602}
12603
12604static int
12605nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12606{
12607 int ret;
12608
12609 do {
12610 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12611 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12612
12613 if (ret < 0) {
12614 stp->syserr = IOWAIT_SYSCALL;
12615 stp->error_no = errno;
12616 return ret;
12617 }
12618 return 0;
12619}
12620
12621#ifdef USE_COPY_FILE_RANGE
12622
12623static ssize_t
12624simple_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)
12625{
12626#ifdef HAVE_COPY_FILE_RANGE
12627 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12628#else
12629 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12630#endif
12631}
12632
12633static int
12634nogvl_copy_file_range(struct copy_stream_struct *stp)
12635{
12636 ssize_t ss;
12637 rb_off_t src_size;
12638 rb_off_t copy_length, src_offset, *src_offset_ptr;
12639
12640 if (!S_ISREG(stp->src_stat.st_mode))
12641 return 0;
12642
12643 src_size = stp->src_stat.st_size;
12644 src_offset = stp->src_offset;
12645 if (src_offset >= (rb_off_t)0) {
12646 src_offset_ptr = &src_offset;
12647 }
12648 else {
12649 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12650 }
12651
12652 copy_length = stp->copy_length;
12653 if (copy_length < (rb_off_t)0) {
12654 if (src_offset < (rb_off_t)0) {
12655 rb_off_t current_offset;
12656 errno = 0;
12657 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12658 if (current_offset < (rb_off_t)0 && errno) {
12659 stp->syserr = "lseek";
12660 stp->error_no = errno;
12661 return (int)current_offset;
12662 }
12663 copy_length = src_size - current_offset;
12664 }
12665 else {
12666 copy_length = src_size - src_offset;
12667 }
12668 }
12669
12670 retry_copy_file_range:
12671# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12672 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12673 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12674# else
12675 ss = (ssize_t)copy_length;
12676# endif
12677 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12678 if (0 < ss) {
12679 stp->total += ss;
12680 copy_length -= ss;
12681 if (0 < copy_length) {
12682 goto retry_copy_file_range;
12683 }
12684 }
12685 if (ss < 0) {
12686 if (maygvl_copy_stream_continue_p(0, stp)) {
12687 goto retry_copy_file_range;
12688 }
12689 switch (errno) {
12690 case EINVAL:
12691 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12692 docker container) */
12693#ifdef ENOSYS
12694 case ENOSYS:
12695#endif
12696#ifdef EXDEV
12697 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12698#endif
12699 return 0;
12700 case EAGAIN:
12701#if EWOULDBLOCK != EAGAIN
12702 case EWOULDBLOCK:
12703#endif
12704 {
12705 int ret = nogvl_copy_stream_wait_write(stp);
12706 if (ret < 0) return ret;
12707 }
12708 goto retry_copy_file_range;
12709 case EBADF:
12710 {
12711 int e = errno;
12712 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12713
12714 if (flags != -1 && flags & O_APPEND) {
12715 return 0;
12716 }
12717 errno = e;
12718 }
12719 }
12720 stp->syserr = "copy_file_range";
12721 stp->error_no = errno;
12722 return (int)ss;
12723 }
12724 return 1;
12725}
12726#endif
12727
12728#ifdef HAVE_FCOPYFILE
12729static int
12730nogvl_fcopyfile(struct copy_stream_struct *stp)
12731{
12732 rb_off_t cur, ss = 0;
12733 const rb_off_t src_offset = stp->src_offset;
12734 int ret;
12735
12736 if (stp->copy_length >= (rb_off_t)0) {
12737 /* copy_length can't be specified in fcopyfile(3) */
12738 return 0;
12739 }
12740
12741 if (!S_ISREG(stp->src_stat.st_mode))
12742 return 0;
12743
12744 if (!S_ISREG(stp->dst_stat.st_mode))
12745 return 0;
12746 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12747 return 0;
12748 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12749 /* fcopyfile(3) appends src IO to dst IO and then truncates
12750 * dst IO to src IO's original size. */
12751 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12752 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12753 if (end > (rb_off_t)0) return 0;
12754 }
12755
12756 if (src_offset > (rb_off_t)0) {
12757 rb_off_t r;
12758
12759 /* get current offset */
12760 errno = 0;
12761 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12762 if (cur < (rb_off_t)0 && errno) {
12763 stp->error_no = errno;
12764 return 1;
12765 }
12766
12767 errno = 0;
12768 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12769 if (r < (rb_off_t)0 && errno) {
12770 stp->error_no = errno;
12771 return 1;
12772 }
12773 }
12774
12775 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12776 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12777 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12778
12779 if (ret == 0) { /* success */
12780 stp->total = ss;
12781 if (src_offset > (rb_off_t)0) {
12782 rb_off_t r;
12783 errno = 0;
12784 /* reset offset */
12785 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12786 if (r < (rb_off_t)0 && errno) {
12787 stp->error_no = errno;
12788 return 1;
12789 }
12790 }
12791 }
12792 else {
12793 switch (errno) {
12794 case ENOTSUP:
12795 case EPERM:
12796 case EINVAL:
12797 return 0;
12798 }
12799 stp->syserr = "fcopyfile";
12800 stp->error_no = errno;
12801 return (int)ret;
12802 }
12803 return 1;
12804}
12805#endif
12806
12807#ifdef HAVE_SENDFILE
12808
12809# ifdef __linux__
12810# define USE_SENDFILE
12811
12812# ifdef HAVE_SYS_SENDFILE_H
12813# include <sys/sendfile.h>
12814# endif
12815
12816static ssize_t
12817simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12818{
12819 return sendfile(out_fd, in_fd, offset, (size_t)count);
12820}
12821
12822# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12823/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12824 * without cpuset -l 0.
12825 */
12826# define USE_SENDFILE
12827
12828static ssize_t
12829simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12830{
12831 int r;
12832 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12833 rb_off_t sbytes;
12834# ifdef __APPLE__
12835 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12836 sbytes = count;
12837# else
12838 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12839# endif
12840 if (r != 0 && sbytes == 0) return r;
12841 if (offset) {
12842 *offset += sbytes;
12843 }
12844 else {
12845 lseek(in_fd, sbytes, SEEK_CUR);
12846 }
12847 return (ssize_t)sbytes;
12848}
12849
12850# endif
12851
12852#endif
12853
12854#ifdef USE_SENDFILE
12855static int
12856nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12857{
12858 ssize_t ss;
12859 rb_off_t src_size;
12860 rb_off_t copy_length;
12861 rb_off_t src_offset;
12862 int use_pread;
12863
12864 if (!S_ISREG(stp->src_stat.st_mode))
12865 return 0;
12866
12867 src_size = stp->src_stat.st_size;
12868#ifndef __linux__
12869 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12870 return 0;
12871#endif
12872
12873 src_offset = stp->src_offset;
12874 use_pread = src_offset >= (rb_off_t)0;
12875
12876 copy_length = stp->copy_length;
12877 if (copy_length < (rb_off_t)0) {
12878 if (use_pread)
12879 copy_length = src_size - src_offset;
12880 else {
12881 rb_off_t cur;
12882 errno = 0;
12883 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12884 if (cur < (rb_off_t)0 && errno) {
12885 stp->syserr = "lseek";
12886 stp->error_no = errno;
12887 return (int)cur;
12888 }
12889 copy_length = src_size - cur;
12890 }
12891 }
12892
12893 retry_sendfile:
12894# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12895 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12896 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12897# else
12898 ss = (ssize_t)copy_length;
12899# endif
12900 if (use_pread) {
12901 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12902 }
12903 else {
12904 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12905 }
12906 if (0 < ss) {
12907 stp->total += ss;
12908 copy_length -= ss;
12909 if (0 < copy_length) {
12910 goto retry_sendfile;
12911 }
12912 }
12913 if (ss < 0) {
12914 if (maygvl_copy_stream_continue_p(0, stp))
12915 goto retry_sendfile;
12916 switch (errno) {
12917 case EINVAL:
12918#ifdef ENOSYS
12919 case ENOSYS:
12920#endif
12921#ifdef EOPNOTSUP
12922 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12923 see also: [Feature #16965] */
12924 case EOPNOTSUP:
12925#endif
12926 return 0;
12927 case EAGAIN:
12928#if EWOULDBLOCK != EAGAIN
12929 case EWOULDBLOCK:
12930#endif
12931 {
12932 int ret;
12933#ifndef __linux__
12934 /*
12935 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12936 * select() reports regular files to always be "ready", so
12937 * there is no need to select() on it.
12938 * Other OSes may have the same limitation for sendfile() which
12939 * allow us to bypass maygvl_copy_stream_wait_read()...
12940 */
12941 ret = maygvl_copy_stream_wait_read(0, stp);
12942 if (ret < 0) return ret;
12943#endif
12944 ret = nogvl_copy_stream_wait_write(stp);
12945 if (ret < 0) return ret;
12946 }
12947 goto retry_sendfile;
12948 }
12949 stp->syserr = "sendfile";
12950 stp->error_no = errno;
12951 return (int)ss;
12952 }
12953 return 1;
12954}
12955#endif
12956
12957static ssize_t
12958maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12959{
12960 if (has_gvl)
12961 return rb_io_read_memory(fptr, buf, count);
12962 else
12963 return read(fptr->fd, buf, count);
12964}
12965
12966static ssize_t
12967maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12968{
12969 ssize_t ss;
12970 retry_read:
12971 if (offset < (rb_off_t)0) {
12972 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12973 }
12974 else {
12975 ss = pread(stp->src_fptr->fd, buf, len, offset);
12976 }
12977 if (ss == 0) {
12978 return 0;
12979 }
12980 if (ss < 0) {
12981 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12982 goto retry_read;
12983 switch (errno) {
12984 case EAGAIN:
12985#if EWOULDBLOCK != EAGAIN
12986 case EWOULDBLOCK:
12987#endif
12988 {
12989 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12990 if (ret < 0) return ret;
12991 }
12992 goto retry_read;
12993#ifdef ENOSYS
12994 case ENOSYS:
12995 stp->notimp = "pread";
12996 return ss;
12997#endif
12998 }
12999 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13000 stp->error_no = errno;
13001 }
13002 return ss;
13003}
13004
13005static int
13006nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13007{
13008 ssize_t ss;
13009 int off = 0;
13010 while (len) {
13011 ss = write(stp->dst_fptr->fd, buf+off, len);
13012 if (ss < 0) {
13013 if (maygvl_copy_stream_continue_p(0, stp))
13014 continue;
13015 if (io_again_p(errno)) {
13016 int ret = nogvl_copy_stream_wait_write(stp);
13017 if (ret < 0) return ret;
13018 continue;
13019 }
13020 stp->syserr = "write";
13021 stp->error_no = errno;
13022 return (int)ss;
13023 }
13024 off += (int)ss;
13025 len -= (int)ss;
13026 stp->total += ss;
13027 }
13028 return 0;
13029}
13030
13031static void
13032nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13033{
13034 char buf[1024*16];
13035 size_t len;
13036 ssize_t ss;
13037 int ret;
13038 rb_off_t copy_length;
13039 rb_off_t src_offset;
13040 int use_eof;
13041 int use_pread;
13042
13043 copy_length = stp->copy_length;
13044 use_eof = copy_length < (rb_off_t)0;
13045 src_offset = stp->src_offset;
13046 use_pread = src_offset >= (rb_off_t)0;
13047
13048 if (use_pread && stp->close_src) {
13049 rb_off_t r;
13050 errno = 0;
13051 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13052 if (r < (rb_off_t)0 && errno) {
13053 stp->syserr = "lseek";
13054 stp->error_no = errno;
13055 return;
13056 }
13057 src_offset = (rb_off_t)-1;
13058 use_pread = 0;
13059 }
13060
13061 while (use_eof || 0 < copy_length) {
13062 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13063 len = (size_t)copy_length;
13064 }
13065 else {
13066 len = sizeof(buf);
13067 }
13068 if (use_pread) {
13069 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13070 if (0 < ss)
13071 src_offset += ss;
13072 }
13073 else {
13074 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13075 }
13076 if (ss <= 0) /* EOF or error */
13077 return;
13078
13079 ret = nogvl_copy_stream_write(stp, buf, ss);
13080 if (ret < 0)
13081 return;
13082
13083 if (!use_eof)
13084 copy_length -= ss;
13085 }
13086}
13087
13088static void *
13089nogvl_copy_stream_func(void *arg)
13090{
13091 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13092#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13093 int ret;
13094#endif
13095
13096#ifdef USE_COPY_FILE_RANGE
13097 ret = nogvl_copy_file_range(stp);
13098 if (ret != 0)
13099 goto finish; /* error or success */
13100#endif
13101
13102#ifdef HAVE_FCOPYFILE
13103 ret = nogvl_fcopyfile(stp);
13104 if (ret != 0)
13105 goto finish; /* error or success */
13106#endif
13107
13108#ifdef USE_SENDFILE
13109 ret = nogvl_copy_stream_sendfile(stp);
13110 if (ret != 0)
13111 goto finish; /* error or success */
13112#endif
13113
13114 nogvl_copy_stream_read_write(stp);
13115
13116#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13117 finish:
13118#endif
13119 return 0;
13120}
13121
13122static VALUE
13123copy_stream_fallback_body(VALUE arg)
13124{
13125 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13126 const int buflen = 16*1024;
13127 VALUE n;
13128 VALUE buf = rb_str_buf_new(buflen);
13129 rb_off_t rest = stp->copy_length;
13130 rb_off_t off = stp->src_offset;
13131 ID read_method = id_readpartial;
13132
13133 if (!stp->src_fptr) {
13134 if (!rb_respond_to(stp->src, read_method)) {
13135 read_method = id_read;
13136 }
13137 }
13138
13139 while (1) {
13140 long numwrote;
13141 long l;
13142 if (stp->copy_length < (rb_off_t)0) {
13143 l = buflen;
13144 }
13145 else {
13146 if (rest == 0) {
13147 rb_str_resize(buf, 0);
13148 break;
13149 }
13150 l = buflen < rest ? buflen : (long)rest;
13151 }
13152 if (!stp->src_fptr) {
13153 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13154
13155 if (read_method == id_read && NIL_P(rc))
13156 break;
13157 }
13158 else {
13159 ssize_t ss;
13160 rb_str_resize(buf, buflen);
13161 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13162 rb_str_resize(buf, ss > 0 ? ss : 0);
13163 if (ss < 0)
13164 return Qnil;
13165 if (ss == 0)
13166 rb_eof_error();
13167 if (off >= (rb_off_t)0)
13168 off += ss;
13169 }
13170 n = rb_io_write(stp->dst, buf);
13171 numwrote = NUM2LONG(n);
13172 stp->total += numwrote;
13173 rest -= numwrote;
13174 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13175 break;
13176 }
13177 }
13178
13179 return Qnil;
13180}
13181
13182static VALUE
13183copy_stream_fallback(struct copy_stream_struct *stp)
13184{
13185 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13186 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13187 }
13188 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13189 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13190 rb_eEOFError, (VALUE)0);
13191 return Qnil;
13192}
13193
13194static VALUE
13195copy_stream_body(VALUE arg)
13196{
13197 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13198 VALUE src_io = stp->src, dst_io = stp->dst;
13199 const int common_oflags = 0
13200#ifdef O_NOCTTY
13201 | O_NOCTTY
13202#endif
13203 ;
13204
13205 stp->th = rb_thread_current();
13206
13207 stp->total = 0;
13208
13209 if (src_io == argf ||
13210 !(RB_TYPE_P(src_io, T_FILE) ||
13211 RB_TYPE_P(src_io, T_STRING) ||
13212 rb_respond_to(src_io, rb_intern("to_path")))) {
13213 stp->src_fptr = NULL;
13214 }
13215 else {
13216 int stat_ret;
13217 VALUE tmp_io = rb_io_check_io(src_io);
13218 if (!NIL_P(tmp_io)) {
13219 src_io = tmp_io;
13220 }
13221 else if (!RB_TYPE_P(src_io, T_FILE)) {
13222 VALUE args[2];
13223 FilePathValue(src_io);
13224 args[0] = src_io;
13225 args[1] = INT2NUM(O_RDONLY|common_oflags);
13226 src_io = rb_class_new_instance(2, args, rb_cFile);
13227 stp->src = src_io;
13228 stp->close_src = 1;
13229 }
13230 RB_IO_POINTER(src_io, stp->src_fptr);
13231 rb_io_check_byte_readable(stp->src_fptr);
13232
13233 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13234 if (stat_ret < 0) {
13235 stp->syserr = "fstat";
13236 stp->error_no = errno;
13237 return Qnil;
13238 }
13239 }
13240
13241 if (dst_io == argf ||
13242 !(RB_TYPE_P(dst_io, T_FILE) ||
13243 RB_TYPE_P(dst_io, T_STRING) ||
13244 rb_respond_to(dst_io, rb_intern("to_path")))) {
13245 stp->dst_fptr = NULL;
13246 }
13247 else {
13248 int stat_ret;
13249 VALUE tmp_io = rb_io_check_io(dst_io);
13250 if (!NIL_P(tmp_io)) {
13251 dst_io = GetWriteIO(tmp_io);
13252 }
13253 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13254 VALUE args[3];
13255 FilePathValue(dst_io);
13256 args[0] = dst_io;
13257 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13258 args[2] = INT2FIX(0666);
13259 dst_io = rb_class_new_instance(3, args, rb_cFile);
13260 stp->dst = dst_io;
13261 stp->close_dst = 1;
13262 }
13263 else {
13264 dst_io = GetWriteIO(dst_io);
13265 stp->dst = dst_io;
13266 }
13267 RB_IO_POINTER(dst_io, stp->dst_fptr);
13268 rb_io_check_writable(stp->dst_fptr);
13269
13270 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13271 if (stat_ret < 0) {
13272 stp->syserr = "fstat";
13273 stp->error_no = errno;
13274 return Qnil;
13275 }
13276 }
13277
13278#ifdef O_BINARY
13279 if (stp->src_fptr)
13280 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13281#endif
13282 if (stp->dst_fptr)
13283 io_ascii8bit_binmode(stp->dst_fptr);
13284
13285 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13286 size_t len = stp->src_fptr->rbuf.len;
13287 VALUE str;
13288 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13289 len = (size_t)stp->copy_length;
13290 }
13291 str = rb_str_buf_new(len);
13292 rb_str_resize(str,len);
13293 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13294 if (stp->dst_fptr) { /* IO or filename */
13295 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13296 rb_sys_fail_on_write(stp->dst_fptr);
13297 }
13298 else /* others such as StringIO */
13299 rb_io_write(dst_io, str);
13300 rb_str_resize(str, 0);
13301 stp->total += len;
13302 if (stp->copy_length >= (rb_off_t)0)
13303 stp->copy_length -= len;
13304 }
13305
13306 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13307 rb_raise(rb_eIOError, "flush failed");
13308 }
13309
13310 if (stp->copy_length == 0)
13311 return Qnil;
13312
13313 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13314 return copy_stream_fallback(stp);
13315 }
13316
13317 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13318 return Qnil;
13319}
13320
13321static VALUE
13322copy_stream_finalize(VALUE arg)
13323{
13324 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13325
13326#ifdef HAVE_FCOPYFILE
13327 if (stp->copyfile_state) {
13328 copyfile_state_free(stp->copyfile_state);
13329 }
13330#endif
13331
13332 if (stp->close_src) {
13333 rb_io_close_m(stp->src);
13334 }
13335 if (stp->close_dst) {
13336 rb_io_close_m(stp->dst);
13337 }
13338 if (stp->syserr) {
13339 rb_syserr_fail(stp->error_no, stp->syserr);
13340 }
13341 if (stp->notimp) {
13342 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13343 }
13344 return Qnil;
13345}
13346
13347/*
13348 * call-seq:
13349 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13350 *
13351 * Copies from the given +src+ to the given +dst+,
13352 * returning the number of bytes copied.
13353 *
13354 * - The given +src+ must be one of the following:
13355 *
13356 * - The path to a readable file, from which source data is to be read.
13357 * - An \IO-like object, opened for reading and capable of responding
13358 * to method +:readpartial+ or method +:read+.
13359 *
13360 * - The given +dst+ must be one of the following:
13361 *
13362 * - The path to a writable file, to which data is to be written.
13363 * - An \IO-like object, opened for writing and capable of responding
13364 * to method +:write+.
13365 *
13366 * The examples here use file <tt>t.txt</tt> as source:
13367 *
13368 * File.read('t.txt')
13369 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13370 * File.read('t.txt').size # => 47
13371 *
13372 * If only arguments +src+ and +dst+ are given,
13373 * the entire source stream is copied:
13374 *
13375 * # Paths.
13376 * IO.copy_stream('t.txt', 't.tmp') # => 47
13377 *
13378 * # IOs (recall that a File is also an IO).
13379 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13380 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13381 * IO.copy_stream(src_io, dst_io) # => 47
13382 * src_io.close
13383 * dst_io.close
13384 *
13385 * With argument +src_length+ a non-negative integer,
13386 * no more than that many bytes are copied:
13387 *
13388 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13389 * File.read('t.tmp') # => "First line"
13390 *
13391 * With argument +src_offset+ also given,
13392 * the source stream is read beginning at that offset:
13393 *
13394 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13395 * IO.read('t.tmp') # => "Second line"
13396 *
13397 */
13398static VALUE
13399rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13400{
13401 VALUE src, dst, length, src_offset;
13402 struct copy_stream_struct st;
13403
13404 MEMZERO(&st, struct copy_stream_struct, 1);
13405
13406 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13407
13408 st.src = src;
13409 st.dst = dst;
13410
13411 st.src_fptr = NULL;
13412 st.dst_fptr = NULL;
13413
13414 if (NIL_P(length))
13415 st.copy_length = (rb_off_t)-1;
13416 else
13417 st.copy_length = NUM2OFFT(length);
13418
13419 if (NIL_P(src_offset))
13420 st.src_offset = (rb_off_t)-1;
13421 else
13422 st.src_offset = NUM2OFFT(src_offset);
13423
13424 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13425
13426 return OFFT2NUM(st.total);
13427}
13428
13429/*
13430 * call-seq:
13431 * external_encoding -> encoding or nil
13432 *
13433 * Returns the Encoding object that represents the encoding of the stream,
13434 * or +nil+ if the stream is in write mode and no encoding is specified.
13435 *
13436 * See {Encodings}[rdoc-ref:File@Encodings].
13437 *
13438 */
13439
13440static VALUE
13441rb_io_external_encoding(VALUE io)
13442{
13443 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13444
13445 if (fptr->encs.enc2) {
13446 return rb_enc_from_encoding(fptr->encs.enc2);
13447 }
13448 if (fptr->mode & FMODE_WRITABLE) {
13449 if (fptr->encs.enc)
13450 return rb_enc_from_encoding(fptr->encs.enc);
13451 return Qnil;
13452 }
13453 return rb_enc_from_encoding(io_read_encoding(fptr));
13454}
13455
13456/*
13457 * call-seq:
13458 * internal_encoding -> encoding or nil
13459 *
13460 * Returns the Encoding object that represents the encoding of the internal string,
13461 * if conversion is specified,
13462 * or +nil+ otherwise.
13463 *
13464 * See {Encodings}[rdoc-ref:File@Encodings].
13465 *
13466 */
13467
13468static VALUE
13469rb_io_internal_encoding(VALUE io)
13470{
13471 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13472
13473 if (!fptr->encs.enc2) return Qnil;
13474 return rb_enc_from_encoding(io_read_encoding(fptr));
13475}
13476
13477/*
13478 * call-seq:
13479 * set_encoding(ext_enc) -> self
13480 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13481 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13482 *
13483 * See {Encodings}[rdoc-ref:File@Encodings].
13484 *
13485 * Argument +ext_enc+, if given, must be an Encoding object
13486 * or a String with the encoding name;
13487 * it is assigned as the encoding for the stream.
13488 *
13489 * Argument +int_enc+, if given, must be an Encoding object
13490 * or a String with the encoding name;
13491 * it is assigned as the encoding for the internal string.
13492 *
13493 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13494 * containing two colon-separated encoding names;
13495 * corresponding Encoding objects are assigned as the external
13496 * and internal encodings for the stream.
13497 *
13498 * If the external encoding of a string is binary/ASCII-8BIT,
13499 * the internal encoding of the string is set to nil, since no
13500 * transcoding is needed.
13501 *
13502 * Optional keyword arguments +enc_opts+ specify
13503 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13504 *
13505 */
13506
13507static VALUE
13508rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13509{
13510 rb_io_t *fptr;
13511 VALUE v1, v2, opt;
13512
13513 if (!RB_TYPE_P(io, T_FILE)) {
13514 return forward(io, id_set_encoding, argc, argv);
13515 }
13516
13517 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13518 GetOpenFile(io, fptr);
13519 io_encoding_set(fptr, v1, v2, opt);
13520 return io;
13521}
13522
13523void
13524rb_stdio_set_default_encoding(void)
13525{
13526 VALUE val = Qnil;
13527
13528#ifdef _WIN32
13529 if (isatty(fileno(stdin))) {
13530 rb_encoding *external = rb_locale_encoding();
13531 rb_encoding *internal = rb_default_internal_encoding();
13532 if (!internal) internal = rb_default_external_encoding();
13533 io_encoding_set(RFILE(rb_stdin)->fptr,
13534 rb_enc_from_encoding(external),
13535 rb_enc_from_encoding(internal),
13536 Qnil);
13537 }
13538 else
13539#endif
13540 rb_io_set_encoding(1, &val, rb_stdin);
13541 rb_io_set_encoding(1, &val, rb_stdout);
13542 rb_io_set_encoding(1, &val, rb_stderr);
13543}
13544
13545static inline int
13546global_argf_p(VALUE arg)
13547{
13548 return arg == argf;
13549}
13550
13551typedef VALUE (*argf_encoding_func)(VALUE io);
13552
13553static VALUE
13554argf_encoding(VALUE argf, argf_encoding_func func)
13555{
13556 if (!RTEST(ARGF.current_file)) {
13557 return rb_enc_default_external();
13558 }
13559 return func(rb_io_check_io(ARGF.current_file));
13560}
13561
13562/*
13563 * call-seq:
13564 * ARGF.external_encoding -> encoding
13565 *
13566 * Returns the external encoding for files read from ARGF as an Encoding
13567 * object. The external encoding is the encoding of the text as stored in a
13568 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13569 * represent this text within Ruby.
13570 *
13571 * To set the external encoding use ARGF.set_encoding.
13572 *
13573 * For example:
13574 *
13575 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13576 *
13577 */
13578static VALUE
13579argf_external_encoding(VALUE argf)
13580{
13581 return argf_encoding(argf, rb_io_external_encoding);
13582}
13583
13584/*
13585 * call-seq:
13586 * ARGF.internal_encoding -> encoding
13587 *
13588 * Returns the internal encoding for strings read from ARGF as an
13589 * Encoding object.
13590 *
13591 * If ARGF.set_encoding has been called with two encoding names, the second
13592 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13593 * value is returned. Failing that, if a default external encoding was
13594 * specified on the command-line, that value is used. If the encoding is
13595 * unknown, +nil+ is returned.
13596 */
13597static VALUE
13598argf_internal_encoding(VALUE argf)
13599{
13600 return argf_encoding(argf, rb_io_internal_encoding);
13601}
13602
13603/*
13604 * call-seq:
13605 * ARGF.set_encoding(ext_enc) -> ARGF
13606 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13607 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13608 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13609 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13610 *
13611 * If single argument is specified, strings read from ARGF are tagged with
13612 * the encoding specified.
13613 *
13614 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13615 * the read string is converted from the first encoding (external encoding)
13616 * to the second encoding (internal encoding), then tagged with the second
13617 * encoding.
13618 *
13619 * If two arguments are specified, they must be encoding objects or encoding
13620 * names. Again, the first specifies the external encoding; the second
13621 * specifies the internal encoding.
13622 *
13623 * If the external encoding and the internal encoding are specified, the
13624 * optional Hash argument can be used to adjust the conversion process. The
13625 * structure of this hash is explained in the String#encode documentation.
13626 *
13627 * For example:
13628 *
13629 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13630 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13631 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13632 * # to UTF-8.
13633 */
13634static VALUE
13635argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13636{
13637 rb_io_t *fptr;
13638
13639 if (!next_argv()) {
13640 rb_raise(rb_eArgError, "no stream to set encoding");
13641 }
13642 rb_io_set_encoding(argc, argv, ARGF.current_file);
13643 GetOpenFile(ARGF.current_file, fptr);
13644 ARGF.encs = fptr->encs;
13645 return argf;
13646}
13647
13648/*
13649 * call-seq:
13650 * ARGF.tell -> Integer
13651 * ARGF.pos -> Integer
13652 *
13653 * Returns the current offset (in bytes) of the current file in ARGF.
13654 *
13655 * ARGF.pos #=> 0
13656 * ARGF.gets #=> "This is line one\n"
13657 * ARGF.pos #=> 17
13658 *
13659 */
13660static VALUE
13661argf_tell(VALUE argf)
13662{
13663 if (!next_argv()) {
13664 rb_raise(rb_eArgError, "no stream to tell");
13665 }
13666 ARGF_FORWARD(0, 0);
13667 return rb_io_tell(ARGF.current_file);
13668}
13669
13670/*
13671 * call-seq:
13672 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13673 *
13674 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13675 * the value of _whence_. See IO#seek for further details.
13676 */
13677static VALUE
13678argf_seek_m(int argc, VALUE *argv, VALUE argf)
13679{
13680 if (!next_argv()) {
13681 rb_raise(rb_eArgError, "no stream to seek");
13682 }
13683 ARGF_FORWARD(argc, argv);
13684 return rb_io_seek_m(argc, argv, ARGF.current_file);
13685}
13686
13687/*
13688 * call-seq:
13689 * ARGF.pos = position -> Integer
13690 *
13691 * Seeks to the position given by _position_ (in bytes) in ARGF.
13692 *
13693 * For example:
13694 *
13695 * ARGF.pos = 17
13696 * ARGF.gets #=> "This is line two\n"
13697 */
13698static VALUE
13699argf_set_pos(VALUE argf, VALUE offset)
13700{
13701 if (!next_argv()) {
13702 rb_raise(rb_eArgError, "no stream to set position");
13703 }
13704 ARGF_FORWARD(1, &offset);
13705 return rb_io_set_pos(ARGF.current_file, offset);
13706}
13707
13708/*
13709 * call-seq:
13710 * ARGF.rewind -> 0
13711 *
13712 * Positions the current file to the beginning of input, resetting
13713 * ARGF.lineno to zero.
13714 *
13715 * ARGF.readline #=> "This is line one\n"
13716 * ARGF.rewind #=> 0
13717 * ARGF.lineno #=> 0
13718 * ARGF.readline #=> "This is line one\n"
13719 */
13720static VALUE
13721argf_rewind(VALUE argf)
13722{
13723 VALUE ret;
13724 int old_lineno;
13725
13726 if (!next_argv()) {
13727 rb_raise(rb_eArgError, "no stream to rewind");
13728 }
13729 ARGF_FORWARD(0, 0);
13730 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13731 ret = rb_io_rewind(ARGF.current_file);
13732 if (!global_argf_p(argf)) {
13733 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13734 }
13735 return ret;
13736}
13737
13738/*
13739 * call-seq:
13740 * ARGF.fileno -> integer
13741 * ARGF.to_i -> integer
13742 *
13743 * Returns an integer representing the numeric file descriptor for
13744 * the current file. Raises an ArgumentError if there isn't a current file.
13745 *
13746 * ARGF.fileno #=> 3
13747 */
13748static VALUE
13749argf_fileno(VALUE argf)
13750{
13751 if (!next_argv()) {
13752 rb_raise(rb_eArgError, "no stream");
13753 }
13754 ARGF_FORWARD(0, 0);
13755 return rb_io_fileno(ARGF.current_file);
13756}
13757
13758/*
13759 * call-seq:
13760 * ARGF.to_io -> IO
13761 *
13762 * Returns an IO object representing the current file. This will be a
13763 * File object unless the current file is a stream such as STDIN.
13764 *
13765 * For example:
13766 *
13767 * ARGF.to_io #=> #<File:glark.txt>
13768 * ARGF.to_io #=> #<IO:<STDIN>>
13769 */
13770static VALUE
13771argf_to_io(VALUE argf)
13772{
13773 next_argv();
13774 ARGF_FORWARD(0, 0);
13775 return ARGF.current_file;
13776}
13777
13778/*
13779 * call-seq:
13780 * ARGF.eof? -> true or false
13781 * ARGF.eof -> true or false
13782 *
13783 * Returns true if the current file in ARGF is at end of file, i.e. it has
13784 * no data to read. The stream must be opened for reading or an IOError
13785 * will be raised.
13786 *
13787 * $ echo "eof" | ruby argf.rb
13788 *
13789 * ARGF.eof? #=> false
13790 * 3.times { ARGF.readchar }
13791 * ARGF.eof? #=> false
13792 * ARGF.readchar #=> "\n"
13793 * ARGF.eof? #=> true
13794 */
13795
13796static VALUE
13797argf_eof(VALUE argf)
13798{
13799 next_argv();
13800 if (RTEST(ARGF.current_file)) {
13801 if (ARGF.init_p == 0) return Qtrue;
13802 next_argv();
13803 ARGF_FORWARD(0, 0);
13804 if (rb_io_eof(ARGF.current_file)) {
13805 return Qtrue;
13806 }
13807 }
13808 return Qfalse;
13809}
13810
13811/*
13812 * call-seq:
13813 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13814 *
13815 * Reads _length_ bytes from ARGF. The files named on the command line
13816 * are concatenated and treated as a single file by this method, so when
13817 * called without arguments the contents of this pseudo file are returned in
13818 * their entirety.
13819 *
13820 * _length_ must be a non-negative integer or +nil+.
13821 *
13822 * If _length_ is a positive integer, +read+ tries to read
13823 * _length_ bytes without any conversion (binary mode).
13824 * It returns +nil+ if an EOF is encountered before anything can be read.
13825 * Fewer than _length_ bytes are returned if an EOF is encountered during
13826 * the read.
13827 * In the case of an integer _length_, the resulting string is always
13828 * in ASCII-8BIT encoding.
13829 *
13830 * If _length_ is omitted or is +nil+, it reads until EOF
13831 * and the encoding conversion is applied, if applicable.
13832 * A string is returned even if EOF is encountered before any data is read.
13833 *
13834 * If _length_ is zero, it returns an empty string (<code>""</code>).
13835 *
13836 * If the optional _outbuf_ argument is present,
13837 * it must reference a String, which will receive the data.
13838 * The _outbuf_ will contain only the received data after the method call
13839 * even if it is not empty at the beginning.
13840 *
13841 * For example:
13842 *
13843 * $ echo "small" > small.txt
13844 * $ echo "large" > large.txt
13845 * $ ./glark.rb small.txt large.txt
13846 *
13847 * ARGF.read #=> "small\nlarge"
13848 * ARGF.read(200) #=> "small\nlarge"
13849 * ARGF.read(2) #=> "sm"
13850 * ARGF.read(0) #=> ""
13851 *
13852 * Note that this method behaves like the fread() function in C.
13853 * This means it retries to invoke read(2) system calls to read data
13854 * with the specified length.
13855 * If you need the behavior like a single read(2) system call,
13856 * consider ARGF#readpartial or ARGF#read_nonblock.
13857 */
13858
13859static VALUE
13860argf_read(int argc, VALUE *argv, VALUE argf)
13861{
13862 VALUE tmp, str, length;
13863 long len = 0;
13864
13865 rb_scan_args(argc, argv, "02", &length, &str);
13866 if (!NIL_P(length)) {
13867 len = NUM2LONG(argv[0]);
13868 }
13869 if (!NIL_P(str)) {
13870 StringValue(str);
13871 rb_str_resize(str,0);
13872 argv[1] = Qnil;
13873 }
13874
13875 retry:
13876 if (!next_argv()) {
13877 return str;
13878 }
13879 if (ARGF_GENERIC_INPUT_P()) {
13880 tmp = argf_forward(argc, argv, argf);
13881 }
13882 else {
13883 tmp = io_read(argc, argv, ARGF.current_file);
13884 }
13885 if (NIL_P(str)) str = tmp;
13886 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13887 if (NIL_P(tmp) || NIL_P(length)) {
13888 if (ARGF.next_p != -1) {
13889 argf_close(argf);
13890 ARGF.next_p = 1;
13891 goto retry;
13892 }
13893 }
13894 else if (argc >= 1) {
13895 long slen = RSTRING_LEN(str);
13896 if (slen < len) {
13897 argv[0] = LONG2NUM(len - slen);
13898 goto retry;
13899 }
13900 }
13901 return str;
13902}
13903
13904 struct argf_call_arg {
13905 int argc;
13906 VALUE *argv;
13907 VALUE argf;
13908};
13909
13910static VALUE
13911argf_forward_call(VALUE arg)
13912{
13913 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13914 argf_forward(p->argc, p->argv, p->argf);
13915 return Qnil;
13916}
13917
13918static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13919 int nonblock);
13920
13921/*
13922 * call-seq:
13923 * ARGF.readpartial(maxlen) -> string
13924 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13925 *
13926 * Reads at most _maxlen_ bytes from the ARGF stream.
13927 *
13928 * If the optional _outbuf_ argument is present,
13929 * it must reference a String, which will receive the data.
13930 * The _outbuf_ will contain only the received data after the method call
13931 * even if it is not empty at the beginning.
13932 *
13933 * It raises EOFError on end of ARGF stream.
13934 * Since ARGF stream is a concatenation of multiple files,
13935 * internally EOF is occur for each file.
13936 * ARGF.readpartial returns empty strings for EOFs except the last one and
13937 * raises EOFError for the last one.
13938 *
13939 */
13940
13941static VALUE
13942argf_readpartial(int argc, VALUE *argv, VALUE argf)
13943{
13944 return argf_getpartial(argc, argv, argf, Qnil, 0);
13945}
13946
13947/*
13948 * call-seq:
13949 * ARGF.read_nonblock(maxlen[, options]) -> string
13950 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13951 *
13952 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13953 */
13954
13955static VALUE
13956argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13957{
13958 VALUE opts;
13959
13960 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13961
13962 if (!NIL_P(opts))
13963 argc--;
13964
13965 return argf_getpartial(argc, argv, argf, opts, 1);
13966}
13967
13968static VALUE
13969argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13970{
13971 VALUE tmp, str, length;
13972 int no_exception;
13973
13974 rb_scan_args(argc, argv, "11", &length, &str);
13975 if (!NIL_P(str)) {
13976 StringValue(str);
13977 argv[1] = str;
13978 }
13979 no_exception = no_exception_p(opts);
13980
13981 if (!next_argv()) {
13982 if (!NIL_P(str)) {
13983 rb_str_resize(str, 0);
13984 }
13985 rb_eof_error();
13986 }
13987 if (ARGF_GENERIC_INPUT_P()) {
13988 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13989 struct argf_call_arg arg;
13990 arg.argc = argc;
13991 arg.argv = argv;
13992 arg.argf = argf;
13993 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
13994 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
13995 }
13996 else {
13997 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13998 }
13999 if (NIL_P(tmp)) {
14000 if (ARGF.next_p == -1) {
14001 return io_nonblock_eof(no_exception);
14002 }
14003 argf_close(argf);
14004 ARGF.next_p = 1;
14005 if (RARRAY_LEN(ARGF.argv) == 0) {
14006 return io_nonblock_eof(no_exception);
14007 }
14008 if (NIL_P(str))
14009 str = rb_str_new(NULL, 0);
14010 return str;
14011 }
14012 return tmp;
14013}
14014
14015/*
14016 * call-seq:
14017 * ARGF.getc -> String or nil
14018 *
14019 * Reads the next character from ARGF and returns it as a String. Returns
14020 * +nil+ at the end of the stream.
14021 *
14022 * ARGF treats the files named on the command line as a single file created
14023 * by concatenating their contents. After returning the last character of the
14024 * first file, it returns the first character of the second file, and so on.
14025 *
14026 * For example:
14027 *
14028 * $ echo "foo" > file
14029 * $ ruby argf.rb file
14030 *
14031 * ARGF.getc #=> "f"
14032 * ARGF.getc #=> "o"
14033 * ARGF.getc #=> "o"
14034 * ARGF.getc #=> "\n"
14035 * ARGF.getc #=> nil
14036 * ARGF.getc #=> nil
14037 */
14038static VALUE
14039argf_getc(VALUE argf)
14040{
14041 VALUE ch;
14042
14043 retry:
14044 if (!next_argv()) return Qnil;
14045 if (ARGF_GENERIC_INPUT_P()) {
14046 ch = forward_current(rb_intern("getc"), 0, 0);
14047 }
14048 else {
14049 ch = rb_io_getc(ARGF.current_file);
14050 }
14051 if (NIL_P(ch) && ARGF.next_p != -1) {
14052 argf_close(argf);
14053 ARGF.next_p = 1;
14054 goto retry;
14055 }
14056
14057 return ch;
14058}
14059
14060/*
14061 * call-seq:
14062 * ARGF.getbyte -> Integer or nil
14063 *
14064 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14065 * the end of the stream.
14066 *
14067 * For example:
14068 *
14069 * $ echo "foo" > file
14070 * $ ruby argf.rb file
14071 *
14072 * ARGF.getbyte #=> 102
14073 * ARGF.getbyte #=> 111
14074 * ARGF.getbyte #=> 111
14075 * ARGF.getbyte #=> 10
14076 * ARGF.getbyte #=> nil
14077 */
14078static VALUE
14079argf_getbyte(VALUE argf)
14080{
14081 VALUE ch;
14082
14083 retry:
14084 if (!next_argv()) return Qnil;
14085 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14086 ch = forward_current(rb_intern("getbyte"), 0, 0);
14087 }
14088 else {
14089 ch = rb_io_getbyte(ARGF.current_file);
14090 }
14091 if (NIL_P(ch) && ARGF.next_p != -1) {
14092 argf_close(argf);
14093 ARGF.next_p = 1;
14094 goto retry;
14095 }
14096
14097 return ch;
14098}
14099
14100/*
14101 * call-seq:
14102 * ARGF.readchar -> String or nil
14103 *
14104 * Reads the next character from ARGF and returns it as a String. Raises
14105 * an EOFError after the last character of the last file has been read.
14106 *
14107 * For example:
14108 *
14109 * $ echo "foo" > file
14110 * $ ruby argf.rb file
14111 *
14112 * ARGF.readchar #=> "f"
14113 * ARGF.readchar #=> "o"
14114 * ARGF.readchar #=> "o"
14115 * ARGF.readchar #=> "\n"
14116 * ARGF.readchar #=> end of file reached (EOFError)
14117 */
14118static VALUE
14119argf_readchar(VALUE argf)
14120{
14121 VALUE ch;
14122
14123 retry:
14124 if (!next_argv()) rb_eof_error();
14125 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14126 ch = forward_current(rb_intern("getc"), 0, 0);
14127 }
14128 else {
14129 ch = rb_io_getc(ARGF.current_file);
14130 }
14131 if (NIL_P(ch) && ARGF.next_p != -1) {
14132 argf_close(argf);
14133 ARGF.next_p = 1;
14134 goto retry;
14135 }
14136
14137 return ch;
14138}
14139
14140/*
14141 * call-seq:
14142 * ARGF.readbyte -> Integer
14143 *
14144 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14145 * an EOFError after the last byte of the last file has been read.
14146 *
14147 * For example:
14148 *
14149 * $ echo "foo" > file
14150 * $ ruby argf.rb file
14151 *
14152 * ARGF.readbyte #=> 102
14153 * ARGF.readbyte #=> 111
14154 * ARGF.readbyte #=> 111
14155 * ARGF.readbyte #=> 10
14156 * ARGF.readbyte #=> end of file reached (EOFError)
14157 */
14158static VALUE
14159argf_readbyte(VALUE argf)
14160{
14161 VALUE c;
14162
14163 NEXT_ARGF_FORWARD(0, 0);
14164 c = argf_getbyte(argf);
14165 if (NIL_P(c)) {
14166 rb_eof_error();
14167 }
14168 return c;
14169}
14170
14171#define FOREACH_ARGF() while (next_argv())
14172
14173static VALUE
14174argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14175{
14176 const VALUE current = ARGF.current_file;
14177 rb_yield_values2(argc, argv);
14178 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14179 rb_iter_break_value(Qundef);
14180 }
14181 return Qnil;
14182}
14183
14184#define ARGF_block_call(mid, argc, argv, func, argf) \
14185 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14186 func, argf, rb_keyword_given_p())
14187
14188static void
14189argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14190{
14191 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14192 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14193}
14194
14195static VALUE
14196argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14197{
14198 if (!global_argf_p(argf)) {
14199 ARGF.last_lineno = ++ARGF.lineno;
14200 }
14201 return argf_block_call_i(i, argf, argc, argv, blockarg);
14202}
14203
14204static void
14205argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14206{
14207 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14208 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14209}
14210
14211/*
14212 * call-seq:
14213 * ARGF.each(sep=$/) {|line| block } -> ARGF
14214 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14215 * ARGF.each(...) -> an_enumerator
14216 *
14217 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14218 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14219 * ARGF.each_line(...) -> an_enumerator
14220 *
14221 * Returns an enumerator which iterates over each line (separated by _sep_,
14222 * which defaults to your platform's newline character) of each file in
14223 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14224 * block, otherwise an enumerator is returned.
14225 * The optional _limit_ argument is an Integer specifying the maximum
14226 * length of each line; longer lines will be split according to this limit.
14227 *
14228 * This method allows you to treat the files supplied on the command line as
14229 * a single file consisting of the concatenation of each named file. After
14230 * the last line of the first file has been returned, the first line of the
14231 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14232 * used to determine the filename of the current line and line number of the
14233 * whole input, respectively.
14234 *
14235 * For example, the following code prints out each line of each named file
14236 * prefixed with its line number, displaying the filename once per file:
14237 *
14238 * ARGF.each_line do |line|
14239 * puts ARGF.filename if ARGF.file.lineno == 1
14240 * puts "#{ARGF.file.lineno}: #{line}"
14241 * end
14242 *
14243 * While the following code prints only the first file's name at first, and
14244 * the contents with line number counted through all named files.
14245 *
14246 * ARGF.each_line do |line|
14247 * puts ARGF.filename if ARGF.lineno == 1
14248 * puts "#{ARGF.lineno}: #{line}"
14249 * end
14250 */
14251static VALUE
14252argf_each_line(int argc, VALUE *argv, VALUE argf)
14253{
14254 RETURN_ENUMERATOR(argf, argc, argv);
14255 FOREACH_ARGF() {
14256 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14257 }
14258 return argf;
14259}
14260
14261/*
14262 * call-seq:
14263 * ARGF.each_byte {|byte| block } -> ARGF
14264 * ARGF.each_byte -> an_enumerator
14265 *
14266 * Iterates over each byte of each file in +ARGV+.
14267 * A byte is returned as an Integer in the range 0..255.
14268 *
14269 * This method allows you to treat the files supplied on the command line as
14270 * a single file consisting of the concatenation of each named file. After
14271 * the last byte of the first file has been returned, the first byte of the
14272 * second file is returned. The ARGF.filename method can be used to
14273 * determine the filename of the current byte.
14274 *
14275 * If no block is given, an enumerator is returned instead.
14276 *
14277 * For example:
14278 *
14279 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14280 *
14281 */
14282static VALUE
14283argf_each_byte(VALUE argf)
14284{
14285 RETURN_ENUMERATOR(argf, 0, 0);
14286 FOREACH_ARGF() {
14287 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14288 }
14289 return argf;
14290}
14291
14292/*
14293 * call-seq:
14294 * ARGF.each_char {|char| block } -> ARGF
14295 * ARGF.each_char -> an_enumerator
14296 *
14297 * Iterates over each character of each file in ARGF.
14298 *
14299 * This method allows you to treat the files supplied on the command line as
14300 * a single file consisting of the concatenation of each named file. After
14301 * the last character of the first file has been returned, the first
14302 * character of the second file is returned. The ARGF.filename method can
14303 * be used to determine the name of the file in which the current character
14304 * appears.
14305 *
14306 * If no block is given, an enumerator is returned instead.
14307 */
14308static VALUE
14309argf_each_char(VALUE argf)
14310{
14311 RETURN_ENUMERATOR(argf, 0, 0);
14312 FOREACH_ARGF() {
14313 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14314 }
14315 return argf;
14316}
14317
14318/*
14319 * call-seq:
14320 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14321 * ARGF.each_codepoint -> an_enumerator
14322 *
14323 * Iterates over each codepoint of each file in ARGF.
14324 *
14325 * This method allows you to treat the files supplied on the command line as
14326 * a single file consisting of the concatenation of each named file. After
14327 * the last codepoint of the first file has been returned, the first
14328 * codepoint of the second file is returned. The ARGF.filename method can
14329 * be used to determine the name of the file in which the current codepoint
14330 * appears.
14331 *
14332 * If no block is given, an enumerator is returned instead.
14333 */
14334static VALUE
14335argf_each_codepoint(VALUE argf)
14336{
14337 RETURN_ENUMERATOR(argf, 0, 0);
14338 FOREACH_ARGF() {
14339 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14340 }
14341 return argf;
14342}
14343
14344/*
14345 * call-seq:
14346 * ARGF.filename -> String
14347 * ARGF.path -> String
14348 *
14349 * Returns the current filename. "-" is returned when the current file is
14350 * STDIN.
14351 *
14352 * For example:
14353 *
14354 * $ echo "foo" > foo
14355 * $ echo "bar" > bar
14356 * $ echo "glark" > glark
14357 *
14358 * $ ruby argf.rb foo bar glark
14359 *
14360 * ARGF.filename #=> "foo"
14361 * ARGF.read(5) #=> "foo\nb"
14362 * ARGF.filename #=> "bar"
14363 * ARGF.skip
14364 * ARGF.filename #=> "glark"
14365 */
14366static VALUE
14367argf_filename(VALUE argf)
14368{
14369 next_argv();
14370 return ARGF.filename;
14371}
14372
14373static VALUE
14374argf_filename_getter(ID id, VALUE *var)
14375{
14376 return argf_filename(*var);
14377}
14378
14379/*
14380 * call-seq:
14381 * ARGF.file -> IO or File object
14382 *
14383 * Returns the current file as an IO or File object.
14384 * <code>$stdin</code> is returned when the current file is STDIN.
14385 *
14386 * For example:
14387 *
14388 * $ echo "foo" > foo
14389 * $ echo "bar" > bar
14390 *
14391 * $ ruby argf.rb foo bar
14392 *
14393 * ARGF.file #=> #<File:foo>
14394 * ARGF.read(5) #=> "foo\nb"
14395 * ARGF.file #=> #<File:bar>
14396 */
14397static VALUE
14398argf_file(VALUE argf)
14399{
14400 next_argv();
14401 return ARGF.current_file;
14402}
14403
14404/*
14405 * call-seq:
14406 * ARGF.binmode -> ARGF
14407 *
14408 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14409 * be reset to non-binary mode. This option has the following effects:
14410 *
14411 * * Newline conversion is disabled.
14412 * * Encoding conversion is disabled.
14413 * * Content is treated as ASCII-8BIT.
14414 */
14415static VALUE
14416argf_binmode_m(VALUE argf)
14417{
14418 ARGF.binmode = 1;
14419 next_argv();
14420 ARGF_FORWARD(0, 0);
14421 rb_io_ascii8bit_binmode(ARGF.current_file);
14422 return argf;
14423}
14424
14425/*
14426 * call-seq:
14427 * ARGF.binmode? -> true or false
14428 *
14429 * Returns true if ARGF is being read in binary mode; false otherwise.
14430 * To enable binary mode use ARGF.binmode.
14431 *
14432 * For example:
14433 *
14434 * ARGF.binmode? #=> false
14435 * ARGF.binmode
14436 * ARGF.binmode? #=> true
14437 */
14438static VALUE
14439argf_binmode_p(VALUE argf)
14440{
14441 return RBOOL(ARGF.binmode);
14442}
14443
14444/*
14445 * call-seq:
14446 * ARGF.skip -> ARGF
14447 *
14448 * Sets the current file to the next file in ARGV. If there aren't any more
14449 * files it has no effect.
14450 *
14451 * For example:
14452 *
14453 * $ ruby argf.rb foo bar
14454 * ARGF.filename #=> "foo"
14455 * ARGF.skip
14456 * ARGF.filename #=> "bar"
14457 */
14458static VALUE
14459argf_skip(VALUE argf)
14460{
14461 if (ARGF.init_p && ARGF.next_p == 0) {
14462 argf_close(argf);
14463 ARGF.next_p = 1;
14464 }
14465 return argf;
14466}
14467
14468/*
14469 * call-seq:
14470 * ARGF.close -> ARGF
14471 *
14472 * Closes the current file and skips to the next file in ARGV. If there are
14473 * no more files to open, just closes the current file. STDIN will not be
14474 * closed.
14475 *
14476 * For example:
14477 *
14478 * $ ruby argf.rb foo bar
14479 *
14480 * ARGF.filename #=> "foo"
14481 * ARGF.close
14482 * ARGF.filename #=> "bar"
14483 * ARGF.close
14484 */
14485static VALUE
14486argf_close_m(VALUE argf)
14487{
14488 next_argv();
14489 argf_close(argf);
14490 if (ARGF.next_p != -1) {
14491 ARGF.next_p = 1;
14492 }
14493 ARGF.lineno = 0;
14494 return argf;
14495}
14496
14497/*
14498 * call-seq:
14499 * ARGF.closed? -> true or false
14500 *
14501 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14502 * ARGF.close to actually close the current file.
14503 */
14504static VALUE
14505argf_closed(VALUE argf)
14506{
14507 next_argv();
14508 ARGF_FORWARD(0, 0);
14509 return rb_io_closed_p(ARGF.current_file);
14510}
14511
14512/*
14513 * call-seq:
14514 * ARGF.to_s -> String
14515 *
14516 * Returns "ARGF".
14517 */
14518static VALUE
14519argf_to_s(VALUE argf)
14520{
14521 return rb_str_new2("ARGF");
14522}
14523
14524/*
14525 * call-seq:
14526 * ARGF.inplace_mode -> String
14527 *
14528 * Returns the file extension appended to the names of backup copies of
14529 * modified files under in-place edit mode. This value can be set using
14530 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14531 */
14532static VALUE
14533argf_inplace_mode_get(VALUE argf)
14534{
14535 if (!ARGF.inplace) return Qnil;
14536 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14537 return rb_str_dup(ARGF.inplace);
14538}
14539
14540static VALUE
14541opt_i_get(ID id, VALUE *var)
14542{
14543 return argf_inplace_mode_get(*var);
14544}
14545
14546/*
14547 * call-seq:
14548 * ARGF.inplace_mode = ext -> ARGF
14549 *
14550 * Sets the filename extension for in-place editing mode to the given String.
14551 * The backup copy of each file being edited has this value appended to its
14552 * filename.
14553 *
14554 * For example:
14555 *
14556 * $ ruby argf.rb file.txt
14557 *
14558 * ARGF.inplace_mode = '.bak'
14559 * ARGF.each_line do |line|
14560 * print line.sub("foo","bar")
14561 * end
14562 *
14563 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14564 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14565 * "bar".
14566 */
14567static VALUE
14568argf_inplace_mode_set(VALUE argf, VALUE val)
14569{
14570 if (!RTEST(val)) {
14571 ARGF.inplace = Qfalse;
14572 }
14573 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14574 ARGF.inplace = Qnil;
14575 }
14576 else {
14577 ARGF.inplace = rb_str_new_frozen(val);
14578 }
14579 return argf;
14580}
14581
14582static void
14583opt_i_set(VALUE val, ID id, VALUE *var)
14584{
14585 argf_inplace_mode_set(*var, val);
14586}
14587
14588void
14589ruby_set_inplace_mode(const char *suffix)
14590{
14591 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14592}
14593
14594/*
14595 * call-seq:
14596 * ARGF.argv -> ARGV
14597 *
14598 * Returns the +ARGV+ array, which contains the arguments passed to your
14599 * script, one per element.
14600 *
14601 * For example:
14602 *
14603 * $ ruby argf.rb -v glark.txt
14604 *
14605 * ARGF.argv #=> ["-v", "glark.txt"]
14606 *
14607 */
14608static VALUE
14609argf_argv(VALUE argf)
14610{
14611 return ARGF.argv;
14612}
14613
14614static VALUE
14615argf_argv_getter(ID id, VALUE *var)
14616{
14617 return argf_argv(*var);
14618}
14619
14620 VALUE
14621rb_get_argv(void)
14622{
14623 return ARGF.argv;
14624}
14625
14626/*
14627 * call-seq:
14628 * ARGF.to_write_io -> io
14629 *
14630 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14631 * enabled.
14632 */
14633static VALUE
14634argf_write_io(VALUE argf)
14635{
14636 if (!RTEST(ARGF.current_file)) {
14637 rb_raise(rb_eIOError, "not opened for writing");
14638 }
14639 return GetWriteIO(ARGF.current_file);
14640}
14641
14642/*
14643 * call-seq:
14644 * ARGF.write(*objects) -> integer
14645 *
14646 * Writes each of the given +objects+ if inplace mode.
14647 */
14648static VALUE
14649argf_write(int argc, VALUE *argv, VALUE argf)
14650{
14651 return rb_io_writev(argf_write_io(argf), argc, argv);
14652}
14653
14654void
14655rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14656{
14657 rb_readwrite_syserr_fail(waiting, errno, mesg);
14658}
14659
14660void
14661rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14662{
14663 VALUE arg, c = Qnil;
14664 arg = mesg ? rb_str_new2(mesg) : Qnil;
14665 switch (waiting) {
14666 case RB_IO_WAIT_WRITABLE:
14667 switch (n) {
14668 case EAGAIN:
14669 c = rb_eEAGAINWaitWritable;
14670 break;
14671#if EAGAIN != EWOULDBLOCK
14672 case EWOULDBLOCK:
14673 c = rb_eEWOULDBLOCKWaitWritable;
14674 break;
14675#endif
14676 case EINPROGRESS:
14677 c = rb_eEINPROGRESSWaitWritable;
14678 break;
14679 default:
14680 rb_mod_syserr_fail_str(rb_mWaitWritable, n, arg);
14681 }
14682 break;
14683 case RB_IO_WAIT_READABLE:
14684 switch (n) {
14685 case EAGAIN:
14686 c = rb_eEAGAINWaitReadable;
14687 break;
14688#if EAGAIN != EWOULDBLOCK
14689 case EWOULDBLOCK:
14690 c = rb_eEWOULDBLOCKWaitReadable;
14691 break;
14692#endif
14693 case EINPROGRESS:
14694 c = rb_eEINPROGRESSWaitReadable;
14695 break;
14696 default:
14697 rb_mod_syserr_fail_str(rb_mWaitReadable, n, arg);
14698 }
14699 break;
14700 default:
14701 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14702 }
14703 rb_exc_raise(rb_class_new_instance(1, &arg, c));
14704}
14705
14706static VALUE
14707get_LAST_READ_LINE(ID _x, VALUE *_y)
14708{
14709 return rb_lastline_get();
14710}
14711
14712static void
14713set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14714{
14715 rb_lastline_set(val);
14716}
14717
14718/*
14719 * Document-class: IOError
14720 *
14721 * Raised when an IO operation fails.
14722 *
14723 * File.open("/etc/hosts") {|f| f << "example"}
14724 * #=> IOError: not opened for writing
14725 *
14726 * File.open("/etc/hosts") {|f| f.close; f.read }
14727 * #=> IOError: closed stream
14728 *
14729 * Note that some IO failures raise <code>SystemCallError</code>s
14730 * and these are not subclasses of IOError:
14731 *
14732 * File.open("does/not/exist")
14733 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14734 */
14735
14736/*
14737 * Document-class: EOFError
14738 *
14739 * Raised by some IO operations when reaching the end of file. Many IO
14740 * methods exist in two forms,
14741 *
14742 * one that returns +nil+ when the end of file is reached, the other
14743 * raises EOFError.
14744 *
14745 * EOFError is a subclass of IOError.
14746 *
14747 * file = File.open("/etc/hosts")
14748 * file.read
14749 * file.gets #=> nil
14750 * file.readline #=> EOFError: end of file reached
14751 * file.close
14752 */
14753
14754/*
14755 * Document-class: ARGF
14756 *
14757 * == \ARGF and +ARGV+
14758 *
14759 * The \ARGF object works with the array at global variable +ARGV+
14760 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14761 *
14762 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14763 *
14764 * Initially, it contains the command-line arguments and options
14765 * that are passed to the Ruby program;
14766 * the program can modify that array as it likes.
14767 *
14768 * - **ARGF** may be thought of as the <b>argument files</b> object.
14769 *
14770 * It can access file streams and/or the <tt>$stdin</tt> stream,
14771 * based on what it finds in +ARGV+.
14772 * This provides a convenient way for the command line
14773 * to specify streams for a Ruby program to read.
14774 *
14775 * == Reading
14776 *
14777 * \ARGF may read from _source_ streams,
14778 * which at any particular time are determined by the content of +ARGV+.
14779 *
14780 * === Simplest Case
14781 *
14782 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14783 * the source is <tt>$stdin</tt>:
14784 *
14785 * - \File +t.rb+:
14786 *
14787 * p ['ARGV', ARGV]
14788 * p ['ARGF.read', ARGF.read]
14789 *
14790 * - Commands and outputs
14791 * (see below for the content of files +foo.txt+ and +bar.txt+):
14792 *
14793 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14794 * ["ARGV", []]
14795 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14796 *
14797 * $ cat foo.txt bar.txt | ruby t.rb
14798 * ["ARGV", []]
14799 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14800 *
14801 * === About the Examples
14802 *
14803 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14804 *
14805 * $ cat foo.txt
14806 * Foo 0
14807 * Foo 1
14808 * $ cat bar.txt
14809 * Bar 0
14810 * Bar 1
14811 * Bar 2
14812 * Bar 3
14813 *
14814 * === Sources in +ARGV+
14815 *
14816 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14817 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14818 * the sources are found in +ARGV+.
14819 *
14820 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14821 * and is one of:
14822 *
14823 * - The string path to a file that may be opened as a stream.
14824 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14825 *
14826 * Each element that is _not_ one of these
14827 * should be removed from +ARGV+ before \ARGF accesses that source.
14828 *
14829 * In the following example:
14830 *
14831 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14832 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14833 *
14834 * Example:
14835 *
14836 * - \File +t.rb+:
14837 *
14838 * # Print arguments (and options, if any) found on command line.
14839 * p ['ARGV', ARGV]
14840 *
14841 * - Command and output:
14842 *
14843 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14844 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14845 *
14846 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14847 *
14848 * - \File +t.rb+:
14849 *
14850 * p "ARGV: #{ARGV}"
14851 * p "Line: #{ARGF.read}" # Read everything from all specified streams.
14852 *
14853 * - Command and output:
14854 *
14855 * $ ruby t.rb foo.txt bar.txt
14856 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14857 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14858 *
14859 * Because the value at +ARGV+ is an ordinary array,
14860 * you can manipulate it to control which sources \ARGF considers:
14861 *
14862 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14863 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14864 *
14865 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14866 * when all sources have been accessed, the array is empty:
14867 *
14868 * - \File +t.rb+:
14869 *
14870 * until ARGV.empty? && ARGF.eof?
14871 * p "ARGV: #{ARGV}"
14872 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14873 * end
14874 *
14875 * - Command and output:
14876 *
14877 * $ ruby t.rb foo.txt bar.txt
14878 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14879 * "Line: Foo 0\n"
14880 * "ARGV: [\"bar.txt\"]"
14881 * "Line: Foo 1\n"
14882 * "ARGV: [\"bar.txt\"]"
14883 * "Line: Bar 0\n"
14884 * "ARGV: []"
14885 * "Line: Bar 1\n"
14886 * "ARGV: []"
14887 * "Line: Bar 2\n"
14888 * "ARGV: []"
14889 * "Line: Bar 3\n"
14890 *
14891 * ==== Filepaths in +ARGV+
14892 *
14893 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14894 *
14895 * This program prints what it reads from files at the paths specified
14896 * on the command line:
14897 *
14898 * - \File +t.rb+:
14899 *
14900 * p ['ARGV', ARGV]
14901 * # Read and print all content from the specified sources.
14902 * p ['ARGF.read', ARGF.read]
14903 *
14904 * - Command and output:
14905 *
14906 * $ ruby t.rb foo.txt bar.txt
14907 * ["ARGV", [foo.txt, bar.txt]
14908 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14909 *
14910 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14911 *
14912 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14913 *
14914 * - \File +t.rb+:
14915 *
14916 * p ['ARGV', ARGV]
14917 * p ['ARGF.read', ARGF.read]
14918 *
14919 * - Command and output:
14920 *
14921 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14922 * ["ARGV", ["-"]]
14923 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14924 *
14925 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14926 * (exception:
14927 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14928 *
14929 * - Command and output:
14930 *
14931 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14932 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14933 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14934 *
14935 * ==== Mixtures and Repetitions in +ARGV+
14936 *
14937 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14938 * and character <tt>'-'</tt>, including repetitions.
14939 *
14940 * ==== Modifications to +ARGV+
14941 *
14942 * The running Ruby program may make any modifications to the +ARGV+ array;
14943 * the current value of +ARGV+ affects \ARGF reading.
14944 *
14945 * ==== Empty +ARGV+
14946 *
14947 * For an empty +ARGV+, an \ARGF read method either returns +nil+
14948 * or raises an exception, depending on the specific method.
14949 *
14950 * === More Read Methods
14951 *
14952 * As seen above, method ARGF#read reads the content of all sources
14953 * into a single string.
14954 * Other \ARGF methods provide other ways to access that content;
14955 * these include:
14956 *
14957 * - Byte access: #each_byte, #getbyte, #readbyte.
14958 * - Character access: #each_char, #getc, #readchar.
14959 * - Codepoint access: #each_codepoint.
14960 * - Line access: #each_line, #gets, #readline, #readlines.
14961 * - Source access: #read, #read_nonblock, #readpartial.
14962 *
14963 * === About \Enumerable
14964 *
14965 * \ARGF includes module Enumerable.
14966 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
14967 *
14968 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
14969 * _not_ from +ARGV+;
14970 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
14971 * not an array of the strings from +ARGV+:
14972 *
14973 * - \File +t.rb+:
14974 *
14975 * p ['ARGV', ARGV]
14976 * p ['ARGF.entries', ARGF.entries]
14977 *
14978 * - Command and output:
14979 *
14980 * $ ruby t.rb foo.txt bar.txt
14981 * ["ARGV", ["foo.txt", "bar.txt"]]
14982 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
14983 *
14984 * == Writing
14985 *
14986 * If <i>inplace mode</i> is in effect,
14987 * \ARGF may write to target streams,
14988 * which at any particular time are determined by the content of ARGV.
14989 *
14990 * Methods about inplace mode:
14991 *
14992 * - #inplace_mode
14993 * - #inplace_mode=
14994 * - #to_write_io
14995 *
14996 * Methods for writing:
14997 *
14998 * - #print
14999 * - #printf
15000 * - #putc
15001 * - #puts
15002 * - #write
15003 *
15004 */
15005
15006/*
15007 * An instance of class \IO (commonly called a _stream_)
15008 * represents an input/output stream in the underlying operating system.
15009 * \Class \IO is the basis for input and output in Ruby.
15010 *
15011 * \Class File is the only class in the Ruby core that is a subclass of \IO.
15012 * Some classes in the Ruby standard library are also subclasses of \IO;
15013 * these include TCPSocket and UDPSocket.
15014 *
15015 * The global constant ARGF (also accessible as <tt>$<</tt>)
15016 * provides an IO-like stream that allows access to all file paths
15017 * found in ARGV (or found in STDIN if ARGV is empty).
15018 * ARGF is not itself a subclass of \IO.
15019 *
15020 * \Class StringIO provides an IO-like stream that handles a String.
15021 * StringIO is not itself a subclass of \IO.
15022 *
15023 * Important objects based on \IO include:
15024 *
15025 * - $stdin.
15026 * - $stdout.
15027 * - $stderr.
15028 * - Instances of class File.
15029 *
15030 * An instance of \IO may be created using:
15031 *
15032 * - IO.new: returns a new \IO object for the given integer file descriptor.
15033 * - IO.open: passes a new \IO object to the given block.
15034 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15035 * of a newly-launched subprocess.
15036 * - Kernel#open: Returns a new \IO object connected to a given source:
15037 * stream, file, or subprocess.
15038 *
15039 * Like a File stream, an \IO stream has:
15040 *
15041 * - A read/write mode, which may be read-only, write-only, or read/write;
15042 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15043 * - A data mode, which may be text-only or binary;
15044 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15045 * - Internal and external encodings;
15046 * see {Encodings}[rdoc-ref:File@Encodings].
15047 *
15048 * And like other \IO streams, it has:
15049 *
15050 * - A position, which determines where in the stream the next
15051 * read or write is to occur;
15052 * see {Position}[rdoc-ref:IO@Position].
15053 * - A line number, which is a special, line-oriented, "position"
15054 * (different from the position mentioned above);
15055 * see {Line Number}[rdoc-ref:IO@Line+Number].
15056 *
15057 * == Extension <tt>io/console</tt>
15058 *
15059 * Extension <tt>io/console</tt> provides numerous methods
15060 * for interacting with the console;
15061 * requiring it adds numerous methods to class \IO.
15062 *
15063 * == Example Files
15064 *
15065 * Many examples here use these variables:
15066 *
15067 * :include: doc/examples/files.rdoc
15068 *
15069 * == Open Options
15070 *
15071 * A number of \IO methods accept optional keyword arguments
15072 * that determine how a new stream is to be opened:
15073 *
15074 * - +:mode+: Stream mode.
15075 * - +:flags+: Integer file open flags;
15076 * If +mode+ is also given, the two are bitwise-ORed.
15077 * - +:external_encoding+: External encoding for the stream.
15078 * - +:internal_encoding+: Internal encoding for the stream.
15079 * <tt>'-'</tt> is a synonym for the default internal encoding.
15080 * If the value is +nil+ no conversion occurs.
15081 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15082 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15083 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15084 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15085 * when the stream closes; otherwise it remains open.
15086 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15087 * #path method.
15088 *
15089 * Also available are the options offered in String#encode,
15090 * which may control conversion between external and internal encoding.
15091 *
15092 * == Basic \IO
15093 *
15094 * You can perform basic stream \IO with these methods,
15095 * which typically operate on multi-byte strings:
15096 *
15097 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15098 * - IO#write: Writes zero or more strings to the stream;
15099 * each given object that is not already a string is converted via +to_s+.
15100 *
15101 * === Position
15102 *
15103 * An \IO stream has a nonnegative integer _position_,
15104 * which is the byte offset at which the next read or write is to occur.
15105 * A new stream has position zero (and line number zero);
15106 * method +rewind+ resets the position (and line number) to zero.
15107 *
15108 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15109 * Encoding::Converter instances used for that \IO.
15110 *
15111 * The relevant methods:
15112 *
15113 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15114 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15115 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15116 * relative to a given position +whence+
15117 * (indicating the beginning, end, or current position).
15118 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15119 *
15120 * === Open and Closed Streams
15121 *
15122 * A new \IO stream may be open for reading, open for writing, or both.
15123 *
15124 * A stream is automatically closed when claimed by the garbage collector.
15125 *
15126 * Attempted reading or writing on a closed stream raises an exception.
15127 *
15128 * The relevant methods:
15129 *
15130 * - IO#close: Closes the stream for both reading and writing.
15131 * - IO#close_read: Closes the stream for reading.
15132 * - IO#close_write: Closes the stream for writing.
15133 * - IO#closed?: Returns whether the stream is closed.
15134 *
15135 * === End-of-Stream
15136 *
15137 * You can query whether a stream is positioned at its end:
15138 *
15139 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15140 *
15141 * You can reposition to end-of-stream by using method IO#seek:
15142 *
15143 * f = File.new('t.txt')
15144 * f.eof? # => false
15145 * f.seek(0, :END)
15146 * f.eof? # => true
15147 * f.close
15148 *
15149 * Or by reading all stream content (which is slower than using IO#seek):
15150 *
15151 * f.rewind
15152 * f.eof? # => false
15153 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15154 * f.eof? # => true
15155 *
15156 * == Line \IO
15157 *
15158 * \Class \IO supports line-oriented
15159 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15160 *
15161 * === Line Input
15162 *
15163 * \Class \IO supports line-oriented input for
15164 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15165 *
15166 * ==== \File Line Input
15167 *
15168 * You can read lines from a file using these methods:
15169 *
15170 * - IO.foreach: Reads each line and passes it to the given block.
15171 * - IO.readlines: Reads and returns all lines in an array.
15172 *
15173 * For each of these methods:
15174 *
15175 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15176 * - Line parsing depends on the effective <i>line separator</i>;
15177 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15178 * - The length of each returned line depends on the effective <i>line limit</i>;
15179 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15180 *
15181 * ==== Stream Line Input
15182 *
15183 * You can read lines from an \IO stream using these methods:
15184 *
15185 * - IO#each_line: Reads each remaining line, passing it to the given block.
15186 * - IO#gets: Returns the next line.
15187 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15188 * - IO#readlines: Returns all remaining lines in an array.
15189 *
15190 * For each of these methods:
15191 *
15192 * - Reading may begin mid-line,
15193 * depending on the stream's _position_;
15194 * see {Position}[rdoc-ref:IO@Position].
15195 * - Line parsing depends on the effective <i>line separator</i>;
15196 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15197 * - The length of each returned line depends on the effective <i>line limit</i>;
15198 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15199 *
15200 * ===== Line Separator
15201 *
15202 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15203 * the string that determines what is considered a line;
15204 * it is sometimes called the <i>input record separator</i>.
15205 *
15206 * The default line separator is taken from global variable <tt>$/</tt>,
15207 * whose initial value is <tt>"\n"</tt>.
15208 *
15209 * Generally, the line to be read next is all data
15210 * from the current {position}[rdoc-ref:IO@Position]
15211 * to the next line separator
15212 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15213 *
15214 * f = File.new('t.txt')
15215 * # Method gets with no sep argument returns the next line, according to $/.
15216 * f.gets # => "First line\n"
15217 * f.gets # => "Second line\n"
15218 * f.gets # => "\n"
15219 * f.gets # => "Fourth line\n"
15220 * f.gets # => "Fifth line\n"
15221 * f.close
15222 *
15223 * You can use a different line separator by passing argument +sep+:
15224 *
15225 * f = File.new('t.txt')
15226 * f.gets('l') # => "First l"
15227 * f.gets('li') # => "ine\nSecond li"
15228 * f.gets('lin') # => "ne\n\nFourth lin"
15229 * f.gets # => "e\n"
15230 * f.close
15231 *
15232 * Or by setting global variable <tt>$/</tt>:
15233 *
15234 * f = File.new('t.txt')
15235 * $/ = 'l'
15236 * f.gets # => "First l"
15237 * f.gets # => "ine\nSecond l"
15238 * f.gets # => "ine\n\nFourth l"
15239 * f.close
15240 *
15241 * ===== Special Line Separator Values
15242 *
15243 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15244 * accepts two special values for parameter +sep+:
15245 *
15246 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15247 *
15248 * f = File.new('t.txt')
15249 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15250 * f.close
15251 *
15252 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15253 * (paragraphs being separated by two consecutive line separators):
15254 *
15255 * f = File.new('t.txt')
15256 * f.gets('') # => "First line\nSecond line\n\n"
15257 * f.gets('') # => "Fourth line\nFifth line\n"
15258 * f.close
15259 *
15260 * ===== Line Limit
15261 *
15262 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15263 * uses an integer <i>line limit</i>,
15264 * which restricts the number of bytes that may be returned.
15265 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15266 * than the limit).
15267 *
15268 * The default limit value is <tt>-1</tt>;
15269 * any negative limit value means that there is no limit.
15270 *
15271 * If there is no limit, the line is determined only by +sep+.
15272 *
15273 * # Text with 1-byte characters.
15274 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15275 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15276 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15277 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15278 * # No more than one line.
15279 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15280 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15281 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15282 *
15283 * # Text with 2-byte characters, which will not be split.
15284 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15285 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15286 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15287 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15288 *
15289 * ===== Line Separator and Line Limit
15290 *
15291 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15292 *
15293 * - Returns the next line as determined by line separator +sep+.
15294 * - But returns no more bytes than are allowed by the limit +limit+.
15295 *
15296 * Example:
15297 *
15298 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15299 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15300 *
15301 * ===== Line Number
15302 *
15303 * A readable \IO stream has a non-negative integer <i>line number</i>:
15304 *
15305 * - IO#lineno: Returns the line number.
15306 * - IO#lineno=: Resets and returns the line number.
15307 *
15308 * Unless modified by a call to method IO#lineno=,
15309 * the line number is the number of lines read
15310 * by certain line-oriented methods,
15311 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15312 *
15313 * - IO.foreach: Increments the line number on each call to the block.
15314 * - IO#each_line: Increments the line number on each call to the block.
15315 * - IO#gets: Increments the line number.
15316 * - IO#readline: Increments the line number.
15317 * - IO#readlines: Increments the line number for each line read.
15318 *
15319 * A new stream is initially has line number zero (and position zero);
15320 * method +rewind+ resets the line number (and position) to zero:
15321 *
15322 * f = File.new('t.txt')
15323 * f.lineno # => 0
15324 * f.gets # => "First line\n"
15325 * f.lineno # => 1
15326 * f.rewind
15327 * f.lineno # => 0
15328 * f.close
15329 *
15330 * Reading lines from a stream usually changes its line number:
15331 *
15332 * f = File.new('t.txt', 'r')
15333 * f.lineno # => 0
15334 * f.readline # => "This is line one.\n"
15335 * f.lineno # => 1
15336 * f.readline # => "This is the second line.\n"
15337 * f.lineno # => 2
15338 * f.readline # => "Here's the third line.\n"
15339 * f.lineno # => 3
15340 * f.eof? # => true
15341 * f.close
15342 *
15343 * Iterating over lines in a stream usually changes its line number:
15344 *
15345 * File.open('t.txt') do |f|
15346 * f.each_line do |line|
15347 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15348 * end
15349 * end
15350 *
15351 * Output:
15352 *
15353 * "position=11 eof?=false lineno=1"
15354 * "position=23 eof?=false lineno=2"
15355 * "position=24 eof?=false lineno=3"
15356 * "position=36 eof?=false lineno=4"
15357 * "position=47 eof?=true lineno=5"
15358 *
15359 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15360 * the line number does not affect where the next read or write will occur:
15361 *
15362 * f = File.new('t.txt')
15363 * f.lineno = 1000
15364 * f.lineno # => 1000
15365 * f.gets # => "First line\n"
15366 * f.lineno # => 1001
15367 * f.close
15368 *
15369 * Associated with the line number is the global variable <tt>$.</tt>:
15370 *
15371 * - When a stream is opened, <tt>$.</tt> is not set;
15372 * its value is left over from previous activity in the process:
15373 *
15374 * $. = 41
15375 * f = File.new('t.txt')
15376 * $. = 41
15377 * # => 41
15378 * f.close
15379 *
15380 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15381 *
15382 * f0 = File.new('t.txt')
15383 * f1 = File.new('t.dat')
15384 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15385 * $. # => 5
15386 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15387 * $. # => 1
15388 * f0.close
15389 * f1.close
15390 *
15391 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15392 *
15393 * f = File.new('t.txt')
15394 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15395 * $. # => 5
15396 * f.rewind
15397 * f.seek(0, :SET)
15398 * $. # => 5
15399 * f.close
15400 *
15401 * === Line Output
15402 *
15403 * You can write to an \IO stream line-by-line using this method:
15404 *
15405 * - IO#puts: Writes objects to the stream.
15406 *
15407 * == Character \IO
15408 *
15409 * You can process an \IO stream character-by-character using these methods:
15410 *
15411 * - IO#getc: Reads and returns the next character from the stream.
15412 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15413 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15414 * - IO#putc: Writes a character to the stream.
15415 * - IO#each_char: Reads each remaining character in the stream,
15416 * passing the character to the given block.
15417 *
15418 * == Byte \IO
15419 *
15420 * You can process an \IO stream byte-by-byte using these methods:
15421 *
15422 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15423 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15424 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15425 * - IO#each_byte: Reads each remaining byte in the stream,
15426 * passing the byte to the given block.
15427 *
15428 * == Codepoint \IO
15429 *
15430 * You can process an \IO stream codepoint-by-codepoint:
15431 *
15432 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15433 *
15434 * == What's Here
15435 *
15436 * First, what's elsewhere. \Class \IO:
15437 *
15438 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15439 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15440 * which provides dozens of additional methods.
15441 *
15442 * Here, class \IO provides methods that are useful for:
15443 *
15444 * - {Creating}[rdoc-ref:IO@Creating]
15445 * - {Reading}[rdoc-ref:IO@Reading]
15446 * - {Writing}[rdoc-ref:IO@Writing]
15447 * - {Positioning}[rdoc-ref:IO@Positioning]
15448 * - {Iterating}[rdoc-ref:IO@Iterating]
15449 * - {Settings}[rdoc-ref:IO@Settings]
15450 * - {Querying}[rdoc-ref:IO@Querying]
15451 * - {Buffering}[rdoc-ref:IO@Buffering]
15452 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15453 * - {Other}[rdoc-ref:IO@Other]
15454 *
15455 * === Creating
15456 *
15457 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15458 * integer file descriptor.
15459 * - ::open: Creates a new \IO object.
15460 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15461 * - ::popen: Creates an \IO object to interact with a subprocess.
15462 * - ::select: Selects which given \IO instances are ready for reading,
15463 * writing, or have pending exceptions.
15464 *
15465 * === Reading
15466 *
15467 * - ::binread: Returns a binary string with all or a subset of bytes
15468 * from the given file.
15469 * - ::read: Returns a string with all or a subset of bytes from the given file.
15470 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15471 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15472 * - #getc: Returns the next character read from +self+ as a string.
15473 * - #gets: Returns the line read from +self+.
15474 * - #pread: Returns all or the next _n_ bytes read from +self+,
15475 * not updating the receiver's offset.
15476 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15477 * for a given _n_.
15478 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15479 * in non-block mode.
15480 * - #readbyte: Returns the next byte read from +self+;
15481 * same as #getbyte, but raises an exception on end-of-stream.
15482 * - #readchar: Returns the next character read from +self+;
15483 * same as #getc, but raises an exception on end-of-stream.
15484 * - #readline: Returns the next line read from +self+;
15485 * same as #getline, but raises an exception of end-of-stream.
15486 * - #readlines: Returns an array of all lines read read from +self+.
15487 * - #readpartial: Returns up to the given number of bytes from +self+.
15488 *
15489 * === Writing
15490 *
15491 * - ::binwrite: Writes the given string to the file at the given filepath,
15492 * in binary mode.
15493 * - ::write: Writes the given string to +self+.
15494 * - #<<: Appends the given string to +self+.
15495 * - #print: Prints last read line or given objects to +self+.
15496 * - #printf: Writes to +self+ based on the given format string and objects.
15497 * - #putc: Writes a character to +self+.
15498 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15499 * - #pwrite: Writes the given string at the given offset,
15500 * not updating the receiver's offset.
15501 * - #write: Writes one or more given strings to +self+.
15502 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15503 *
15504 * === Positioning
15505 *
15506 * - #lineno: Returns the current line number in +self+.
15507 * - #lineno=: Sets the line number is +self+.
15508 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15509 * - #pos=: Sets the byte offset in +self+.
15510 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15511 * - #rewind: Positions +self+ to the beginning of input.
15512 * - #seek: Sets the offset for +self+ relative to given position.
15513 *
15514 * === Iterating
15515 *
15516 * - ::foreach: Yields each line of given file to the block.
15517 * - #each (aliased as #each_line): Calls the given block
15518 * with each successive line in +self+.
15519 * - #each_byte: Calls the given block with each successive byte in +self+
15520 * as an integer.
15521 * - #each_char: Calls the given block with each successive character in +self+
15522 * as a string.
15523 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15524 * as an integer.
15525 *
15526 * === Settings
15527 *
15528 * - #autoclose=: Sets whether +self+ auto-closes.
15529 * - #binmode: Sets +self+ to binary mode.
15530 * - #close: Closes +self+.
15531 * - #close_on_exec=: Sets the close-on-exec flag.
15532 * - #close_read: Closes +self+ for reading.
15533 * - #close_write: Closes +self+ for writing.
15534 * - #set_encoding: Sets the encoding for +self+.
15535 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15536 * Unicode byte-order-mark.
15537 * - #sync=: Sets the sync-mode to the given value.
15538 *
15539 * === Querying
15540 *
15541 * - #autoclose?: Returns whether +self+ auto-closes.
15542 * - #binmode?: Returns whether +self+ is in binary mode.
15543 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15544 * - #closed?: Returns whether +self+ is closed.
15545 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15546 * - #external_encoding: Returns the external encoding object for +self+.
15547 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15548 * - #internal_encoding: Returns the internal encoding object for +self+.
15549 * - #pid: Returns the process ID of a child process associated with +self+,
15550 * if +self+ was created by ::popen.
15551 * - #stat: Returns the File::Stat object containing status information for +self+.
15552 * - #sync: Returns whether +self+ is in sync-mode.
15553 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15554 *
15555 * === Buffering
15556 *
15557 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15558 * - #flush: Flushes any buffered data within +self+ to the underlying
15559 * operating system.
15560 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15561 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15562 * - #ungetc: Prepends buffer for +self+ with given string.
15563 *
15564 * === Low-Level Access
15565 *
15566 * - ::sysopen: Opens the file given by its path,
15567 * returning the integer file descriptor.
15568 * - #advise: Announces the intention to access data from +self+ in a specific way.
15569 * - #fcntl: Passes a low-level command to the file specified
15570 * by the given file descriptor.
15571 * - #ioctl: Passes a low-level command to the device specified
15572 * by the given file descriptor.
15573 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15574 * - #sysseek: Sets the offset for +self+.
15575 * - #syswrite: Writes the given string to +self+ using a low-level write.
15576 *
15577 * === Other
15578 *
15579 * - ::copy_stream: Copies data from a source to a destination,
15580 * each of which is a filepath or an \IO-like object.
15581 * - ::try_convert: Returns a new \IO object resulting from converting
15582 * the given object.
15583 * - #inspect: Returns the string representation of +self+.
15584 *
15585 */
15586
15587void
15588Init_IO(void)
15589{
15590 VALUE rb_cARGF;
15591#ifdef __CYGWIN__
15592#include <sys/cygwin.h>
15593 static struct __cygwin_perfile pf[] =
15594 {
15595 {"", O_RDONLY | O_BINARY},
15596 {"", O_WRONLY | O_BINARY},
15597 {"", O_RDWR | O_BINARY},
15598 {"", O_APPEND | O_BINARY},
15599 {NULL, 0}
15600 };
15601 cygwin_internal(CW_PERFILE, pf);
15602#endif
15603
15604 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15605 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15606
15607 id_write = rb_intern_const("write");
15608 id_read = rb_intern_const("read");
15609 id_getc = rb_intern_const("getc");
15610 id_flush = rb_intern_const("flush");
15611 id_readpartial = rb_intern_const("readpartial");
15612 id_set_encoding = rb_intern_const("set_encoding");
15613 id_fileno = rb_intern_const("fileno");
15614
15615 rb_define_global_function("syscall", rb_f_syscall, -1);
15616
15617 rb_define_global_function("open", rb_f_open, -1);
15618 rb_define_global_function("printf", rb_f_printf, -1);
15619 rb_define_global_function("print", rb_f_print, -1);
15620 rb_define_global_function("putc", rb_f_putc, 1);
15621 rb_define_global_function("puts", rb_f_puts, -1);
15622 rb_define_global_function("gets", rb_f_gets, -1);
15623 rb_define_global_function("readline", rb_f_readline, -1);
15624 rb_define_global_function("select", rb_f_select, -1);
15625
15626 rb_define_global_function("readlines", rb_f_readlines, -1);
15627
15628 rb_define_global_function("`", rb_f_backquote, 1);
15629
15630 rb_define_global_function("p", rb_f_p, -1);
15631 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15632
15633 rb_cIO = rb_define_class("IO", rb_cObject);
15634 rb_include_module(rb_cIO, rb_mEnumerable);
15635
15636 /* Can be raised by IO operations when IO#timeout= is set. */
15637 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15638
15639 /* Readable event mask for IO#wait. */
15640 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15641 /* Writable event mask for IO#wait. */
15642 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15643 /* Priority event mask for IO#wait. */
15644 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15645
15646 /* exception to wait for reading. see IO.select. */
15647 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15648 /* exception to wait for writing. see IO.select. */
15649 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15650 /* exception to wait for reading by EAGAIN. see IO.select. */
15651 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15652 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15653 /* exception to wait for writing by EAGAIN. see IO.select. */
15654 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15655 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15656#if EAGAIN == EWOULDBLOCK
15657 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15658 /* same as IO::EAGAINWaitReadable */
15659 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15660 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15661 /* same as IO::EAGAINWaitWritable */
15662 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15663#else
15664 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15665 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15666 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15667 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15668 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15669 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15670#endif
15671 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15672 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15673 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15674 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15675 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15676 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15677
15678#if 0
15679 /* This is necessary only for forcing rdoc handle File::open */
15680 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15681#endif
15682
15683 rb_define_alloc_func(rb_cIO, io_alloc);
15684 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15685 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15686 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15687 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15688 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15689 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15690 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15691 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15692 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15693 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15694 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15695 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15696 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15697 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15698 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15699
15700 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15701
15702 rb_output_fs = Qnil;
15703 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15704
15705 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15706 rb_vm_register_global_object(rb_default_rs);
15707 rb_rs = rb_default_rs;
15708 rb_output_rs = Qnil;
15709 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15710 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15711 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15712
15713 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15714 rb_gvar_ractor_local("$_");
15715
15716 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15717 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15718
15719 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15720 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15721 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15722 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15723
15724 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15725 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15726 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15727 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15728 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15729
15730 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15731 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15732
15733 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15734 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15735
15736 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15737 rb_define_alias(rb_cIO, "to_i", "fileno");
15738 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15739
15740 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15741 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15742
15743 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15744 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15745 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15746 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15747
15748 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15749 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15750
15751 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15752
15753 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15754 rb_define_method(rb_cIO, "read", io_read, -1);
15755 rb_define_method(rb_cIO, "write", io_write_m, -1);
15756 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15757 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15758 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15759 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15760 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15761 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15762 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15763 rb_define_method(rb_cIO, "<<", rb_io_addstr, 1);
15764 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15765 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15766 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15767 /* Set I/O position from the beginning */
15768 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15769 /* Set I/O position from the current position */
15770 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15771 /* Set I/O position from the end */
15772 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15773#ifdef SEEK_DATA
15774 /* Set I/O position to the next location containing data */
15775 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15776#endif
15777#ifdef SEEK_HOLE
15778 /* Set I/O position to the next hole */
15779 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15780#endif
15781 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15782 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15783 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15784 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15785 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15786
15787 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15788 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15789
15790 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15791 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15792 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15793 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15794
15795 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15796 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15797 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15798 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15799 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15800 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15801
15802 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15803 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15804 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15805
15806 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15807 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15808
15809 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15810
15811 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15812 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15813 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15814 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15815
15816 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15817 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15818
15819 rb_define_method(rb_cIO, "wait", io_wait, -1);
15820
15821 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15822 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15823 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15824
15825 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15826 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15827 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15828 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15829
15830 rb_gvar_ractor_local("$stdin");
15831 rb_gvar_ractor_local("$stdout");
15832 rb_gvar_ractor_local("$>");
15833 rb_gvar_ractor_local("$stderr");
15834
15835 rb_global_variable(&rb_stdin);
15836 rb_stdin = rb_io_prep_stdin();
15837 rb_global_variable(&rb_stdout);
15838 rb_stdout = rb_io_prep_stdout();
15839 rb_global_variable(&rb_stderr);
15840 rb_stderr = rb_io_prep_stderr();
15841
15842 orig_stdout = rb_stdout;
15843 orig_stderr = rb_stderr;
15844
15845 /* Holds the original stdin */
15846 rb_define_global_const("STDIN", rb_stdin);
15847 /* Holds the original stdout */
15848 rb_define_global_const("STDOUT", rb_stdout);
15849 /* Holds the original stderr */
15850 rb_define_global_const("STDERR", rb_stderr);
15851
15852#if 0
15853 /* Hack to get rdoc to regard ARGF as a class: */
15854 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15855#endif
15856
15857 rb_cARGF = rb_class_new(rb_cObject);
15858 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15859 rb_define_alloc_func(rb_cARGF, argf_alloc);
15860
15861 rb_include_module(rb_cARGF, rb_mEnumerable);
15862
15863 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15864 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15865 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15866 rb_define_alias(rb_cARGF, "inspect", "to_s");
15867 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15868
15869 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15870 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15871 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15872 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15873 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15874 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15875 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15876 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15877 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15878
15879 rb_define_method(rb_cARGF, "read", argf_read, -1);
15880 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15881 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15882 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15883 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15884 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15885 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15886 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15887 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15888 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15889 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15890 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15891 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15892 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15893 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15894 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15895 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15896 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15897 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15898 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15899
15900 rb_define_method(rb_cARGF, "write", argf_write, -1);
15901 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15902 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15903 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15904 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15905
15906 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15907 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15908 rb_define_method(rb_cARGF, "file", argf_file, 0);
15909 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15910 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15911 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15912
15913 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15914 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15915
15916 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15917 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15918
15919 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15920 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15921 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15922
15923 argf = rb_class_new_instance(0, 0, rb_cARGF);
15924
15925 rb_define_readonly_variable("$<", &argf);
15926 /*
15927 * ARGF is a stream designed for use in scripts that process files given
15928 * as command-line arguments or passed in via STDIN.
15929 *
15930 * See ARGF (the class) for more details.
15931 */
15932 rb_define_global_const("ARGF", argf);
15933
15934 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15935 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15936 ARGF.filename = rb_str_new2("-");
15937
15938 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15939 rb_gvar_ractor_local("$-i");
15940
15941 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15942
15943#if defined (_WIN32) || defined(__CYGWIN__)
15944 atexit(pipe_atexit);
15945#endif
15946
15947 Init_File();
15948
15949 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15950
15951 sym_mode = ID2SYM(rb_intern_const("mode"));
15952 sym_perm = ID2SYM(rb_intern_const("perm"));
15953 sym_flags = ID2SYM(rb_intern_const("flags"));
15954 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15955 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15956 sym_encoding = ID2SYM(rb_id_encoding());
15957 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15958 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15959 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15960 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15961 sym_normal = ID2SYM(rb_intern_const("normal"));
15962 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15963 sym_random = ID2SYM(rb_intern_const("random"));
15964 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15965 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15966 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15967 sym_SET = ID2SYM(rb_intern_const("SET"));
15968 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15969 sym_END = ID2SYM(rb_intern_const("END"));
15970#ifdef SEEK_DATA
15971 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15972#endif
15973#ifdef SEEK_HOLE
15974 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15975#endif
15976 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15977 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15978}
15979
15980#include "io.rbinc"
RUBY_ASSERT
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
rb_atomic_t
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
buffer.h
ruby_strtoul
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:138
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition cxxanyargs.hpp:670
rb_define_singleton_method
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition cxxanyargs.hpp:685
rb_define_global_function
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
Definition cxxanyargs.hpp:695
rb_include_module
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1187
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:980
rb_class_new
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:359
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1012
rb_define_module_under
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1119
rb_define_alias
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2345
rb_scan_args_kw
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:2648
rb_scan_args
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:2635
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:937
rb_get_kwargs
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2424
ECONV_AFTER_OUTPUT
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
rb_str_new2
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
TYPE
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
RB_INTEGER_TYPE_P
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
ENC_CODERANGE_7BIT
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
T_FILE
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
ENC_CODERANGE_VALID
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
ECONV_UNIVERSAL_NEWLINE_DECORATOR
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
OBJ_INIT_COPY
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
ALLOC
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
T_STRING
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
Qundef
#define Qundef
Old name of RUBY_Qundef.
Definition special_consts.h:62
INT2FIX
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
rb_str_cat2
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
T_NIL
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
UNREACHABLE
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
ID2SYM
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
T_BIGNUM
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
OBJ_FREEZE
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:135
T_FIXNUM
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
FIX2UINT
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
SSIZET2NUM
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
ZALLOC
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
CLASS_OF
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
rb_ary_new4
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
ECONV_NEWLINE_DECORATOR_WRITE_MASK
#define ECONV_NEWLINE_DECORATOR_WRITE_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_WRITE_MASK.
Definition transcode.h:531
ENCODING_MAXNAMELEN
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
MBCLEN_NEEDMORE_LEN
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
ENCODING_GET
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
LONG2FIX
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
NUM2UINT
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
ALLOC_N
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
MBCLEN_CHARFOUND_LEN
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
LONG2NUM
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
rb_exc_new3
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
STRNCASECMP
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
MBCLEN_INVALID_P
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
ISASCII
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
ECONV_STATEFUL_DECORATOR_MASK
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
Qtrue
#define Qtrue
Old name of RUBY_Qtrue.
Definition special_consts.h:61
MBCLEN_NEEDMORE_P
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
ECONV_PARTIAL_INPUT
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
NUM2INT
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
ECONV_ERROR_HANDLER_MASK
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
INT2NUM
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
Qnil
#define Qnil
Old name of RUBY_Qnil.
Definition special_consts.h:60
Qfalse
#define Qfalse
Old name of RUBY_Qfalse.
Definition special_consts.h:59
FIX2LONG
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
ENC_CODERANGE_BROKEN
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
T_ARRAY
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
NIL_P
#define NIL_P
Old name of RB_NIL_P.
Definition special_consts.h:55
ALLOCV_N
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
MBCLEN_CHARFOUND_P
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
ECONV_NEWLINE_DECORATOR_READ_MASK
#define ECONV_NEWLINE_DECORATOR_READ_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_READ_MASK.
Definition transcode.h:530
NUM2CHR
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
NUM2LONG
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
UINT2NUM
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
FIXNUM_P
#define FIXNUM_P
Old name of RB_FIXNUM_P.
Definition special_consts.h:53
ECONV_NEWLINE_DECORATOR_MASK
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
CONST_ID
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
rb_ary_new2
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
NUM2SIZET
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
ENC_CODERANGE_SET
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
rb_str_new4
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1677
ALLOCV_END
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
SYMBOL_P
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
ECONV_DEFAULT_NEWLINE_DECORATOR
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
rb_notimplement
void rb_notimplement(void)
Definition error.c:3808
rb_category_warn
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
rb_category_warning
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:508
rb_eNotImpError
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
rb_syserr_fail
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3877
rb_readwrite_syserr_fail
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:14661
rb_eIOError
VALUE rb_eIOError
IOError exception.
Definition io.c:189
rb_eStandardError
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
rb_mod_syserr_fail_str
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:3967
rb_syserr_fail_str
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:3883
ruby_verbose
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
rb_eTypeError
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
rb_eEOFError
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
rb_readwrite_sys_fail
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14655
rb_iter_break_value
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2091
rb_io_wait_readwrite
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
rb_eRuntimeError
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
rb_warn
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
rb_eSystemCallError
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1450
RB_WARN_CATEGORY_DEPRECATED
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
rb_mKernel
VALUE rb_mKernel
Kernel module.
Definition object.c:65
rb_check_to_int
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3198
rb_any_to_s
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:669
rb_obj_alloc
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2097
rb_class_new_instance
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2138
rb_cIO
VALUE rb_cIO
IO class.
Definition io.c:187
rb_class_new_instance_kw
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:2126
rb_mEnumerable
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
rb_stdin
VALUE rb_stdin
STDIN constant.
Definition io.c:201
rb_stderr
VALUE rb_stderr
STDERR constant.
Definition io.c:201
rb_obj_class
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:247
rb_obj_dup
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:576
rb_inspect
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:680
rb_mWaitReadable
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:191
rb_mWaitWritable
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:192
rb_obj_freeze
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1260
rb_check_to_integer
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:3179
rb_cFile
VALUE rb_cFile
File class.
Definition file.c:175
rb_stdout
VALUE rb_stdout
STDOUT constant.
Definition io.c:201
rb_to_int
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3192
rb_enc_codepoint
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
rb_str_conv_enc
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1285
rb_enc_uint_chr
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3803
rb_str_coderange_scan_restartable
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:784
rb_econv_prepare_options
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:2600
rb_econv_open_exc
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:2097
rb_econv_convert
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:1475
rb_econv_result_t
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
econv_incomplete_input
@ 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
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
econv_undefined_conversion
@ 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
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
econv_destination_buffer_full
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
econv_invalid_byte_sequence
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
rb_econv_putbackable
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1770
rb_econv_asciicompat_encoding
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1814
rb_econv_str_convert
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:1931
rb_econv_open_opts
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:2651
rb_econv_binmode
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:1996
rb_str_encode
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:2914
rb_econv_make_exception
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4272
rb_econv_check_error
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4278
rb_econv_close
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1731
rb_econv_putback
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1781
rb_funcall
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1099
rb_funcallv_kw
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:1066
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:239
rb_check_arity
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
rb_io_printf
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8601
rb_io_gets
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4297
rb_cloexec_pipe
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:427
rb_io_print
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:8727
rb_io_addstr
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2344
rb_write_error
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9156
rb_io_ungetbyte
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:5166
rb_io_getbyte
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5072
rb_cloexec_dup2
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:374
rb_io_fdopen
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:9332
rb_update_max_fd
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:248
rb_cloexec_open
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:328
rb_output_rs
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:206
rb_io_eof
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2689
rb_write_error2
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:9136
rb_close_before_exec
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
rb_reserved_fd_p
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
rb_fd_fix_cloexec
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:298
rb_io_ascii8bit_binmode
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6378
rb_io_binmode
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6332
rb_io_ungetc
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5230
rb_pipe
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7379
rb_gets
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10401
rb_cloexec_fcntl_dupfd
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:461
rb_file_open_str
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:7262
rb_cloexec_dup
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:367
rb_file_open
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7269
rb_io_close
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5752
rb_default_rs
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:207
rb_lastline_set
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:1853
rb_lastline_get
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1847
rb_obj_method_arity
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:2936
rb_waitpid
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1271
rb_last_status_set
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:682
rb_str_append
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:3676
rb_str_new
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
rb_str_buf_cat
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
rb_usascii_str_new
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1532
rb_str_capacity
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:954
rb_str_new_frozen
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1461
rb_str_dup
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1916
rb_str_cat
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3444
rb_str_locktmp
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_str_setter
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
rb_str_set_len
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3268
rb_str_buf_cat_ascii
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:3618
rb_check_string_type
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2850
rb_str_substr
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3148
rb_str_unlocktmp
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3251
rb_str_modify_expand
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:2648
rb_str_buf_new
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1643
rb_str_new_cstr
#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:1514
rb_thread_interrupted
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1451
rb_mutex_new
VALUE rb_mutex_new(void)
Creates a mutex.
Definition thread_sync.c:191
rb_thread_fd_writable
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:1597
rb_exec_recursive
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
Definition thread.c:5332
rb_thread_fd_close
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
Definition thread.c:2707
rb_mutex_synchronize
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.
Definition thread_sync.c:640
rb_thread_check_ints
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1434
rb_thread_current
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:2984
rb_thread_wait_fd
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1591
rb_thread_sleep
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1457
rb_time_interval
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2892
rb_set_class_path
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:353
rb_ivar_set
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:1871
rb_class_name
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:412
rb_respond_to
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:2960
rb_check_funcall
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:668
rb_define_alloc_func
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
rb_intern_const
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
RB_ID2SYM
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
rb_define_global_const
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:3743
rb_define_readonly_variable
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:744
rb_gvar_readonly_setter
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
rb_define_const
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition variable.c:3729
io.h
FMODE_READABLE
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:270
rb_io_modestr_fmode
int 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:6464
rb_io_get_io
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:811
rb_io_timeout
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:857
rb_io_taint_check
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:781
rb_io_read_check
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1069
rb_io_modestr_oflags
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:6597
FMODE_SETENC_BY_BOM
#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:368
rb_io_mode
int rb_io_mode(VALUE io)
Get the mode of the IO.
Definition io.c:2912
rb_io_event
rb_io_event
Type of events that an IO can wait.
Definition io.h:81
RUBY_IO_READABLE
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:82
RUBY_IO_PRIORITY
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:84
RUBY_IO_WRITABLE
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:83
FMODE_READWRITE
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:276
FMODE_EXTERNAL
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:360
GetOpenFile
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:402
rb_io_check_byte_readable
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:1015
FMODE_TTY
#define FMODE_TTY
The IO is a TTY.
Definition io.h:300
FMODE_CREATE
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:323
rb_io_check_readable
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1024
rb_io_extract_encoding_option
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:6746
rb_io_oflags_fmode
int rb_io_oflags_fmode(int oflags)
Converts an oflags (that rb_io_modestr_oflags() returns) to a fmode (that rb_io_mode_flags() returns)...
Definition io.c:6521
rb_wait_for_single_fd
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:1585
rb_fdopen
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:7079
rb_io_descriptor
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2892
FMODE_WRITABLE
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:273
rb_io_stdio_file
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:9378
FMODE_APPEND
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:315
MakeOpenFile
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:425
FMODE_DUPLEX
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:308
FMODE_BINMODE
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:287
rb_io_maybe_wait_readable
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:1644
capa
int capa
Designed capacity of the buffer.
Definition io.h:11
RB_IO_POINTER
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:396
rb_io_maybe_wait
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:1603
rb_eIOTimeoutError
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
FMODE_SYNC
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:294
off
int off
Offset inside of ptr.
Definition io.h:5
rb_io_path
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:2966
rb_io_check_initialized
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:788
FMODE_EXCL
#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:331
FMODE_TEXTMODE
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:351
rb_io_check_io
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:817
rb_io_closed_p
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5860
rb_io_buffer_t
struct rb_io_internal_buffer rb_io_buffer_t
Just another name of rb_io_buffer_t.
Definition io.h:110
rb_io_set_timeout
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:886
rb_io_bufwrite
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2009
rb_io_check_char_readable
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:996
FMODE_TRUNC
#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:337
rb_io_read_pending
int rb_io_read_pending(rb_io_t *fptr)
Queries if the passed IO has any pending reads.
Definition io.c:1060
rb_io_get_write_io
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:823
rb_io_set_nonblock
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3418
rb_io_extract_modeenc
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *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:6871
rb_io_wait_writable
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1542
rb_io_open_descriptor
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:9249
rb_io_set_write_io
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:834
rb_io_check_writable
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1048
rb_io_maybe_wait_writable
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:1659
rb_io_check_closed
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:796
rb_eof_error
void rb_eof_error(void)
Utility function to raise rb_eEOFError.
Definition io.c:775
rb_io_wait_readable
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1508
rb_io_synchronized
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7366
rb_io_wait
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1447
len
int len
Length of the buffer.
Definition io.h:8
ractor.h
rb_ractor_stdin
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:2737
rb_ractor_stderr_set
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:2797
rb_ractor_stdout_set
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:2785
rb_ractor_stdin_set
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:2773
thread.h
rb_thread_call_with_gvl
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:1904
util.h
RB_NUM2INT
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
RB_INT2NUM
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
rb_f_sprintf
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:209
RB_BLOCK_CALL_FUNC_ARGLIST
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
rb_yield_values2
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:1388
rb_yield
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1354
rb_fd_term
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
MEMZERO
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
RB_GC_GUARD
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
MEMMOVE
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
NUM2MODET
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
ruby::backward::cxxanyargs::rb_define_hooked_variable
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
Definition cxxanyargs.hpp:136
ruby::backward::cxxanyargs::rb_define_virtual_variable
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
Definition cxxanyargs.hpp:73
ruby::backward::cxxanyargs::rb_rescue2
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
Definition cxxanyargs.hpp:284
ruby::backward::cxxanyargs::rb_ensure
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
Definition cxxanyargs.hpp:310
PRI_OFFT_PREFIX
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
OFFT2NUM
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
NUM2OFFT
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
PIDT2NUM
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
rb_fd_isset
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
rb_fd_select
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
rb_fd_init
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
rb_fd_set
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
RARRAY_LEN
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
RARRAY_LENINT
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition rarray.h:403
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
RFILE
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
StringValue
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
RSTRING_END
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:442
RSTRING_GETMEM
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:488
StringValueCStr
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
RUBY_TYPED_DEFAULT_FREE
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:79
rb_data_type_t
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:197
TypedData_Make_Struct
#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:497
rb_get_argv
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14621
rb_p
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9035
FilePathValue
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
errno
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
RB_SCAN_ARGS_LAST_HASH_KEYWORDS
#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
RB_PASS_CALLED_KEYWORDS
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
scheduler.h
Scheduler APIs.
rb_fiber_scheduler_current
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:228
rb_fiber_scheduler_io_pread_memory
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:632
rb_fiber_scheduler_make_timeout
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:271
rb_fiber_scheduler_io_wait_readable
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:444
rb_fiber_scheduler_io_read_memory
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:608
rb_fiber_scheduler_io_wait
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:438
rb_fiber_scheduler_io_result_apply
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:70
rb_fiber_scheduler_io_selectv
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:474
rb_fiber_scheduler_io_pwrite_memory
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:644
rb_fiber_scheduler_current_for_thread
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:233
rb_fiber_scheduler_io_write_memory
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:620
rb_fiber_scheduler_io_wait_writable
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:450
rb_thread_fd_select
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:4335
RB_TEST
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
Definition special_consts.h:138
RUBY_Qfalse
@ RUBY_Qfalse
Definition special_consts.h:88
RTEST
#define RTEST
This is an old name of RB_TEST.
Definition special_consts.h:51
_
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
stdbool.h
C99 shim for <stdbool.h>
RFile
Ruby's File and IO.
Definition rfile.h:35
argf_call_arg
Definition io.c:13904
argf
Definition io.c:236
binwrite_arg
Definition io.c:1729
bufread_arg
Definition io.c:3086
copy_stream_struct
Definition io.c:12436
fiber_scheduler_wait_for_arguments
Definition io.c:12490
finish_writeconv_arg
Definition io.c:5460
foreach_arg
Definition io.c:11949
getline_arg
Definition io.c:4064
io_encoding_set_args
Definition io.c:11763
io_internal_read_struct
Definition io.c:1124
io_internal_write_struct
Definition io.c:1135
iovec
Definition win32.h:219
pipe_list
Definition io.c:7275
prdwr_internal_arg
Definition io.c:6158
rb_execarg
Definition process.h:30
rb_fdset_t
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
rb_global_variable
Definition variable.c:439
rb_io_close_wait_list
Definition thread.h:60
rb_io_encoding
Decomposed encoding flags (e.g.
Definition io.h:119
rb_io_encoding::ecflags
int ecflags
Flags.
Definition io.h:129
rb_io_encoding::ecopts
VALUE ecopts
Flags as Ruby hash.
Definition io.h:137
rb_io_encoding::enc2
rb_encoding * enc2
External encoding.
Definition io.h:123
rb_io_encoding::enc
rb_encoding * enc
Internal encoding.
Definition io.h:121
rb_io_internal_buffer
IO buffers.
Definition io.h:94
rb_io_internal_buffer::ptr
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:97
rb_io_internal_buffer::off
int off
Offset inside of ptr.
Definition io.h:100
rb_io_internal_buffer::len
int len
Length of the buffer.
Definition io.h:103
rb_io_internal_buffer::capa
int capa
Designed capacity of the buffer.
Definition io.h:106
rb_io
Ruby's IO, metadata and buffers.
Definition io.h:143
rb_io::mode
int mode
mode flags: FMODE_XXXs
Definition io.h:158
rb_io::wbuf
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:178
rb_io::finalize
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:174
rb_io::readconv
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:200
rb_io::writeconv
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:211
rb_io::encs
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:196
rb_io::self
VALUE self
The IO's Ruby level counterpart.
Definition io.h:146
rb_io::write_lock
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:248
rb_io::timeout
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:254
rb_io::stdio_file
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:150
rb_io::writeconv_pre_ecopts
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:238
rb_io::tied_io_for_writing
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:193
rb_io::writeconv_initialized
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:224
rb_io::fd
int fd
file descriptor.
Definition io.h:154
rb_io::rbuf
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:185
rb_io::lineno
int lineno
number of lines read
Definition io.h:166
rb_io::writeconv_asciicompat
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:220
rb_io::cbuf
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:207
rb_io::pid
rb_pid_t pid
child's pid (for pipes)
Definition io.h:162
rb_io::writeconv_pre_ecflags
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:231
rb_io::pathv
VALUE pathv
pathname for file
Definition io.h:170
seek_arg
Definition io.c:12178
select_args
Definition io.c:10770
sysopen_struct
Definition io.c:7016
timeval
Definition missing.h:63
write_arg
Definition io.c:1735
SIGNED_VALUE
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
ID
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
RB_SYMBOL_P
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:307
Check_Type
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:433
RB_TYPE_P
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