Ruby: io.c Source File

Ruby 3.4.4p34 (2025-05-14 revision a38531fd3f617bf734ef7d6c595325f69985ea1d)

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 // If there was an error BEFORE we started waiting, return it:
1185 if (error) {
1186 errno = error;
1187 return -1;
1188 } else {
1189 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1190 return ready;
1191 }
1192}
1193
1194static VALUE
1195internal_read_func(void *ptr)
1196{
1197 struct io_internal_read_struct *iis = ptr;
1198 ssize_t result;
1199
1200 if (iis->timeout && !iis->nonblock) {
1201 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1202 return -1;
1203 }
1204 }
1205
1206 retry:
1207 result = read(iis->fd, iis->buf, iis->capa);
1208
1209 if (result < 0 && !iis->nonblock) {
1210 if (io_again_p(errno)) {
1211 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1212 return -1;
1213 }
1214 else {
1215 goto retry;
1216 }
1217 }
1218 }
1219
1220 return result;
1221}
1222
1223#if defined __APPLE__
1224# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1225#else
1226# define do_write_retry(code) result = code
1227#endif
1228
1229static VALUE
1230internal_write_func(void *ptr)
1231{
1232 struct io_internal_write_struct *iis = ptr;
1233 ssize_t result;
1234
1235 if (iis->timeout && !iis->nonblock) {
1236 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1237 return -1;
1238 }
1239 }
1240
1241 retry:
1242 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1243
1244 if (result < 0 && !iis->nonblock) {
1245 int e = errno;
1246 if (io_again_p(e)) {
1247 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1248 return -1;
1249 }
1250 else {
1251 goto retry;
1252 }
1253 }
1254 }
1255
1256 return result;
1257}
1258
1259#ifdef HAVE_WRITEV
1260static VALUE
1261internal_writev_func(void *ptr)
1262{
1263 struct io_internal_writev_struct *iis = ptr;
1264 ssize_t result;
1265
1266 if (iis->timeout && !iis->nonblock) {
1267 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1268 return -1;
1269 }
1270 }
1271
1272 retry:
1273 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1274
1275 if (result < 0 && !iis->nonblock) {
1276 if (io_again_p(errno)) {
1277 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1278 return -1;
1279 }
1280 else {
1281 goto retry;
1282 }
1283 }
1284 }
1285
1286 return result;
1287}
1288#endif
1289
1290static ssize_t
1291rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1292{
1293 VALUE scheduler = rb_fiber_scheduler_current();
1294 if (scheduler != Qnil) {
1295 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1296
1297 if (!UNDEF_P(result)) {
1298 return rb_fiber_scheduler_io_result_apply(result);
1299 }
1300 }
1301
1302 struct io_internal_read_struct iis = {
1303 .th = rb_thread_current(),
1304 .fptr = fptr,
1305 .nonblock = 0,
1306 .fd = fptr->fd,
1307
1308 .buf = buf,
1309 .capa = count,
1310 .timeout = NULL,
1311 };
1312
1313 struct timeval timeout_storage;
1314
1315 if (fptr->timeout != Qnil) {
1316 timeout_storage = rb_time_interval(fptr->timeout);
1317 iis.timeout = &timeout_storage;
1318 }
1319
1320 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1321}
1322
1323static ssize_t
1324rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1325{
1326 VALUE scheduler = rb_fiber_scheduler_current();
1327 if (scheduler != Qnil) {
1328 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1329
1330 if (!UNDEF_P(result)) {
1331 return rb_fiber_scheduler_io_result_apply(result);
1332 }
1333 }
1334
1335 struct io_internal_write_struct iis = {
1336 .th = rb_thread_current(),
1337 .fptr = fptr,
1338 .nonblock = 0,
1339 .fd = fptr->fd,
1340
1341 .buf = buf,
1342 .capa = count,
1343 .timeout = NULL
1344 };
1345
1346 struct timeval timeout_storage;
1347
1348 if (fptr->timeout != Qnil) {
1349 timeout_storage = rb_time_interval(fptr->timeout);
1350 iis.timeout = &timeout_storage;
1351 }
1352
1353 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1354}
1355
1356#ifdef HAVE_WRITEV
1357static ssize_t
1358rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1359{
1360 if (!iovcnt) return 0;
1361
1362 VALUE scheduler = rb_fiber_scheduler_current();
1363 if (scheduler != Qnil) {
1364 // This path assumes at least one `iov`:
1365 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1366
1367 if (!UNDEF_P(result)) {
1368 return rb_fiber_scheduler_io_result_apply(result);
1369 }
1370 }
1371
1372 struct io_internal_writev_struct iis = {
1373 .th = rb_thread_current(),
1374 .fptr = fptr,
1375 .nonblock = 0,
1376 .fd = fptr->fd,
1377
1378 .iov = iov,
1379 .iovcnt = iovcnt,
1380 .timeout = NULL
1381 };
1382
1383 struct timeval timeout_storage;
1384
1385 if (fptr->timeout != Qnil) {
1386 timeout_storage = rb_time_interval(fptr->timeout);
1387 iis.timeout = &timeout_storage;
1388 }
1389
1390 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1391}
1392#endif
1393
1394static VALUE
1395io_flush_buffer_sync(void *arg)
1396{
1397 rb_io_t *fptr = arg;
1398 long l = fptr->wbuf.len;
1399 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1400
1401 if (fptr->wbuf.len <= r) {
1402 fptr->wbuf.off = 0;
1403 fptr->wbuf.len = 0;
1404 return 0;
1405 }
1406
1407 if (0 <= r) {
1408 fptr->wbuf.off += (int)r;
1409 fptr->wbuf.len -= (int)r;
1410 errno = EAGAIN;
1411 }
1412
1413 return (VALUE)-1;
1414}
1415
1416static VALUE
1417io_flush_buffer_async(VALUE arg)
1418{
1419 rb_io_t *fptr = (rb_io_t *)arg;
1420 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1421}
1422
1423static inline int
1424io_flush_buffer(rb_io_t *fptr)
1425{
1426 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1427 return (int)io_flush_buffer_async((VALUE)fptr);
1428 }
1429 else {
1430 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1431 }
1432}
1433
1434static int
1435io_fflush(rb_io_t *fptr)
1436{
1437 rb_io_check_closed(fptr);
1438
1439 if (fptr->wbuf.len == 0)
1440 return 0;
1441
1442 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1443 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1444 return -1;
1445
1446 rb_io_check_closed(fptr);
1447 }
1448
1449 return 0;
1450}
1451
1452 VALUE
1453rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1454{
1455 VALUE scheduler = rb_fiber_scheduler_current();
1456
1457 if (scheduler != Qnil) {
1458 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1459 }
1460
1461 rb_io_t * fptr = NULL;
1462 RB_IO_POINTER(io, fptr);
1463
1464 struct timeval tv_storage;
1465 struct timeval *tv = NULL;
1466
1467 if (NIL_OR_UNDEF_P(timeout)) {
1468 timeout = fptr->timeout;
1469 }
1470
1471 if (timeout != Qnil) {
1472 tv_storage = rb_time_interval(timeout);
1473 tv = &tv_storage;
1474 }
1475
1476 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1477
1478 if (ready < 0) {
1479 rb_sys_fail(0);
1480 }
1481
1482 // Not sure if this is necessary:
1483 rb_io_check_closed(fptr);
1484
1485 if (ready) {
1486 return RB_INT2NUM(ready);
1487 }
1488 else {
1489 return Qfalse;
1490 }
1491}
1492
1493static VALUE
1494io_from_fd(int fd)
1495{
1496 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1497}
1498
1499static int
1500io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1501{
1502 VALUE scheduler = rb_fiber_scheduler_current();
1503
1504 if (scheduler != Qnil) {
1505 return RTEST(
1506 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1507 );
1508 }
1509
1510 return rb_thread_wait_for_single_fd(fd, events, timeout);
1511}
1512
1513int
1514rb_io_wait_readable(int f)
1515{
1516 io_fd_check_closed(f);
1517
1518 VALUE scheduler = rb_fiber_scheduler_current();
1519
1520 switch (errno) {
1521 case EINTR:
1522#if defined(ERESTART)
1523 case ERESTART:
1524#endif
1525 rb_thread_check_ints();
1526 return TRUE;
1527
1528 case EAGAIN:
1529#if EWOULDBLOCK != EAGAIN
1530 case EWOULDBLOCK:
1531#endif
1532 if (scheduler != Qnil) {
1533 return RTEST(
1534 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1535 );
1536 }
1537 else {
1538 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1539 }
1540 return TRUE;
1541
1542 default:
1543 return FALSE;
1544 }
1545}
1546
1547int
1548rb_io_wait_writable(int f)
1549{
1550 io_fd_check_closed(f);
1551
1552 VALUE scheduler = rb_fiber_scheduler_current();
1553
1554 switch (errno) {
1555 case EINTR:
1556#if defined(ERESTART)
1557 case ERESTART:
1558#endif
1559 /*
1560 * In old Linux, several special files under /proc and /sys don't handle
1561 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1562 * Otherwise, we face nasty hang up. Sigh.
1563 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1564 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1565 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1566 * Then rb_thread_check_ints() is enough.
1567 */
1568 rb_thread_check_ints();
1569 return TRUE;
1570
1571 case EAGAIN:
1572#if EWOULDBLOCK != EAGAIN
1573 case EWOULDBLOCK:
1574#endif
1575 if (scheduler != Qnil) {
1576 return RTEST(
1577 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1578 );
1579 }
1580 else {
1581 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1582 }
1583 return TRUE;
1584
1585 default:
1586 return FALSE;
1587 }
1588}
1589
1590int
1591rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1592{
1593 return io_wait_for_single_fd(fd, events, timeout);
1594}
1595
1596int
1597rb_thread_wait_fd(int fd)
1598{
1599 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1600}
1601
1602int
1603rb_thread_fd_writable(int fd)
1604{
1605 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1606}
1607
1608 VALUE
1609rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1610{
1611 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1612 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1613 // instead relies on `read(-1) -> -1` which causes this code path. We then
1614 // check here whether the IO was in fact closed. Probably it's better to
1615 // check that `fptr->fd != -1` before using it in syscall.
1616 rb_io_check_closed(RFILE(io)->fptr);
1617
1618 switch (error) {
1619 // In old Linux, several special files under /proc and /sys don't handle
1620 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1621 // Otherwise, we face nasty hang up. Sigh.
1622 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1623 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1624 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1625 // Then rb_thread_check_ints() is enough.
1626 case EINTR:
1627#if defined(ERESTART)
1628 case ERESTART:
1629#endif
1630 // We might have pending interrupts since the previous syscall was interrupted:
1631 rb_thread_check_ints();
1632
1633 // The operation was interrupted, so retry it immediately:
1634 return events;
1635
1636 case EAGAIN:
1637#if EWOULDBLOCK != EAGAIN
1638 case EWOULDBLOCK:
1639#endif
1640 // The operation would block, so wait for the specified events:
1641 return rb_io_wait(io, events, timeout);
1642
1643 default:
1644 // Non-specific error, no event is ready:
1645 return Qnil;
1646 }
1647}
1648
1649int
1650rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
1651{
1652 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1653
1654 if (RTEST(result)) {
1655 return RB_NUM2INT(result);
1656 }
1657 else if (result == RUBY_Qfalse) {
1658 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1659 }
1660
1661 return 0;
1662}
1663
1664int
1665rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
1666{
1667 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1668
1669 if (RTEST(result)) {
1670 return RB_NUM2INT(result);
1671 }
1672 else if (result == RUBY_Qfalse) {
1673 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1674 }
1675
1676 return 0;
1677}
1678
1679static void
1680make_writeconv(rb_io_t *fptr)
1681{
1682 if (!fptr->writeconv_initialized) {
1683 const char *senc, *denc;
1684 rb_encoding *enc;
1685 int ecflags;
1686 VALUE ecopts;
1687
1688 fptr->writeconv_initialized = 1;
1689
1690 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1691 ecopts = fptr->encs.ecopts;
1692
1693 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1694 /* no encoding conversion */
1695 fptr->writeconv_pre_ecflags = 0;
1696 fptr->writeconv_pre_ecopts = Qnil;
1697 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1698 if (!fptr->writeconv)
1699 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1700 fptr->writeconv_asciicompat = Qnil;
1701 }
1702 else {
1703 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1704 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1705 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1706 /* single conversion */
1707 fptr->writeconv_pre_ecflags = ecflags;
1708 fptr->writeconv_pre_ecopts = ecopts;
1709 fptr->writeconv = NULL;
1710 fptr->writeconv_asciicompat = Qnil;
1711 }
1712 else {
1713 /* double conversion */
1714 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1715 fptr->writeconv_pre_ecopts = ecopts;
1716 if (senc) {
1717 denc = rb_enc_name(enc);
1718 fptr->writeconv_asciicompat = rb_str_new2(senc);
1719 }
1720 else {
1721 senc = denc = "";
1722 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1723 }
1724 ecflags = fptr->encs.ecflags & (ECONV_ERROR_HANDLER_MASK|ECONV_STATEFUL_DECORATOR_MASK);
1725 ecopts = fptr->encs.ecopts;
1726 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1727 if (!fptr->writeconv)
1728 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1729 }
1730 }
1731 }
1732}
1733
1734/* writing functions */
1735 struct binwrite_arg {
1736 rb_io_t *fptr;
1737 const char *ptr;
1738 long length;
1739};
1740
1741 struct write_arg {
1742 VALUE io;
1743 VALUE str;
1744 int nosync;
1745};
1746
1747#ifdef HAVE_WRITEV
1748static ssize_t
1749io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1750{
1751 if (fptr->wbuf.len) {
1752 struct iovec iov[2];
1753
1754 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1755 iov[0].iov_len = fptr->wbuf.len;
1756 iov[1].iov_base = (void*)ptr;
1757 iov[1].iov_len = length;
1758
1759 ssize_t result = rb_writev_internal(fptr, iov, 2);
1760
1761 if (result < 0)
1762 return result;
1763
1764 if (result >= fptr->wbuf.len) {
1765 // We wrote more than the internal buffer:
1766 result -= fptr->wbuf.len;
1767 fptr->wbuf.off = 0;
1768 fptr->wbuf.len = 0;
1769 }
1770 else {
1771 // We only wrote less data than the internal buffer:
1772 fptr->wbuf.off += (int)result;
1773 fptr->wbuf.len -= (int)result;
1774
1775 result = 0;
1776 }
1777
1778 return result;
1779 }
1780 else {
1781 return rb_io_write_memory(fptr, ptr, length);
1782 }
1783}
1784#else
1785static ssize_t
1786io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1787{
1788 long remaining = length;
1789
1790 if (fptr->wbuf.len) {
1791 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1792 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1793 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1794 fptr->wbuf.off = 0;
1795 }
1796
1797 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1798 fptr->wbuf.len += (int)length;
1799
1800 // We copied the entire incoming data to the internal buffer:
1801 remaining = 0;
1802 }
1803
1804 // Flush the internal buffer:
1805 if (io_fflush(fptr) < 0) {
1806 return -1;
1807 }
1808
1809 // If all the data was buffered, we are done:
1810 if (remaining == 0) {
1811 return length;
1812 }
1813 }
1814
1815 // Otherwise, we should write the data directly:
1816 return rb_io_write_memory(fptr, ptr, length);
1817}
1818#endif
1819
1820static VALUE
1821io_binwrite_string(VALUE arg)
1822{
1823 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1824
1825 const char *ptr = p->ptr;
1826 size_t remaining = p->length;
1827
1828 while (remaining) {
1829 // Write as much as possible:
1830 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1831
1832 if (result == 0) {
1833 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1834 // should try again immediately.
1835 }
1836 else if (result > 0) {
1837 if ((size_t)result == remaining) break;
1838 ptr += result;
1839 remaining -= result;
1840 }
1841 // Wait for it to become writable:
1842 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1843 rb_io_check_closed(p->fptr);
1844 }
1845 else {
1846 // The error was unrelated to waiting for it to become writable, so we fail:
1847 return -1;
1848 }
1849 }
1850
1851 return p->length;
1852}
1853
1854inline static void
1855io_allocate_write_buffer(rb_io_t *fptr, int sync)
1856{
1857 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1858 fptr->wbuf.off = 0;
1859 fptr->wbuf.len = 0;
1860 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1861 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1862 }
1863
1864 if (NIL_P(fptr->write_lock)) {
1865 fptr->write_lock = rb_mutex_new();
1866 rb_mutex_allow_trap(fptr->write_lock, 1);
1867 }
1868}
1869
1870static inline int
1871io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1872{
1873 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1874 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1875 return 1;
1876
1877 // If the amount of data we want to write exceeds the internal buffer:
1878 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1879 return 1;
1880
1881 // Otherwise, we can append to the internal buffer:
1882 return 0;
1883}
1884
1885static long
1886io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1887{
1888 if (len <= 0) return len;
1889
1890 // Don't write anything if current thread has a pending interrupt:
1891 rb_thread_check_ints();
1892
1893 io_allocate_write_buffer(fptr, !nosync);
1894
1895 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1896 struct binwrite_arg arg;
1897
1898 arg.fptr = fptr;
1899 arg.ptr = ptr;
1900 arg.length = len;
1901
1902 if (!NIL_P(fptr->write_lock)) {
1903 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1904 }
1905 else {
1906 return io_binwrite_string((VALUE)&arg);
1907 }
1908 }
1909 else {
1910 if (fptr->wbuf.off) {
1911 if (fptr->wbuf.len)
1912 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1913 fptr->wbuf.off = 0;
1914 }
1915
1916 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1917 fptr->wbuf.len += (int)len;
1918
1919 return len;
1920 }
1921}
1922
1923# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1924 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1925
1926#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1927 MODE_BTMODE(d, e, f) : \
1928 MODE_BTMODE(a, b, c))
1929
1930static VALUE
1931do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1932{
1933 if (NEED_WRITECONV(fptr)) {
1934 VALUE common_encoding = Qnil;
1935 SET_BINARY_MODE(fptr);
1936
1937 make_writeconv(fptr);
1938
1939 if (fptr->writeconv) {
1940#define fmode (fptr->mode)
1941 if (!NIL_P(fptr->writeconv_asciicompat))
1942 common_encoding = fptr->writeconv_asciicompat;
1943 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1944 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1945 rb_enc_name(rb_enc_get(str)));
1946 }
1947#undef fmode
1948 }
1949 else {
1950 if (fptr->encs.enc2)
1951 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1952 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1953 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1954 }
1955
1956 if (!NIL_P(common_encoding)) {
1957 str = rb_str_encode(str, common_encoding,
1958 fptr->writeconv_pre_ecflags, fptr->writeconv_pre_ecopts);
1959 *converted = 1;
1960 }
1961
1962 if (fptr->writeconv) {
1963 str = rb_econv_str_convert(fptr->writeconv, str, ECONV_PARTIAL_INPUT);
1964 *converted = 1;
1965 }
1966 }
1967#if RUBY_CRLF_ENVIRONMENT
1968#define fmode (fptr->mode)
1969 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1970 if ((fptr->mode & FMODE_READABLE) &&
1971 !(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
1972 setmode(fptr->fd, O_BINARY);
1973 }
1974 else {
1975 setmode(fptr->fd, O_TEXT);
1976 }
1977 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1978 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1979 rb_enc_name(rb_enc_get(str)));
1980 }
1981 }
1982#undef fmode
1983#endif
1984 return str;
1985}
1986
1987static long
1988io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1989{
1990 int converted = 0;
1991 VALUE tmp;
1992 long n, len;
1993 const char *ptr;
1994
1995#ifdef _WIN32
1996 if (fptr->mode & FMODE_TTY) {
1997 long len = rb_w32_write_console(str, fptr->fd);
1998 if (len > 0) return len;
1999 }
2000#endif
2001
2002 str = do_writeconv(str, fptr, &converted);
2003 if (converted)
2004 OBJ_FREEZE(str);
2005
2006 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2007 RSTRING_GETMEM(tmp, ptr, len);
2008 n = io_binwrite(ptr, len, fptr, nosync);
2009 rb_str_tmp_frozen_release(str, tmp);
2010
2011 return n;
2012}
2013
2014ssize_t
2015rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2016{
2017 rb_io_t *fptr;
2018
2019 GetOpenFile(io, fptr);
2020 rb_io_check_writable(fptr);
2021 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2022}
2023
2024static VALUE
2025io_write(VALUE io, VALUE str, int nosync)
2026{
2027 rb_io_t *fptr;
2028 long n;
2029 VALUE tmp;
2030
2031 io = GetWriteIO(io);
2032 str = rb_obj_as_string(str);
2033 tmp = rb_io_check_io(io);
2034
2035 if (NIL_P(tmp)) {
2036 /* port is not IO, call write method for it. */
2037 return rb_funcall(io, id_write, 1, str);
2038 }
2039
2040 io = tmp;
2041 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2042
2043 GetOpenFile(io, fptr);
2044 rb_io_check_writable(fptr);
2045
2046 n = io_fwrite(str, fptr, nosync);
2047 if (n < 0L) rb_sys_fail_on_write(fptr);
2048
2049 return LONG2FIX(n);
2050}
2051
2052#ifdef HAVE_WRITEV
2053struct binwritev_arg {
2054 rb_io_t *fptr;
2055 struct iovec *iov;
2056 int iovcnt;
2057 size_t total;
2058};
2059
2060static VALUE
2061io_binwritev_internal(VALUE arg)
2062{
2063 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2064
2065 size_t remaining = p->total;
2066 size_t offset = 0;
2067
2068 rb_io_t *fptr = p->fptr;
2069 struct iovec *iov = p->iov;
2070 int iovcnt = p->iovcnt;
2071
2072 while (remaining) {
2073 long result = rb_writev_internal(fptr, iov, iovcnt);
2074
2075 if (result >= 0) {
2076 offset += result;
2077 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2078 if (offset < (size_t)fptr->wbuf.len) {
2079 fptr->wbuf.off += result;
2080 fptr->wbuf.len -= result;
2081 }
2082 else {
2083 offset -= (size_t)fptr->wbuf.len;
2084 fptr->wbuf.off = 0;
2085 fptr->wbuf.len = 0;
2086 }
2087 }
2088
2089 if (offset == p->total) {
2090 return p->total;
2091 }
2092
2093 while (result >= (ssize_t)iov->iov_len) {
2094 /* iovcnt > 0 */
2095 result -= iov->iov_len;
2096 iov->iov_len = 0;
2097 iov++;
2098
2099 if (!--iovcnt) {
2100 // I don't believe this code path can ever occur.
2101 return offset;
2102 }
2103 }
2104
2105 iov->iov_base = (char *)iov->iov_base + result;
2106 iov->iov_len -= result;
2107 }
2108 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2109 rb_io_check_closed(fptr);
2110 }
2111 else {
2112 return -1;
2113 }
2114 }
2115
2116 return offset;
2117}
2118
2119static long
2120io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2121{
2122 // Don't write anything if current thread has a pending interrupt:
2123 rb_thread_check_ints();
2124
2125 if (iovcnt == 0) return 0;
2126
2127 size_t total = 0;
2128 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2129
2130 io_allocate_write_buffer(fptr, 1);
2131
2132 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2133 // The end of the buffered data:
2134 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2135
2136 if (offset + total <= (size_t)fptr->wbuf.capa) {
2137 for (int i = 1; i < iovcnt; i++) {
2138 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2139 offset += iov[i].iov_len;
2140 }
2141
2142 fptr->wbuf.len += total;
2143
2144 return total;
2145 }
2146 else {
2147 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2148 iov[0].iov_len = fptr->wbuf.len;
2149 }
2150 }
2151 else {
2152 // The first iov is reserved for the internal buffer, and it's empty.
2153 iov++;
2154
2155 if (!--iovcnt) {
2156 // If there are no other io vectors we are done.
2157 return 0;
2158 }
2159 }
2160
2161 struct binwritev_arg arg;
2162 arg.fptr = fptr;
2163 arg.iov = iov;
2164 arg.iovcnt = iovcnt;
2165 arg.total = total;
2166
2167 if (!NIL_P(fptr->write_lock)) {
2168 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2169 }
2170 else {
2171 return io_binwritev_internal((VALUE)&arg);
2172 }
2173}
2174
2175static long
2176io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2177{
2178 int i, converted, iovcnt = argc + 1;
2179 long n;
2180 VALUE v1, v2, str, tmp, *tmp_array;
2181 struct iovec *iov;
2182
2183 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2184 tmp_array = ALLOCV_N(VALUE, v2, argc);
2185
2186 for (i = 0; i < argc; i++) {
2187 str = rb_obj_as_string(argv[i]);
2188 converted = 0;
2189 str = do_writeconv(str, fptr, &converted);
2190
2191 if (converted)
2192 OBJ_FREEZE(str);
2193
2194 tmp = rb_str_tmp_frozen_acquire(str);
2195 tmp_array[i] = tmp;
2196
2197 /* iov[0] is reserved for buffer of fptr */
2198 iov[i+1].iov_base = RSTRING_PTR(tmp);
2199 iov[i+1].iov_len = RSTRING_LEN(tmp);
2200 }
2201
2202 n = io_binwritev(iov, iovcnt, fptr);
2203 if (v1) ALLOCV_END(v1);
2204
2205 for (i = 0; i < argc; i++) {
2206 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2207 }
2208
2209 if (v2) ALLOCV_END(v2);
2210
2211 return n;
2212}
2213
2214static int
2215iovcnt_ok(int iovcnt)
2216{
2217#ifdef IOV_MAX
2218 return iovcnt < IOV_MAX;
2219#else /* GNU/Hurd has writev, but no IOV_MAX */
2220 return 1;
2221#endif
2222}
2223#endif /* HAVE_WRITEV */
2224
2225static VALUE
2226io_writev(int argc, const VALUE *argv, VALUE io)
2227{
2228 rb_io_t *fptr;
2229 long n;
2230 VALUE tmp, total = INT2FIX(0);
2231 int i, cnt = 1;
2232
2233 io = GetWriteIO(io);
2234 tmp = rb_io_check_io(io);
2235
2236 if (NIL_P(tmp)) {
2237 /* port is not IO, call write method for it. */
2238 return rb_funcallv(io, id_write, argc, argv);
2239 }
2240
2241 io = tmp;
2242
2243 GetOpenFile(io, fptr);
2244 rb_io_check_writable(fptr);
2245
2246 for (i = 0; i < argc; i += cnt) {
2247#ifdef HAVE_WRITEV
2248 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2249 n = io_fwritev(cnt, &argv[i], fptr);
2250 }
2251 else
2252#endif
2253 {
2254 cnt = 1;
2255 /* sync at last item */
2256 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2257 }
2258
2259 if (n < 0L)
2260 rb_sys_fail_on_write(fptr);
2261
2262 total = rb_fix_plus(LONG2FIX(n), total);
2263 }
2264
2265 return total;
2266}
2267
2268/*
2269 * call-seq:
2270 * write(*objects) -> integer
2271 *
2272 * Writes each of the given +objects+ to +self+,
2273 * which must be opened for writing
2274 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2275 * returns the total number bytes written;
2276 * each of +objects+ that is not a string is converted via method +to_s+:
2277 *
2278 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2279 * $stdout.write('foo', :bar, 2, "\n") # => 8
2280 *
2281 * Output:
2282 *
2283 * Hello, World!
2284 * foobar2
2285 *
2286 * Related: IO#read.
2287 */
2288
2289static VALUE
2290io_write_m(int argc, VALUE *argv, VALUE io)
2291{
2292 if (argc != 1) {
2293 return io_writev(argc, argv, io);
2294 }
2295 else {
2296 VALUE str = argv[0];
2297 return io_write(io, str, 0);
2298 }
2299}
2300
2301 VALUE
2302rb_io_write(VALUE io, VALUE str)
2303{
2304 return rb_funcallv(io, id_write, 1, &str);
2305}
2306
2307static VALUE
2308rb_io_writev(VALUE io, int argc, const VALUE *argv)
2309{
2310 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2311 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2312 VALUE klass = CLASS_OF(io);
2313 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2314 rb_category_warning(
2315 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2316 " which accepts just one argument",
2317 klass, sep
2318 );
2319 }
2320
2321 do rb_io_write(io, *argv++); while (--argc);
2322
2323 return Qnil;
2324 }
2325
2326 return rb_funcallv(io, id_write, argc, argv);
2327}
2328
2329/*
2330 * call-seq:
2331 * self << object -> self
2332 *
2333 * Writes the given +object+ to +self+,
2334 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2335 * returns +self+;
2336 * if +object+ is not a string, it is converted via method +to_s+:
2337 *
2338 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2339 * $stdout << 'foo' << :bar << 2 << "\n"
2340 *
2341 * Output:
2342 *
2343 * Hello, World!
2344 * foobar2
2345 *
2346 */
2347
2348
2349 VALUE
2350rb_io_addstr(VALUE io, VALUE str)
2351{
2352 rb_io_write(io, str);
2353 return io;
2354}
2355
2356#ifdef HAVE_FSYNC
2357static VALUE
2358nogvl_fsync(void *ptr)
2359{
2360 rb_io_t *fptr = ptr;
2361
2362#ifdef _WIN32
2363 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2364 return 0;
2365#endif
2366 return (VALUE)fsync(fptr->fd);
2367}
2368#endif
2369
2370 VALUE
2371rb_io_flush_raw(VALUE io, int sync)
2372{
2373 rb_io_t *fptr;
2374
2375 if (!RB_TYPE_P(io, T_FILE)) {
2376 return rb_funcall(io, id_flush, 0);
2377 }
2378
2379 io = GetWriteIO(io);
2380 GetOpenFile(io, fptr);
2381
2382 if (fptr->mode & FMODE_WRITABLE) {
2383 if (io_fflush(fptr) < 0)
2384 rb_sys_fail_on_write(fptr);
2385 }
2386 if (fptr->mode & FMODE_READABLE) {
2387 io_unread(fptr, true);
2388 }
2389
2390 return io;
2391}
2392
2393/*
2394 * call-seq:
2395 * flush -> self
2396 *
2397 * Flushes data buffered in +self+ to the operating system
2398 * (but does not necessarily flush data buffered in the operating system):
2399 *
2400 * $stdout.print 'no newline' # Not necessarily flushed.
2401 * $stdout.flush # Flushed.
2402 *
2403 */
2404
2405 VALUE
2406rb_io_flush(VALUE io)
2407{
2408 return rb_io_flush_raw(io, 1);
2409}
2410
2411/*
2412 * call-seq:
2413 * tell -> integer
2414 *
2415 * Returns the current position (in bytes) in +self+
2416 * (see {Position}[rdoc-ref:IO@Position]):
2417 *
2418 * f = File.open('t.txt')
2419 * f.tell # => 0
2420 * f.gets # => "First line\n"
2421 * f.tell # => 12
2422 * f.close
2423 *
2424 * Related: IO#pos=, IO#seek.
2425 */
2426
2427static VALUE
2428rb_io_tell(VALUE io)
2429{
2430 rb_io_t *fptr;
2431 rb_off_t pos;
2432
2433 GetOpenFile(io, fptr);
2434 pos = io_tell(fptr);
2435 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2436 pos -= fptr->rbuf.len;
2437 return OFFT2NUM(pos);
2438}
2439
2440static VALUE
2441rb_io_seek(VALUE io, VALUE offset, int whence)
2442{
2443 rb_io_t *fptr;
2444 rb_off_t pos;
2445
2446 pos = NUM2OFFT(offset);
2447 GetOpenFile(io, fptr);
2448 pos = io_seek(fptr, pos, whence);
2449 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2450
2451 return INT2FIX(0);
2452}
2453
2454static int
2455interpret_seek_whence(VALUE vwhence)
2456{
2457 if (vwhence == sym_SET)
2458 return SEEK_SET;
2459 if (vwhence == sym_CUR)
2460 return SEEK_CUR;
2461 if (vwhence == sym_END)
2462 return SEEK_END;
2463#ifdef SEEK_DATA
2464 if (vwhence == sym_DATA)
2465 return SEEK_DATA;
2466#endif
2467#ifdef SEEK_HOLE
2468 if (vwhence == sym_HOLE)
2469 return SEEK_HOLE;
2470#endif
2471 return NUM2INT(vwhence);
2472}
2473
2474/*
2475 * call-seq:
2476 * seek(offset, whence = IO::SEEK_SET) -> 0
2477 *
2478 * Seeks to the position given by integer +offset+
2479 * (see {Position}[rdoc-ref:IO@Position])
2480 * and constant +whence+, which is one of:
2481 *
2482 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2483 * Repositions the stream to its current position plus the given +offset+:
2484 *
2485 * f = File.open('t.txt')
2486 * f.tell # => 0
2487 * f.seek(20, :CUR) # => 0
2488 * f.tell # => 20
2489 * f.seek(-10, :CUR) # => 0
2490 * f.tell # => 10
2491 * f.close
2492 *
2493 * - +:END+ or <tt>IO::SEEK_END</tt>:
2494 * Repositions the stream to its end plus the given +offset+:
2495 *
2496 * f = File.open('t.txt')
2497 * f.tell # => 0
2498 * f.seek(0, :END) # => 0 # Repositions to stream end.
2499 * f.tell # => 52
2500 * f.seek(-20, :END) # => 0
2501 * f.tell # => 32
2502 * f.seek(-40, :END) # => 0
2503 * f.tell # => 12
2504 * f.close
2505 *
2506 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2507 * Repositions the stream to the given +offset+:
2508 *
2509 * f = File.open('t.txt')
2510 * f.tell # => 0
2511 * f.seek(20, :SET) # => 0
2512 * f.tell # => 20
2513 * f.seek(40, :SET) # => 0
2514 * f.tell # => 40
2515 * f.close
2516 *
2517 * Related: IO#pos=, IO#tell.
2518 *
2519 */
2520
2521static VALUE
2522rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2523{
2524 VALUE offset, ptrname;
2525 int whence = SEEK_SET;
2526
2527 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2528 whence = interpret_seek_whence(ptrname);
2529 }
2530
2531 return rb_io_seek(io, offset, whence);
2532}
2533
2534/*
2535 * call-seq:
2536 * pos = new_position -> new_position
2537 *
2538 * Seeks to the given +new_position+ (in bytes);
2539 * see {Position}[rdoc-ref:IO@Position]:
2540 *
2541 * f = File.open('t.txt')
2542 * f.tell # => 0
2543 * f.pos = 20 # => 20
2544 * f.tell # => 20
2545 * f.close
2546 *
2547 * Related: IO#seek, IO#tell.
2548 *
2549 */
2550
2551static VALUE
2552rb_io_set_pos(VALUE io, VALUE offset)
2553{
2554 rb_io_t *fptr;
2555 rb_off_t pos;
2556
2557 pos = NUM2OFFT(offset);
2558 GetOpenFile(io, fptr);
2559 pos = io_seek(fptr, pos, SEEK_SET);
2560 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2561
2562 return OFFT2NUM(pos);
2563}
2564
2565static void clear_readconv(rb_io_t *fptr);
2566
2567/*
2568 * call-seq:
2569 * rewind -> 0
2570 *
2571 * Repositions the stream to its beginning,
2572 * setting both the position and the line number to zero;
2573 * see {Position}[rdoc-ref:IO@Position]
2574 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2575 *
2576 * f = File.open('t.txt')
2577 * f.tell # => 0
2578 * f.lineno # => 0
2579 * f.gets # => "First line\n"
2580 * f.tell # => 12
2581 * f.lineno # => 1
2582 * f.rewind # => 0
2583 * f.tell # => 0
2584 * f.lineno # => 0
2585 * f.close
2586 *
2587 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2588 *
2589 */
2590
2591static VALUE
2592rb_io_rewind(VALUE io)
2593{
2594 rb_io_t *fptr;
2595
2596 GetOpenFile(io, fptr);
2597 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2598 if (io == ARGF.current_file) {
2599 ARGF.lineno -= fptr->lineno;
2600 }
2601 fptr->lineno = 0;
2602 if (fptr->readconv) {
2603 clear_readconv(fptr);
2604 }
2605
2606 return INT2FIX(0);
2607}
2608
2609static int
2610fptr_wait_readable(rb_io_t *fptr)
2611{
2612 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2613
2614 if (result)
2615 rb_io_check_closed(fptr);
2616
2617 return result;
2618}
2619
2620static int
2621io_fillbuf(rb_io_t *fptr)
2622{
2623 ssize_t r;
2624
2625 if (fptr->rbuf.ptr == NULL) {
2626 fptr->rbuf.off = 0;
2627 fptr->rbuf.len = 0;
2628 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2629 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2630#ifdef _WIN32
2631 fptr->rbuf.capa--;
2632#endif
2633 }
2634 if (fptr->rbuf.len == 0) {
2635 retry:
2636 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2637
2638 if (r < 0) {
2639 if (fptr_wait_readable(fptr))
2640 goto retry;
2641
2642 int e = errno;
2643 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2644 if (!NIL_P(fptr->pathv)) {
2645 rb_str_append(path, fptr->pathv);
2646 }
2647
2648 rb_syserr_fail_path(e, path);
2649 }
2650 if (r > 0) rb_io_check_closed(fptr);
2651 fptr->rbuf.off = 0;
2652 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2653 if (r == 0)
2654 return -1; /* EOF */
2655 }
2656 return 0;
2657}
2658
2659/*
2660 * call-seq:
2661 * eof -> true or false
2662 *
2663 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2664 * see {Position}[rdoc-ref:IO@Position]:
2665 *
2666 * f = File.open('t.txt')
2667 * f.eof # => false
2668 * f.seek(0, :END) # => 0
2669 * f.eof # => true
2670 * f.close
2671 *
2672 * Raises an exception unless the stream is opened for reading;
2673 * see {Mode}[rdoc-ref:File@Access+Modes].
2674 *
2675 * If +self+ is a stream such as pipe or socket, this method
2676 * blocks until the other end sends some data or closes it:
2677 *
2678 * r, w = IO.pipe
2679 * Thread.new { sleep 1; w.close }
2680 * r.eof? # => true # After 1-second wait.
2681 *
2682 * r, w = IO.pipe
2683 * Thread.new { sleep 1; w.puts "a" }
2684 * r.eof? # => false # After 1-second wait.
2685 *
2686 * r, w = IO.pipe
2687 * r.eof? # blocks forever
2688 *
2689 * Note that this method reads data to the input byte buffer. So
2690 * IO#sysread may not behave as you intend with IO#eof?, unless you
2691 * call IO#rewind first (which is not available for some streams).
2692 */
2693
2694 VALUE
2695rb_io_eof(VALUE io)
2696{
2697 rb_io_t *fptr;
2698
2699 GetOpenFile(io, fptr);
2700 rb_io_check_char_readable(fptr);
2701
2702 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2703 if (READ_DATA_PENDING(fptr)) return Qfalse;
2704 READ_CHECK(fptr);
2705#if RUBY_CRLF_ENVIRONMENT
2706 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2707 return RBOOL(eof(fptr->fd));
2708 }
2709#endif
2710 return RBOOL(io_fillbuf(fptr) < 0);
2711}
2712
2713/*
2714 * call-seq:
2715 * sync -> true or false
2716 *
2717 * Returns the current sync mode of the stream.
2718 * When sync mode is true, all output is immediately flushed to the underlying
2719 * operating system and is not buffered by Ruby internally. See also #fsync.
2720 *
2721 * f = File.open('t.tmp', 'w')
2722 * f.sync # => false
2723 * f.sync = true
2724 * f.sync # => true
2725 * f.close
2726 *
2727 */
2728
2729static VALUE
2730rb_io_sync(VALUE io)
2731{
2732 rb_io_t *fptr;
2733
2734 io = GetWriteIO(io);
2735 GetOpenFile(io, fptr);
2736 return RBOOL(fptr->mode & FMODE_SYNC);
2737}
2738
2739#ifdef HAVE_FSYNC
2740
2741/*
2742 * call-seq:
2743 * sync = boolean -> boolean
2744 *
2745 * Sets the _sync_ _mode_ for the stream to the given value;
2746 * returns the given value.
2747 *
2748 * Values for the sync mode:
2749 *
2750 * - +true+: All output is immediately flushed to the
2751 * underlying operating system and is not buffered internally.
2752 * - +false+: Output may be buffered internally.
2753 *
2754 * Example;
2755 *
2756 * f = File.open('t.tmp', 'w')
2757 * f.sync # => false
2758 * f.sync = true
2759 * f.sync # => true
2760 * f.close
2761 *
2762 * Related: IO#fsync.
2763 *
2764 */
2765
2766static VALUE
2767rb_io_set_sync(VALUE io, VALUE sync)
2768{
2769 rb_io_t *fptr;
2770
2771 io = GetWriteIO(io);
2772 GetOpenFile(io, fptr);
2773 if (RTEST(sync)) {
2774 fptr->mode |= FMODE_SYNC;
2775 }
2776 else {
2777 fptr->mode &= ~FMODE_SYNC;
2778 }
2779 return sync;
2780}
2781
2782/*
2783 * call-seq:
2784 * fsync -> 0
2785 *
2786 * Immediately writes to disk all data buffered in the stream,
2787 * via the operating system's <tt>fsync(2)</tt>.
2788
2789 * Note this difference:
2790 *
2791 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2792 * but does not guarantee that the operating system actually writes the data to disk.
2793 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2794 * and that data is written to disk.
2795 *
2796 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2797 *
2798 */
2799
2800static VALUE
2801rb_io_fsync(VALUE io)
2802{
2803 rb_io_t *fptr;
2804
2805 io = GetWriteIO(io);
2806 GetOpenFile(io, fptr);
2807
2808 if (io_fflush(fptr) < 0)
2809 rb_sys_fail_on_write(fptr);
2810
2811 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2812 rb_sys_fail_path(fptr->pathv);
2813
2814 return INT2FIX(0);
2815}
2816#else
2817# define rb_io_fsync rb_f_notimplement
2818# define rb_io_sync rb_f_notimplement
2819static VALUE
2820rb_io_set_sync(VALUE io, VALUE sync)
2821{
2822 rb_notimplement();
2823 UNREACHABLE;
2824}
2825#endif
2826
2827#ifdef HAVE_FDATASYNC
2828static VALUE
2829nogvl_fdatasync(void *ptr)
2830{
2831 rb_io_t *fptr = ptr;
2832
2833#ifdef _WIN32
2834 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2835 return 0;
2836#endif
2837 return (VALUE)fdatasync(fptr->fd);
2838}
2839
2840/*
2841 * call-seq:
2842 * fdatasync -> 0
2843 *
2844 * Immediately writes to disk all data buffered in the stream,
2845 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2846 * otherwise via <tt>fsync(2)</tt>, if supported;
2847 * otherwise raises an exception.
2848 *
2849 */
2850
2851static VALUE
2852rb_io_fdatasync(VALUE io)
2853{
2854 rb_io_t *fptr;
2855
2856 io = GetWriteIO(io);
2857 GetOpenFile(io, fptr);
2858
2859 if (io_fflush(fptr) < 0)
2860 rb_sys_fail_on_write(fptr);
2861
2862 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2863 return INT2FIX(0);
2864
2865 /* fall back */
2866 return rb_io_fsync(io);
2867}
2868#else
2869#define rb_io_fdatasync rb_io_fsync
2870#endif
2871
2872/*
2873 * call-seq:
2874 * fileno -> integer
2875 *
2876 * Returns the integer file descriptor for the stream:
2877 *
2878 * $stdin.fileno # => 0
2879 * $stdout.fileno # => 1
2880 * $stderr.fileno # => 2
2881 * File.open('t.txt').fileno # => 10
2882 * f.close
2883 *
2884 */
2885
2886static VALUE
2887rb_io_fileno(VALUE io)
2888{
2889 rb_io_t *fptr = RFILE(io)->fptr;
2890 int fd;
2891
2892 rb_io_check_closed(fptr);
2893 fd = fptr->fd;
2894 return INT2FIX(fd);
2895}
2896
2897int
2898rb_io_descriptor(VALUE io)
2899{
2900 if (RB_TYPE_P(io, T_FILE)) {
2901 rb_io_t *fptr = RFILE(io)->fptr;
2902 rb_io_check_closed(fptr);
2903 return fptr->fd;
2904 }
2905 else {
2906 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2907 if (!UNDEF_P(fileno)) {
2908 return RB_NUM2INT(fileno);
2909 }
2910 }
2911
2912 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2913
2914 UNREACHABLE_RETURN(-1);
2915}
2916
2917int
2918rb_io_mode(VALUE io)
2919{
2920 rb_io_t *fptr;
2921 GetOpenFile(io, fptr);
2922 return fptr->mode;
2923}
2924
2925/*
2926 * call-seq:
2927 * pid -> integer or nil
2928 *
2929 * Returns the process ID of a child process associated with the stream,
2930 * which will have been set by IO#popen, or +nil+ if the stream was not
2931 * created by IO#popen:
2932 *
2933 * pipe = IO.popen("-")
2934 * if pipe
2935 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2936 * else
2937 * $stderr.puts "In child, pid is #{$$}"
2938 * end
2939 *
2940 * Output:
2941 *
2942 * In child, pid is 26209
2943 * In parent, child pid is 26209
2944 *
2945 */
2946
2947static VALUE
2948rb_io_pid(VALUE io)
2949{
2950 rb_io_t *fptr;
2951
2952 GetOpenFile(io, fptr);
2953 if (!fptr->pid)
2954 return Qnil;
2955 return PIDT2NUM(fptr->pid);
2956}
2957
2958/*
2959 * call-seq:
2960 * path -> string or nil
2961 *
2962 * Returns the path associated with the IO, or +nil+ if there is no path
2963 * associated with the IO. It is not guaranteed that the path exists on
2964 * the filesystem.
2965 *
2966 * $stdin.path # => "<STDIN>"
2967 *
2968 * File.open("testfile") {|f| f.path} # => "testfile"
2969 */
2970
2971 VALUE
2972rb_io_path(VALUE io)
2973{
2974 rb_io_t *fptr = RFILE(io)->fptr;
2975
2976 if (!fptr)
2977 return Qnil;
2978
2979 return rb_obj_dup(fptr->pathv);
2980}
2981
2982/*
2983 * call-seq:
2984 * inspect -> string
2985 *
2986 * Returns a string representation of +self+:
2987 *
2988 * f = File.open('t.txt')
2989 * f.inspect # => "#<File:t.txt>"
2990 * f.close
2991 *
2992 */
2993
2994static VALUE
2995rb_io_inspect(VALUE obj)
2996{
2997 rb_io_t *fptr;
2998 VALUE result;
2999 static const char closed[] = " (closed)";
3000
3001 fptr = RFILE(obj)->fptr;
3002 if (!fptr) return rb_any_to_s(obj);
3003 result = rb_str_new_cstr("#<");
3004 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3005 rb_str_cat2(result, ":");
3006 if (NIL_P(fptr->pathv)) {
3007 if (fptr->fd < 0) {
3008 rb_str_cat(result, closed+1, strlen(closed)-1);
3009 }
3010 else {
3011 rb_str_catf(result, "fd %d", fptr->fd);
3012 }
3013 }
3014 else {
3015 rb_str_append(result, fptr->pathv);
3016 if (fptr->fd < 0) {
3017 rb_str_cat(result, closed, strlen(closed));
3018 }
3019 }
3020 return rb_str_cat2(result, ">");
3021}
3022
3023/*
3024 * call-seq:
3025 * to_io -> self
3026 *
3027 * Returns +self+.
3028 *
3029 */
3030
3031static VALUE
3032rb_io_to_io(VALUE io)
3033{
3034 return io;
3035}
3036
3037/* reading functions */
3038static long
3039read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3040{
3041 int n;
3042
3043 n = READ_DATA_PENDING_COUNT(fptr);
3044 if (n <= 0) return 0;
3045 if (n > len) n = (int)len;
3046 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3047 fptr->rbuf.off += n;
3048 fptr->rbuf.len -= n;
3049 return n;
3050}
3051
3052static long
3053io_bufread(char *ptr, long len, rb_io_t *fptr)
3054{
3055 long offset = 0;
3056 long n = len;
3057 long c;
3058
3059 if (READ_DATA_PENDING(fptr) == 0) {
3060 while (n > 0) {
3061 again:
3062 rb_io_check_closed(fptr);
3063 c = rb_io_read_memory(fptr, ptr+offset, n);
3064 if (c == 0) break;
3065 if (c < 0) {
3066 if (fptr_wait_readable(fptr))
3067 goto again;
3068 return -1;
3069 }
3070 offset += c;
3071 if ((n -= c) <= 0) break;
3072 }
3073 return len - n;
3074 }
3075
3076 while (n > 0) {
3077 c = read_buffered_data(ptr+offset, n, fptr);
3078 if (c > 0) {
3079 offset += c;
3080 if ((n -= c) <= 0) break;
3081 }
3082 rb_io_check_closed(fptr);
3083 if (io_fillbuf(fptr) < 0) {
3084 break;
3085 }
3086 }
3087 return len - n;
3088}
3089
3090static int io_setstrbuf(VALUE *str, long len);
3091
3092 struct bufread_arg {
3093 char *str_ptr;
3094 long len;
3095 rb_io_t *fptr;
3096};
3097
3098static VALUE
3099bufread_call(VALUE arg)
3100{
3101 struct bufread_arg *p = (struct bufread_arg *)arg;
3102 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3103 return Qundef;
3104}
3105
3106static long
3107io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3108{
3109 long len;
3110 struct bufread_arg arg;
3111
3112 io_setstrbuf(&str, offset + size);
3113 arg.str_ptr = RSTRING_PTR(str) + offset;
3114 arg.len = size;
3115 arg.fptr = fptr;
3116 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3117 len = arg.len;
3118 if (len < 0) rb_sys_fail_path(fptr->pathv);
3119 return len;
3120}
3121
3122static long
3123remain_size(rb_io_t *fptr)
3124{
3125 struct stat st;
3126 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3127 rb_off_t pos;
3128
3129 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3130#if defined(__HAIKU__)
3131 && (st.st_dev > 3)
3132#endif
3133 )
3134 {
3135 if (io_fflush(fptr) < 0)
3136 rb_sys_fail_on_write(fptr);
3137 pos = lseek(fptr->fd, 0, SEEK_CUR);
3138 if (st.st_size >= pos && pos >= 0) {
3139 siz += st.st_size - pos;
3140 if (siz > LONG_MAX) {
3141 rb_raise(rb_eIOError, "file too big for single read");
3142 }
3143 }
3144 }
3145 else {
3146 siz += BUFSIZ;
3147 }
3148 return (long)siz;
3149}
3150
3151static VALUE
3152io_enc_str(VALUE str, rb_io_t *fptr)
3153{
3154 rb_enc_associate(str, io_read_encoding(fptr));
3155 return str;
3156}
3157
3158static rb_encoding *io_read_encoding(rb_io_t *fptr);
3159
3160static void
3161make_readconv(rb_io_t *fptr, int size)
3162{
3163 if (!fptr->readconv) {
3164 int ecflags;
3165 VALUE ecopts;
3166 const char *sname, *dname;
3167 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3168 ecopts = fptr->encs.ecopts;
3169 if (fptr->encs.enc2) {
3170 sname = rb_enc_name(fptr->encs.enc2);
3171 dname = rb_enc_name(io_read_encoding(fptr));
3172 }
3173 else {
3174 sname = dname = "";
3175 }
3176 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3177 if (!fptr->readconv)
3178 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3179 fptr->cbuf.off = 0;
3180 fptr->cbuf.len = 0;
3181 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3182 fptr->cbuf.capa = size;
3183 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3184 }
3185}
3186
3187#define MORE_CHAR_SUSPENDED Qtrue
3188#define MORE_CHAR_FINISHED Qnil
3189static VALUE
3190fill_cbuf(rb_io_t *fptr, int ec_flags)
3191{
3192 const unsigned char *ss, *sp, *se;
3193 unsigned char *ds, *dp, *de;
3194 rb_econv_result_t res;
3195 int putbackable;
3196 int cbuf_len0;
3197 VALUE exc;
3198
3199 ec_flags |= ECONV_PARTIAL_INPUT;
3200
3201 if (fptr->cbuf.len == fptr->cbuf.capa)
3202 return MORE_CHAR_SUSPENDED; /* cbuf full */
3203 if (fptr->cbuf.len == 0)
3204 fptr->cbuf.off = 0;
3205 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3206 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3207 fptr->cbuf.off = 0;
3208 }
3209
3210 cbuf_len0 = fptr->cbuf.len;
3211
3212 while (1) {
3213 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3214 se = sp + fptr->rbuf.len;
3215 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3216 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3217 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3218 fptr->rbuf.off += (int)(sp - ss);
3219 fptr->rbuf.len -= (int)(sp - ss);
3220 fptr->cbuf.len += (int)(dp - ds);
3221
3222 putbackable = rb_econv_putbackable(fptr->readconv);
3223 if (putbackable) {
3224 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3225 fptr->rbuf.off -= putbackable;
3226 fptr->rbuf.len += putbackable;
3227 }
3228
3229 exc = rb_econv_make_exception(fptr->readconv);
3230 if (!NIL_P(exc))
3231 return exc;
3232
3233 if (cbuf_len0 != fptr->cbuf.len)
3234 return MORE_CHAR_SUSPENDED;
3235
3236 if (res == econv_finished) {
3237 return MORE_CHAR_FINISHED;
3238 }
3239
3240 if (res == econv_source_buffer_empty) {
3241 if (fptr->rbuf.len == 0) {
3242 READ_CHECK(fptr);
3243 if (io_fillbuf(fptr) < 0) {
3244 if (!fptr->readconv) {
3245 return MORE_CHAR_FINISHED;
3246 }
3247 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3248 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3249 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3250 fptr->cbuf.len += (int)(dp - ds);
3251 rb_econv_check_error(fptr->readconv);
3252 break;
3253 }
3254 }
3255 }
3256 }
3257 if (cbuf_len0 != fptr->cbuf.len)
3258 return MORE_CHAR_SUSPENDED;
3259
3260 return MORE_CHAR_FINISHED;
3261}
3262
3263static VALUE
3264more_char(rb_io_t *fptr)
3265{
3266 VALUE v;
3267 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3268 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3269 rb_exc_raise(v);
3270 return v;
3271}
3272
3273static VALUE
3274io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3275{
3276 VALUE str = Qnil;
3277 if (strp) {
3278 str = *strp;
3279 if (NIL_P(str)) {
3280 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3281 }
3282 else {
3283 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3284 }
3285 rb_enc_associate(str, fptr->encs.enc);
3286 }
3287 fptr->cbuf.off += len;
3288 fptr->cbuf.len -= len;
3289 /* xxx: set coderange */
3290 if (fptr->cbuf.len == 0)
3291 fptr->cbuf.off = 0;
3292 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3293 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3294 fptr->cbuf.off = 0;
3295 }
3296 return str;
3297}
3298
3299static int
3300io_setstrbuf(VALUE *str, long len)
3301{
3302#ifdef _WIN32
3303 if (len > 0)
3304 len = (len + 1) & ~1L; /* round up for wide char */
3305#endif
3306 if (NIL_P(*str)) {
3307 *str = rb_str_new(0, len);
3308 return TRUE;
3309 }
3310 else {
3311 VALUE s = StringValue(*str);
3312 rb_str_modify(s);
3313
3314 long clen = RSTRING_LEN(s);
3315 if (clen >= len) {
3316 return FALSE;
3317 }
3318 len -= clen;
3319 }
3320 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3321 rb_str_modify_expand(*str, len);
3322 }
3323 return FALSE;
3324}
3325
3326#define MAX_REALLOC_GAP 4096
3327static void
3328io_shrink_read_string(VALUE str, long n)
3329{
3330 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3331 rb_str_resize(str, n);
3332 }
3333}
3334
3335static void
3336io_set_read_length(VALUE str, long n, int shrinkable)
3337{
3338 if (RSTRING_LEN(str) != n) {
3339 rb_str_modify(str);
3340 rb_str_set_len(str, n);
3341 if (shrinkable) io_shrink_read_string(str, n);
3342 }
3343}
3344
3345static VALUE
3346read_all(rb_io_t *fptr, long siz, VALUE str)
3347{
3348 long bytes;
3349 long n;
3350 long pos;
3351 rb_encoding *enc;
3352 int cr;
3353 int shrinkable;
3354
3355 if (NEED_READCONV(fptr)) {
3356 int first = !NIL_P(str);
3357 SET_BINARY_MODE(fptr);
3358 shrinkable = io_setstrbuf(&str,0);
3359 make_readconv(fptr, 0);
3360 while (1) {
3361 VALUE v;
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 v = fill_cbuf(fptr, 0);
3367 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3368 if (fptr->cbuf.len) {
3369 if (first) rb_str_set_len(str, first = 0);
3370 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3371 }
3372 rb_exc_raise(v);
3373 }
3374 if (v == MORE_CHAR_FINISHED) {
3375 clear_readconv(fptr);
3376 if (first) rb_str_set_len(str, first = 0);
3377 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3378 return io_enc_str(str, fptr);
3379 }
3380 }
3381 }
3382
3383 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3384 bytes = 0;
3385 pos = 0;
3386
3387 enc = io_read_encoding(fptr);
3388 cr = 0;
3389
3390 if (siz == 0) siz = BUFSIZ;
3391 shrinkable = io_setstrbuf(&str, siz);
3392 for (;;) {
3393 READ_CHECK(fptr);
3394 n = io_fread(str, bytes, siz - bytes, fptr);
3395 if (n == 0 && bytes == 0) {
3396 rb_str_set_len(str, 0);
3397 break;
3398 }
3399 bytes += n;
3400 rb_str_set_len(str, bytes);
3401 if (cr != ENC_CODERANGE_BROKEN)
3402 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3403 if (bytes < siz) break;
3404 siz += BUFSIZ;
3405
3406 size_t capa = rb_str_capacity(str);
3407 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3408 if (capa < BUFSIZ) {
3409 capa = BUFSIZ;
3410 }
3411 else if (capa > IO_MAX_BUFFER_GROWTH) {
3412 capa = IO_MAX_BUFFER_GROWTH;
3413 }
3414 rb_str_modify_expand(str, capa);
3415 }
3416 }
3417 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3418 str = io_enc_str(str, fptr);
3419 ENC_CODERANGE_SET(str, cr);
3420 return str;
3421}
3422
3423void
3424rb_io_set_nonblock(rb_io_t *fptr)
3425{
3426 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3427 rb_sys_fail_path(fptr->pathv);
3428 }
3429}
3430
3431static VALUE
3432io_read_memory_call(VALUE arg)
3433{
3434 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3435
3436 VALUE scheduler = rb_fiber_scheduler_current();
3437 if (scheduler != Qnil) {
3438 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3439
3440 if (!UNDEF_P(result)) {
3441 // This is actually returned as a pseudo-VALUE and later cast to a long:
3442 return (VALUE)rb_fiber_scheduler_io_result_apply(result);
3443 }
3444 }
3445
3446 if (iis->nonblock) {
3447 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3448 }
3449 else {
3450 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3451 }
3452}
3453
3454static long
3455io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3456{
3457 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3458}
3459
3460#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3461
3462static VALUE
3463io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3464{
3465 rb_io_t *fptr;
3466 VALUE length, str;
3467 long n, len;
3468 struct io_internal_read_struct iis;
3469 int shrinkable;
3470
3471 rb_scan_args(argc, argv, "11", &length, &str);
3472
3473 if ((len = NUM2LONG(length)) < 0) {
3474 rb_raise(rb_eArgError, "negative length %ld given", len);
3475 }
3476
3477 shrinkable = io_setstrbuf(&str, len);
3478
3479 GetOpenFile(io, fptr);
3480 rb_io_check_byte_readable(fptr);
3481
3482 if (len == 0) {
3483 io_set_read_length(str, 0, shrinkable);
3484 return str;
3485 }
3486
3487 if (!nonblock)
3488 READ_CHECK(fptr);
3489 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3490 if (n <= 0) {
3491 again:
3492 if (nonblock) {
3493 rb_io_set_nonblock(fptr);
3494 }
3495 io_setstrbuf(&str, len);
3496 iis.th = rb_thread_current();
3497 iis.fptr = fptr;
3498 iis.nonblock = nonblock;
3499 iis.fd = fptr->fd;
3500 iis.buf = RSTRING_PTR(str);
3501 iis.capa = len;
3502 iis.timeout = NULL;
3503 n = io_read_memory_locktmp(str, &iis);
3504 if (n < 0) {
3505 int e = errno;
3506 if (!nonblock && fptr_wait_readable(fptr))
3507 goto again;
3508 if (nonblock && (io_again_p(e))) {
3509 if (no_exception)
3510 return sym_wait_readable;
3511 else
3512 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3513 e, "read would block");
3514 }
3515 rb_syserr_fail_path(e, fptr->pathv);
3516 }
3517 }
3518 io_set_read_length(str, n, shrinkable);
3519
3520 if (n == 0)
3521 return Qnil;
3522 else
3523 return str;
3524}
3525
3526/*
3527 * call-seq:
3528 * readpartial(maxlen) -> string
3529 * readpartial(maxlen, out_string) -> out_string
3530 *
3531 * Reads up to +maxlen+ bytes from the stream;
3532 * returns a string (either a new string or the given +out_string+).
3533 * Its encoding is:
3534 *
3535 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3536 * - ASCII-8BIT, otherwise.
3537 *
3538 * - Contains +maxlen+ bytes from the stream, if available.
3539 * - Otherwise contains all available bytes, if any available.
3540 * - Otherwise is an empty string.
3541 *
3542 * With the single non-negative integer argument +maxlen+ given,
3543 * returns a new string:
3544 *
3545 * f = File.new('t.txt')
3546 * f.readpartial(20) # => "First line\nSecond l"
3547 * f.readpartial(20) # => "ine\n\nFourth line\n"
3548 * f.readpartial(20) # => "Fifth line\n"
3549 * f.readpartial(20) # Raises EOFError.
3550 * f.close
3551 *
3552 * With both argument +maxlen+ and string argument +out_string+ given,
3553 * returns modified +out_string+:
3554 *
3555 * f = File.new('t.txt')
3556 * s = 'foo'
3557 * f.readpartial(20, s) # => "First line\nSecond l"
3558 * s = 'bar'
3559 * f.readpartial(0, s) # => ""
3560 * f.close
3561 *
3562 * This method is useful for a stream such as a pipe, a socket, or a tty.
3563 * It blocks only when no data is immediately available.
3564 * This means that it blocks only when _all_ of the following are true:
3565 *
3566 * - The byte buffer in the stream is empty.
3567 * - The content of the stream is empty.
3568 * - The stream is not at EOF.
3569 *
3570 * When blocked, the method waits for either more data or EOF on the stream:
3571 *
3572 * - If more data is read, the method returns the data.
3573 * - If EOF is reached, the method raises EOFError.
3574 *
3575 * When not blocked, the method responds immediately:
3576 *
3577 * - Returns data from the buffer if there is any.
3578 * - Otherwise returns data from the stream if there is any.
3579 * - Otherwise raises EOFError if the stream has reached EOF.
3580 *
3581 * Note that this method is similar to sysread. The differences are:
3582 *
3583 * - If the byte buffer is not empty, read from the byte buffer
3584 * instead of "sysread for buffered IO (IOError)".
3585 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3586 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3587 * readpartial retries the system call.
3588 *
3589 * The latter means that readpartial is non-blocking-flag insensitive.
3590 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3591 * if the fd is blocking mode.
3592 *
3593 * Examples:
3594 *
3595 * # # Returned Buffer Content Pipe Content
3596 * r, w = IO.pipe #
3597 * w << 'abc' # "" "abc".
3598 * r.readpartial(4096) # => "abc" "" ""
3599 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3600 *
3601 * # # Returned Buffer Content Pipe Content
3602 * r, w = IO.pipe #
3603 * w << 'abc' # "" "abc"
3604 * w.close # "" "abc" EOF
3605 * r.readpartial(4096) # => "abc" "" EOF
3606 * r.readpartial(4096) # raises EOFError
3607 *
3608 * # # Returned Buffer Content Pipe Content
3609 * r, w = IO.pipe #
3610 * w << "abc\ndef\n" # "" "abc\ndef\n"
3611 * r.gets # => "abc\n" "def\n" ""
3612 * w << "ghi\n" # "def\n" "ghi\n"
3613 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3614 * r.readpartial(4096) # => "ghi\n" "" ""
3615 *
3616 */
3617
3618static VALUE
3619io_readpartial(int argc, VALUE *argv, VALUE io)
3620{
3621 VALUE ret;
3622
3623 ret = io_getpartial(argc, argv, io, Qnil, 0);
3624 if (NIL_P(ret))
3625 rb_eof_error();
3626 return ret;
3627}
3628
3629static VALUE
3630io_nonblock_eof(int no_exception)
3631{
3632 if (!no_exception) {
3633 rb_eof_error();
3634 }
3635 return Qnil;
3636}
3637
3638/* :nodoc: */
3639static VALUE
3640io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3641{
3642 rb_io_t *fptr;
3643 long n, len;
3644 struct io_internal_read_struct iis;
3645 int shrinkable;
3646
3647 if ((len = NUM2LONG(length)) < 0) {
3648 rb_raise(rb_eArgError, "negative length %ld given", len);
3649 }
3650
3651 shrinkable = io_setstrbuf(&str, len);
3652 rb_bool_expected(ex, "exception", TRUE);
3653
3654 GetOpenFile(io, fptr);
3655 rb_io_check_byte_readable(fptr);
3656
3657 if (len == 0) {
3658 io_set_read_length(str, 0, shrinkable);
3659 return str;
3660 }
3661
3662 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3663 if (n <= 0) {
3664 rb_fd_set_nonblock(fptr->fd);
3665 shrinkable |= io_setstrbuf(&str, len);
3666 iis.fptr = fptr;
3667 iis.nonblock = 1;
3668 iis.fd = fptr->fd;
3669 iis.buf = RSTRING_PTR(str);
3670 iis.capa = len;
3671 iis.timeout = NULL;
3672 n = io_read_memory_locktmp(str, &iis);
3673 if (n < 0) {
3674 int e = errno;
3675 if (io_again_p(e)) {
3676 if (!ex) return sym_wait_readable;
3677 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3678 e, "read would block");
3679 }
3680 rb_syserr_fail_path(e, fptr->pathv);
3681 }
3682 }
3683 io_set_read_length(str, n, shrinkable);
3684
3685 if (n == 0) {
3686 if (!ex) return Qnil;
3687 rb_eof_error();
3688 }
3689
3690 return str;
3691}
3692
3693/* :nodoc: */
3694static VALUE
3695io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3696{
3697 rb_io_t *fptr;
3698 long n;
3699
3700 if (!RB_TYPE_P(str, T_STRING))
3701 str = rb_obj_as_string(str);
3702 rb_bool_expected(ex, "exception", TRUE);
3703
3704 io = GetWriteIO(io);
3705 GetOpenFile(io, fptr);
3706 rb_io_check_writable(fptr);
3707
3708 if (io_fflush(fptr) < 0)
3709 rb_sys_fail_on_write(fptr);
3710
3711 rb_fd_set_nonblock(fptr->fd);
3712 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3713 RB_GC_GUARD(str);
3714
3715 if (n < 0) {
3716 int e = errno;
3717 if (io_again_p(e)) {
3718 if (!ex) {
3719 return sym_wait_writable;
3720 }
3721 else {
3722 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3723 }
3724 }
3725 rb_syserr_fail_path(e, fptr->pathv);
3726 }
3727
3728 return LONG2FIX(n);
3729}
3730
3731/*
3732 * call-seq:
3733 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3734 *
3735 * Reads bytes from the stream; the stream must be opened for reading
3736 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3737 *
3738 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3739 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3740 *
3741 * Returns a string (either a new string or the given +out_string+)
3742 * containing the bytes read.
3743 * The encoding of the string depends on both +maxLen+ and +out_string+:
3744 *
3745 * - +maxlen+ is +nil+: uses internal encoding of +self+
3746 * (regardless of whether +out_string+ was given).
3747 * - +maxlen+ not +nil+:
3748 *
3749 * - +out_string+ given: encoding of +out_string+ not modified.
3750 * - +out_string+ not given: ASCII-8BIT is used.
3751 *
3752 * <b>Without Argument +out_string+</b>
3753 *
3754 * When argument +out_string+ is omitted,
3755 * the returned value is a new string:
3756 *
3757 * f = File.new('t.txt')
3758 * f.read
3759 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3760 * f.rewind
3761 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3762 * f.read(30) # => "rth line\r\nFifth line\r\n"
3763 * f.read(30) # => nil
3764 * f.close
3765 *
3766 * If +maxlen+ is zero, returns an empty string.
3767 *
3768 * <b> With Argument +out_string+</b>
3769 *
3770 * When argument +out_string+ is given,
3771 * the returned value is +out_string+, whose content is replaced:
3772 *
3773 * f = File.new('t.txt')
3774 * s = 'foo' # => "foo"
3775 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3776 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3777 * f.rewind
3778 * s = 'bar'
3779 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3780 * s # => "First line\r\nSecond line\r\n\r\nFou"
3781 * s = 'baz'
3782 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3783 * s # => "rth line\r\nFifth line\r\n"
3784 * s = 'bat'
3785 * f.read(30, s) # => nil
3786 * s # => ""
3787 * f.close
3788 *
3789 * Note that this method behaves like the fread() function in C.
3790 * This means it retries to invoke read(2) system calls to read data
3791 * with the specified maxlen (or until EOF).
3792 *
3793 * This behavior is preserved even if the stream is in non-blocking mode.
3794 * (This method is non-blocking-flag insensitive as other methods.)
3795 *
3796 * If you need the behavior like a single read(2) system call,
3797 * consider #readpartial, #read_nonblock, and #sysread.
3798 *
3799 * Related: IO#write.
3800 */
3801
3802static VALUE
3803io_read(int argc, VALUE *argv, VALUE io)
3804{
3805 rb_io_t *fptr;
3806 long n, len;
3807 VALUE length, str;
3808 int shrinkable;
3809#if RUBY_CRLF_ENVIRONMENT
3810 int previous_mode;
3811#endif
3812
3813 rb_scan_args(argc, argv, "02", &length, &str);
3814
3815 if (NIL_P(length)) {
3816 GetOpenFile(io, fptr);
3817 rb_io_check_char_readable(fptr);
3818 return read_all(fptr, remain_size(fptr), str);
3819 }
3820 len = NUM2LONG(length);
3821 if (len < 0) {
3822 rb_raise(rb_eArgError, "negative length %ld given", len);
3823 }
3824
3825 shrinkable = io_setstrbuf(&str,len);
3826
3827 GetOpenFile(io, fptr);
3828 rb_io_check_byte_readable(fptr);
3829 if (len == 0) {
3830 io_set_read_length(str, 0, shrinkable);
3831 return str;
3832 }
3833
3834 READ_CHECK(fptr);
3835#if RUBY_CRLF_ENVIRONMENT
3836 previous_mode = set_binary_mode_with_seek_cur(fptr);
3837#endif
3838 n = io_fread(str, 0, len, fptr);
3839 io_set_read_length(str, n, shrinkable);
3840#if RUBY_CRLF_ENVIRONMENT
3841 if (previous_mode == O_TEXT) {
3842 setmode(fptr->fd, O_TEXT);
3843 }
3844#endif
3845 if (n == 0) return Qnil;
3846
3847 return str;
3848}
3849
3850static void
3851rscheck(const char *rsptr, long rslen, VALUE rs)
3852{
3853 if (!rs) return;
3854 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3855 rb_raise(rb_eRuntimeError, "rs modified");
3856}
3857
3858static const char *
3859search_delim(const char *p, long len, int delim, rb_encoding *enc)
3860{
3861 if (rb_enc_mbminlen(enc) == 1) {
3862 p = memchr(p, delim, len);
3863 if (p) return p + 1;
3864 }
3865 else {
3866 const char *end = p + len;
3867 while (p < end) {
3868 int r = rb_enc_precise_mbclen(p, end, enc);
3869 if (!MBCLEN_CHARFOUND_P(r)) {
3870 p += rb_enc_mbminlen(enc);
3871 continue;
3872 }
3873 int n = MBCLEN_CHARFOUND_LEN(r);
3874 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3875 return p + n;
3876 }
3877 p += n;
3878 }
3879 }
3880 return NULL;
3881}
3882
3883static int
3884appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3885{
3886 VALUE str = *strp;
3887 long limit = *lp;
3888
3889 if (NEED_READCONV(fptr)) {
3890 SET_BINARY_MODE(fptr);
3891 make_readconv(fptr, 0);
3892 do {
3893 const char *p, *e;
3894 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3895 if (searchlen) {
3896 p = READ_CHAR_PENDING_PTR(fptr);
3897 if (0 < limit && limit < searchlen)
3898 searchlen = (int)limit;
3899 e = search_delim(p, searchlen, delim, enc);
3900 if (e) {
3901 int len = (int)(e-p);
3902 if (NIL_P(str))
3903 *strp = str = rb_str_new(p, len);
3904 else
3905 rb_str_buf_cat(str, p, len);
3906 fptr->cbuf.off += len;
3907 fptr->cbuf.len -= len;
3908 limit -= len;
3909 *lp = limit;
3910 return delim;
3911 }
3912
3913 if (NIL_P(str))
3914 *strp = str = rb_str_new(p, searchlen);
3915 else
3916 rb_str_buf_cat(str, p, searchlen);
3917 fptr->cbuf.off += searchlen;
3918 fptr->cbuf.len -= searchlen;
3919 limit -= searchlen;
3920
3921 if (limit == 0) {
3922 *lp = limit;
3923 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3924 }
3925 }
3926 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3927 clear_readconv(fptr);
3928 *lp = limit;
3929 return EOF;
3930 }
3931
3932 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3933 do {
3934 long pending = READ_DATA_PENDING_COUNT(fptr);
3935 if (pending > 0) {
3936 const char *p = READ_DATA_PENDING_PTR(fptr);
3937 const char *e;
3938 long last;
3939
3940 if (limit > 0 && pending > limit) pending = limit;
3941 e = search_delim(p, pending, delim, enc);
3942 if (e) pending = e - p;
3943 if (!NIL_P(str)) {
3944 last = RSTRING_LEN(str);
3945 rb_str_resize(str, last + pending);
3946 }
3947 else {
3948 last = 0;
3949 *strp = str = rb_str_buf_new(pending);
3950 rb_str_set_len(str, pending);
3951 }
3952 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3953 limit -= pending;
3954 *lp = limit;
3955 if (e) return delim;
3956 if (limit == 0)
3957 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3958 }
3959 READ_CHECK(fptr);
3960 } while (io_fillbuf(fptr) >= 0);
3961 *lp = limit;
3962 return EOF;
3963}
3964
3965static inline int
3966swallow(rb_io_t *fptr, int term)
3967{
3968 if (NEED_READCONV(fptr)) {
3969 rb_encoding *enc = io_read_encoding(fptr);
3970 int needconv = rb_enc_mbminlen(enc) != 1;
3971 SET_BINARY_MODE(fptr);
3972 make_readconv(fptr, 0);
3973 do {
3974 size_t cnt;
3975 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3976 const char *p = READ_CHAR_PENDING_PTR(fptr);
3977 int i;
3978 if (!needconv) {
3979 if (*p != term) return TRUE;
3980 i = (int)cnt;
3981 while (--i && *++p == term);
3982 }
3983 else {
3984 const char *e = p + cnt;
3985 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3986 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3987 i = (int)(e - p);
3988 }
3989 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3990 }
3991 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3992 return FALSE;
3993 }
3994
3995 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3996 do {
3997 size_t cnt;
3998 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3999 char buf[1024];
4000 const char *p = READ_DATA_PENDING_PTR(fptr);
4001 int i;
4002 if (cnt > sizeof buf) cnt = sizeof buf;
4003 if (*p != term) return TRUE;
4004 i = (int)cnt;
4005 while (--i && *++p == term);
4006 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4007 rb_sys_fail_path(fptr->pathv);
4008 }
4009 READ_CHECK(fptr);
4010 } while (io_fillbuf(fptr) == 0);
4011 return FALSE;
4012}
4013
4014static VALUE
4015rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4016{
4017 VALUE str = Qnil;
4018 int len = 0;
4019 long pos = 0;
4020 int cr = 0;
4021
4022 do {
4023 int pending = READ_DATA_PENDING_COUNT(fptr);
4024
4025 if (pending > 0) {
4026 const char *p = READ_DATA_PENDING_PTR(fptr);
4027 const char *e;
4028 int chomplen = 0;
4029
4030 e = memchr(p, '\n', pending);
4031 if (e) {
4032 pending = (int)(e - p + 1);
4033 if (chomp) {
4034 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4035 }
4036 }
4037 if (NIL_P(str)) {
4038 str = rb_str_new(p, pending - chomplen);
4039 fptr->rbuf.off += pending;
4040 fptr->rbuf.len -= pending;
4041 }
4042 else {
4043 rb_str_resize(str, len + pending - chomplen);
4044 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4045 fptr->rbuf.off += chomplen;
4046 fptr->rbuf.len -= chomplen;
4047 if (pending == 1 && chomplen == 1 && len > 0) {
4048 if (RSTRING_PTR(str)[len-1] == '\r') {
4049 rb_str_resize(str, --len);
4050 break;
4051 }
4052 }
4053 }
4054 len += pending - chomplen;
4055 if (cr != ENC_CODERANGE_BROKEN)
4056 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4057 if (e) break;
4058 }
4059 READ_CHECK(fptr);
4060 } while (io_fillbuf(fptr) >= 0);
4061 if (NIL_P(str)) return Qnil;
4062
4063 str = io_enc_str(str, fptr);
4064 ENC_CODERANGE_SET(str, cr);
4065 fptr->lineno++;
4066
4067 return str;
4068}
4069
4070 struct getline_arg {
4071 VALUE io;
4072 VALUE rs;
4073 long limit;
4074 unsigned int chomp: 1;
4075};
4076
4077static void
4078extract_getline_opts(VALUE opts, struct getline_arg *args)
4079{
4080 int chomp = FALSE;
4081 if (!NIL_P(opts)) {
4082 static ID kwds[1];
4083 VALUE vchomp;
4084 if (!kwds[0]) {
4085 kwds[0] = rb_intern_const("chomp");
4086 }
4087 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4088 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4089 }
4090 args->chomp = chomp;
4091}
4092
4093static void
4094extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4095{
4096 VALUE rs = rb_rs, lim = Qnil;
4097
4098 if (argc == 1) {
4099 VALUE tmp = Qnil;
4100
4101 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4102 rs = tmp;
4103 }
4104 else {
4105 lim = argv[0];
4106 }
4107 }
4108 else if (2 <= argc) {
4109 rs = argv[0], lim = argv[1];
4110 if (!NIL_P(rs))
4111 StringValue(rs);
4112 }
4113 args->rs = rs;
4114 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4115}
4116
4117static void
4118check_getline_args(VALUE *rsp, long *limit, VALUE io)
4119{
4120 rb_io_t *fptr;
4121 VALUE rs = *rsp;
4122
4123 if (!NIL_P(rs)) {
4124 rb_encoding *enc_rs, *enc_io;
4125
4126 GetOpenFile(io, fptr);
4127 enc_rs = rb_enc_get(rs);
4128 enc_io = io_read_encoding(fptr);
4129 if (enc_io != enc_rs &&
4130 (!is_ascii_string(rs) ||
4131 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4132 if (rs == rb_default_rs) {
4133 rs = rb_enc_str_new(0, 0, enc_io);
4134 rb_str_buf_cat_ascii(rs, "\n");
4135 *rsp = rs;
4136 }
4137 else {
4138 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4139 rb_enc_name(enc_io),
4140 rb_enc_name(enc_rs));
4141 }
4142 }
4143 }
4144}
4145
4146static void
4147prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4148{
4149 VALUE opts;
4150 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4151 extract_getline_args(argc, argv, args);
4152 extract_getline_opts(opts, args);
4153 check_getline_args(&args->rs, &args->limit, io);
4154}
4155
4156static VALUE
4157rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4158{
4159 VALUE str = Qnil;
4160 int nolimit = 0;
4161 rb_encoding *enc;
4162
4163 rb_io_check_char_readable(fptr);
4164 if (NIL_P(rs) && limit < 0) {
4165 str = read_all(fptr, 0, Qnil);
4166 if (RSTRING_LEN(str) == 0) return Qnil;
4167 }
4168 else if (limit == 0) {
4169 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4170 }
4171 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4172 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4173 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4174 return rb_io_getline_fast(fptr, enc, chomp);
4175 }
4176 else {
4177 int c, newline = -1;
4178 const char *rsptr = 0;
4179 long rslen = 0;
4180 int rspara = 0;
4181 int extra_limit = 16;
4182 int chomp_cr = chomp;
4183
4184 SET_BINARY_MODE(fptr);
4185 enc = io_read_encoding(fptr);
4186
4187 if (!NIL_P(rs)) {
4188 rslen = RSTRING_LEN(rs);
4189 if (rslen == 0) {
4190 rsptr = "\n\n";
4191 rslen = 2;
4192 rspara = 1;
4193 swallow(fptr, '\n');
4194 rs = 0;
4195 if (!rb_enc_asciicompat(enc)) {
4196 rs = rb_usascii_str_new(rsptr, rslen);
4197 rs = rb_str_conv_enc(rs, 0, enc);
4198 OBJ_FREEZE(rs);
4199 rsptr = RSTRING_PTR(rs);
4200 rslen = RSTRING_LEN(rs);
4201 }
4202 newline = '\n';
4203 }
4204 else if (rb_enc_mbminlen(enc) == 1) {
4205 rsptr = RSTRING_PTR(rs);
4206 newline = (unsigned char)rsptr[rslen - 1];
4207 }
4208 else {
4209 rs = rb_str_conv_enc(rs, 0, enc);
4210 rsptr = RSTRING_PTR(rs);
4211 const char *e = rsptr + rslen;
4212 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4213 int n;
4214 newline = rb_enc_codepoint_len(last, e, &n, enc);
4215 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4216 }
4217 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4218 }
4219
4220 /* MS - Optimization */
4221 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4222 const char *s, *p, *pp, *e;
4223
4224 if (c == newline) {
4225 if (RSTRING_LEN(str) < rslen) continue;
4226 s = RSTRING_PTR(str);
4227 e = RSTRING_END(str);
4228 p = e - rslen;
4229 if (!at_char_boundary(s, p, e, enc)) continue;
4230 if (!rspara) rscheck(rsptr, rslen, rs);
4231 if (memcmp(p, rsptr, rslen) == 0) {
4232 if (chomp) {
4233 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4234 rb_str_set_len(str, p - s);
4235 }
4236 break;
4237 }
4238 }
4239 if (limit == 0) {
4240 s = RSTRING_PTR(str);
4241 p = RSTRING_END(str);
4242 pp = rb_enc_prev_char(s, p, p, enc);
4243 if (extra_limit && pp &&
4244 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4245 /* relax the limit while incomplete character.
4246 * extra_limit limits the relax length */
4247 limit = 1;
4248 extra_limit--;
4249 }
4250 else {
4251 nolimit = 1;
4252 break;
4253 }
4254 }
4255 }
4256
4257 if (rspara && c != EOF)
4258 swallow(fptr, '\n');
4259 if (!NIL_P(str))
4260 str = io_enc_str(str, fptr);
4261 }
4262
4263 if (!NIL_P(str) && !nolimit) {
4264 fptr->lineno++;
4265 }
4266
4267 return str;
4268}
4269
4270static VALUE
4271rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4272{
4273 rb_io_t *fptr;
4274 int old_lineno, new_lineno;
4275 VALUE str;
4276
4277 GetOpenFile(io, fptr);
4278 old_lineno = fptr->lineno;
4279 str = rb_io_getline_0(rs, limit, chomp, fptr);
4280 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4281 if (io == ARGF.current_file) {
4282 ARGF.lineno += new_lineno - old_lineno;
4283 ARGF.last_lineno = ARGF.lineno;
4284 }
4285 else {
4286 ARGF.last_lineno = new_lineno;
4287 }
4288 }
4289
4290 return str;
4291}
4292
4293static VALUE
4294rb_io_getline(int argc, VALUE *argv, VALUE io)
4295{
4296 struct getline_arg args;
4297
4298 prepare_getline_args(argc, argv, &args, io);
4299 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4300}
4301
4302 VALUE
4303rb_io_gets(VALUE io)
4304{
4305 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4306}
4307
4308 VALUE
4309rb_io_gets_internal(VALUE io)
4310{
4311 rb_io_t *fptr;
4312 GetOpenFile(io, fptr);
4313 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4314}
4315
4316/*
4317 * call-seq:
4318 * gets(sep = $/, chomp: false) -> string or nil
4319 * gets(limit, chomp: false) -> string or nil
4320 * gets(sep, limit, chomp: false) -> string or nil
4321 *
4322 * Reads and returns a line from the stream;
4323 * assigns the return value to <tt>$_</tt>.
4324 * See {Line IO}[rdoc-ref:IO@Line+IO].
4325 *
4326 * With no arguments given, returns the next line
4327 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4328 *
4329 * f = File.open('t.txt')
4330 * f.gets # => "First line\n"
4331 * $_ # => "First line\n"
4332 * f.gets # => "\n"
4333 * f.gets # => "Fourth line\n"
4334 * f.gets # => "Fifth line\n"
4335 * f.gets # => nil
4336 * f.close
4337 *
4338 * With only string argument +sep+ given,
4339 * returns the next line as determined by line separator +sep+,
4340 * or +nil+ if none;
4341 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4342 *
4343 * f = File.new('t.txt')
4344 * f.gets('l') # => "First l"
4345 * f.gets('li') # => "ine\nSecond li"
4346 * f.gets('lin') # => "ne\n\nFourth lin"
4347 * f.gets # => "e\n"
4348 * f.close
4349 *
4350 * The two special values for +sep+ are honored:
4351 *
4352 * f = File.new('t.txt')
4353 * # Get all.
4354 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4355 * f.rewind
4356 * # Get paragraph (up to two line separators).
4357 * f.gets('') # => "First line\nSecond line\n\n"
4358 * f.close
4359 *
4360 * With only integer argument +limit+ given,
4361 * limits the number of bytes in the line;
4362 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4363 *
4364 * # No more than one line.
4365 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4366 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4367 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4368 *
4369 * With arguments +sep+ and +limit+ given,
4370 * combines the two behaviors
4371 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4372 *
4373 * Optional keyword argument +chomp+ specifies whether line separators
4374 * are to be omitted:
4375 *
4376 * f = File.open('t.txt')
4377 * # Chomp the lines.
4378 * f.gets(chomp: true) # => "First line"
4379 * f.gets(chomp: true) # => "Second line"
4380 * f.gets(chomp: true) # => ""
4381 * f.gets(chomp: true) # => "Fourth line"
4382 * f.gets(chomp: true) # => "Fifth line"
4383 * f.gets(chomp: true) # => nil
4384 * f.close
4385 *
4386 */
4387
4388static VALUE
4389rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4390{
4391 VALUE str;
4392
4393 str = rb_io_getline(argc, argv, io);
4394 rb_lastline_set(str);
4395
4396 return str;
4397}
4398
4399/*
4400 * call-seq:
4401 * lineno -> integer
4402 *
4403 * Returns the current line number for the stream;
4404 * see {Line Number}[rdoc-ref:IO@Line+Number].
4405 *
4406 */
4407
4408static VALUE
4409rb_io_lineno(VALUE io)
4410{
4411 rb_io_t *fptr;
4412
4413 GetOpenFile(io, fptr);
4414 rb_io_check_char_readable(fptr);
4415 return INT2NUM(fptr->lineno);
4416}
4417
4418/*
4419 * call-seq:
4420 * lineno = integer -> integer
4421 *
4422 * Sets and returns the line number for the stream;
4423 * see {Line Number}[rdoc-ref:IO@Line+Number].
4424 *
4425 */
4426
4427static VALUE
4428rb_io_set_lineno(VALUE io, VALUE lineno)
4429{
4430 rb_io_t *fptr;
4431
4432 GetOpenFile(io, fptr);
4433 rb_io_check_char_readable(fptr);
4434 fptr->lineno = NUM2INT(lineno);
4435 return lineno;
4436}
4437
4438/* :nodoc: */
4439static VALUE
4440io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4441{
4442 long limit = -1;
4443 if (NIL_P(lim)) {
4444 VALUE tmp = Qnil;
4445 // If sep is specified, but it's not a string and not nil, then assume
4446 // it's the limit (it should be an integer)
4447 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4448 // If the user has specified a non-nil / non-string value
4449 // for the separator, we assume it's the limit and set the
4450 // separator to default: rb_rs.
4451 lim = sep;
4452 limit = NUM2LONG(lim);
4453 sep = rb_rs;
4454 }
4455 else {
4456 sep = tmp;
4457 }
4458 }
4459 else {
4460 if (!NIL_P(sep)) StringValue(sep);
4461 limit = NUM2LONG(lim);
4462 }
4463
4464 check_getline_args(&sep, &limit, io);
4465
4466 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4467 rb_lastline_set_up(line, 1);
4468
4469 if (NIL_P(line)) {
4470 rb_eof_error();
4471 }
4472 return line;
4473}
4474
4475static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4476
4477/*
4478 * call-seq:
4479 * readlines(sep = $/, chomp: false) -> array
4480 * readlines(limit, chomp: false) -> array
4481 * readlines(sep, limit, chomp: false) -> array
4482 *
4483 * Reads and returns all remaining line from the stream;
4484 * does not modify <tt>$_</tt>.
4485 * See {Line IO}[rdoc-ref:IO@Line+IO].
4486 *
4487 * With no arguments given, returns lines
4488 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4489 *
4490 * f = File.new('t.txt')
4491 * f.readlines
4492 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4493 * f.readlines # => []
4494 * f.close
4495 *
4496 * With only string argument +sep+ given,
4497 * returns lines as determined by line separator +sep+,
4498 * or +nil+ if none;
4499 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4500 *
4501 * f = File.new('t.txt')
4502 * f.readlines('li')
4503 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4504 * f.close
4505 *
4506 * The two special values for +sep+ are honored:
4507 *
4508 * f = File.new('t.txt')
4509 * # Get all into one string.
4510 * f.readlines(nil)
4511 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4512 * # Get paragraphs (up to two line separators).
4513 * f.rewind
4514 * f.readlines('')
4515 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4516 * f.close
4517 *
4518 * With only integer argument +limit+ given,
4519 * limits the number of bytes in each line;
4520 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4521 *
4522 * f = File.new('t.txt')
4523 * f.readlines(8)
4524 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4525 * f.close
4526 *
4527 * With arguments +sep+ and +limit+ given,
4528 * combines the two behaviors
4529 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4530 *
4531 * Optional keyword argument +chomp+ specifies whether line separators
4532 * are to be omitted:
4533 *
4534 * f = File.new('t.txt')
4535 * f.readlines(chomp: true)
4536 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4537 * f.close
4538 *
4539 */
4540
4541static VALUE
4542rb_io_readlines(int argc, VALUE *argv, VALUE io)
4543{
4544 struct getline_arg args;
4545
4546 prepare_getline_args(argc, argv, &args, io);
4547 return io_readlines(&args, io);
4548}
4549
4550static VALUE
4551io_readlines(const struct getline_arg *arg, VALUE io)
4552{
4553 VALUE line, ary;
4554
4555 if (arg->limit == 0)
4556 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4557 ary = rb_ary_new();
4558 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4559 rb_ary_push(ary, line);
4560 }
4561 return ary;
4562}
4563
4564/*
4565 * call-seq:
4566 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4567 * each_line(limit, chomp: false) {|line| ... } -> self
4568 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4569 * each_line -> enumerator
4570 *
4571 * Calls the block with each remaining line read from the stream;
4572 * returns +self+.
4573 * Does nothing if already at end-of-stream;
4574 * See {Line IO}[rdoc-ref:IO@Line+IO].
4575 *
4576 * With no arguments given, reads lines
4577 * as determined by line separator <tt>$/</tt>:
4578 *
4579 * f = File.new('t.txt')
4580 * f.each_line {|line| p line }
4581 * f.each_line {|line| fail 'Cannot happen' }
4582 * f.close
4583 *
4584 * Output:
4585 *
4586 * "First line\n"
4587 * "Second line\n"
4588 * "\n"
4589 * "Fourth line\n"
4590 * "Fifth line\n"
4591 *
4592 * With only string argument +sep+ given,
4593 * reads lines as determined by line separator +sep+;
4594 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4595 *
4596 * f = File.new('t.txt')
4597 * f.each_line('li') {|line| p line }
4598 * f.close
4599 *
4600 * Output:
4601 *
4602 * "First li"
4603 * "ne\nSecond li"
4604 * "ne\n\nFourth li"
4605 * "ne\nFifth li"
4606 * "ne\n"
4607 *
4608 * The two special values for +sep+ are honored:
4609 *
4610 * f = File.new('t.txt')
4611 * # Get all into one string.
4612 * f.each_line(nil) {|line| p line }
4613 * f.close
4614 *
4615 * Output:
4616 *
4617 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4618 *
4619 * f.rewind
4620 * # Get paragraphs (up to two line separators).
4621 * f.each_line('') {|line| p line }
4622 *
4623 * Output:
4624 *
4625 * "First line\nSecond line\n\n"
4626 * "Fourth line\nFifth line\n"
4627 *
4628 * With only integer argument +limit+ given,
4629 * limits the number of bytes in each line;
4630 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4631 *
4632 * f = File.new('t.txt')
4633 * f.each_line(8) {|line| p line }
4634 * f.close
4635 *
4636 * Output:
4637 *
4638 * "First li"
4639 * "ne\n"
4640 * "Second l"
4641 * "ine\n"
4642 * "\n"
4643 * "Fourth l"
4644 * "ine\n"
4645 * "Fifth li"
4646 * "ne\n"
4647 *
4648 * With arguments +sep+ and +limit+ given,
4649 * combines the two behaviors
4650 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4651 *
4652 * Optional keyword argument +chomp+ specifies whether line separators
4653 * are to be omitted:
4654 *
4655 * f = File.new('t.txt')
4656 * f.each_line(chomp: true) {|line| p line }
4657 * f.close
4658 *
4659 * Output:
4660 *
4661 * "First line"
4662 * "Second line"
4663 * ""
4664 * "Fourth line"
4665 * "Fifth line"
4666 *
4667 * Returns an Enumerator if no block is given.
4668 */
4669
4670static VALUE
4671rb_io_each_line(int argc, VALUE *argv, VALUE io)
4672{
4673 VALUE str;
4674 struct getline_arg args;
4675
4676 RETURN_ENUMERATOR(io, argc, argv);
4677 prepare_getline_args(argc, argv, &args, io);
4678 if (args.limit == 0)
4679 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4680 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4681 rb_yield(str);
4682 }
4683 return io;
4684}
4685
4686/*
4687 * call-seq:
4688 * each_byte {|byte| ... } -> self
4689 * each_byte -> enumerator
4690 *
4691 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4692 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4693 *
4694 * f = File.new('t.rus')
4695 * a = []
4696 * f.each_byte {|b| a << b }
4697 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4698 * f.close
4699 *
4700 * Returns an Enumerator if no block is given.
4701 *
4702 * Related: IO#each_char, IO#each_codepoint.
4703 *
4704 */
4705
4706static VALUE
4707rb_io_each_byte(VALUE io)
4708{
4709 rb_io_t *fptr;
4710
4711 RETURN_ENUMERATOR(io, 0, 0);
4712 GetOpenFile(io, fptr);
4713
4714 do {
4715 while (fptr->rbuf.len > 0) {
4716 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4717 fptr->rbuf.len--;
4718 rb_yield(INT2FIX(*p & 0xff));
4719 rb_io_check_byte_readable(fptr);
4720 errno = 0;
4721 }
4722 READ_CHECK(fptr);
4723 } while (io_fillbuf(fptr) >= 0);
4724 return io;
4725}
4726
4727static VALUE
4728io_getc(rb_io_t *fptr, rb_encoding *enc)
4729{
4730 int r, n, cr = 0;
4731 VALUE str;
4732
4733 if (NEED_READCONV(fptr)) {
4734 rb_encoding *read_enc = io_read_encoding(fptr);
4735
4736 str = Qnil;
4737 SET_BINARY_MODE(fptr);
4738 make_readconv(fptr, 0);
4739
4740 while (1) {
4741 if (fptr->cbuf.len) {
4742 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4743 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4744 read_enc);
4745 if (!MBCLEN_NEEDMORE_P(r))
4746 break;
4747 if (fptr->cbuf.len == fptr->cbuf.capa) {
4748 rb_raise(rb_eIOError, "too long character");
4749 }
4750 }
4751
4752 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4753 if (fptr->cbuf.len == 0) {
4754 clear_readconv(fptr);
4755 return Qnil;
4756 }
4757 /* return an unit of an incomplete character just before EOF */
4758 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4759 fptr->cbuf.off += 1;
4760 fptr->cbuf.len -= 1;
4761 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4762 ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
4763 return str;
4764 }
4765 }
4766 if (MBCLEN_INVALID_P(r)) {
4767 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4768 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4769 read_enc);
4770 io_shift_cbuf(fptr, r, &str);
4771 cr = ENC_CODERANGE_BROKEN;
4772 }
4773 else {
4774 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4775 cr = ENC_CODERANGE_VALID;
4776 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4777 ISASCII(RSTRING_PTR(str)[0])) {
4778 cr = ENC_CODERANGE_7BIT;
4779 }
4780 }
4781 str = io_enc_str(str, fptr);
4782 ENC_CODERANGE_SET(str, cr);
4783 return str;
4784 }
4785
4786 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4787 if (io_fillbuf(fptr) < 0) {
4788 return Qnil;
4789 }
4790 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4791 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4792 fptr->rbuf.off += 1;
4793 fptr->rbuf.len -= 1;
4794 cr = ENC_CODERANGE_7BIT;
4795 }
4796 else {
4797 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4798 if (MBCLEN_CHARFOUND_P(r) &&
4799 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4800 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4801 fptr->rbuf.off += n;
4802 fptr->rbuf.len -= n;
4803 cr = ENC_CODERANGE_VALID;
4804 }
4805 else if (MBCLEN_NEEDMORE_P(r)) {
4806 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4807 fptr->rbuf.len = 0;
4808 getc_needmore:
4809 if (io_fillbuf(fptr) != -1) {
4810 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4811 fptr->rbuf.off++;
4812 fptr->rbuf.len--;
4813 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4814 if (MBCLEN_NEEDMORE_P(r)) {
4815 goto getc_needmore;
4816 }
4817 else if (MBCLEN_CHARFOUND_P(r)) {
4818 cr = ENC_CODERANGE_VALID;
4819 }
4820 }
4821 }
4822 else {
4823 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4824 fptr->rbuf.off++;
4825 fptr->rbuf.len--;
4826 }
4827 }
4828 if (!cr) cr = ENC_CODERANGE_BROKEN;
4829 str = io_enc_str(str, fptr);
4830 ENC_CODERANGE_SET(str, cr);
4831 return str;
4832}
4833
4834/*
4835 * call-seq:
4836 * each_char {|c| ... } -> self
4837 * each_char -> enumerator
4838 *
4839 * Calls the given block with each character in the stream; returns +self+.
4840 * See {Character IO}[rdoc-ref:IO@Character+IO].
4841 *
4842 * f = File.new('t.rus')
4843 * a = []
4844 * f.each_char {|c| a << c.ord }
4845 * a # => [1090, 1077, 1089, 1090]
4846 * f.close
4847 *
4848 * Returns an Enumerator if no block is given.
4849 *
4850 * Related: IO#each_byte, IO#each_codepoint.
4851 *
4852 */
4853
4854static VALUE
4855rb_io_each_char(VALUE io)
4856{
4857 rb_io_t *fptr;
4858 rb_encoding *enc;
4859 VALUE c;
4860
4861 RETURN_ENUMERATOR(io, 0, 0);
4862 GetOpenFile(io, fptr);
4863 rb_io_check_char_readable(fptr);
4864
4865 enc = io_input_encoding(fptr);
4866 READ_CHECK(fptr);
4867 while (!NIL_P(c = io_getc(fptr, enc))) {
4868 rb_yield(c);
4869 }
4870 return io;
4871}
4872
4873/*
4874 * call-seq:
4875 * each_codepoint {|c| ... } -> self
4876 * each_codepoint -> enumerator
4877 *
4878 * Calls the given block with each codepoint in the stream; returns +self+:
4879 *
4880 * f = File.new('t.rus')
4881 * a = []
4882 * f.each_codepoint {|c| a << c }
4883 * a # => [1090, 1077, 1089, 1090]
4884 * f.close
4885 *
4886 * Returns an Enumerator if no block is given.
4887 *
4888 * Related: IO#each_byte, IO#each_char.
4889 *
4890 */
4891
4892static VALUE
4893rb_io_each_codepoint(VALUE io)
4894{
4895 rb_io_t *fptr;
4896 rb_encoding *enc;
4897 unsigned int c;
4898 int r, n;
4899
4900 RETURN_ENUMERATOR(io, 0, 0);
4901 GetOpenFile(io, fptr);
4902 rb_io_check_char_readable(fptr);
4903
4904 READ_CHECK(fptr);
4905 if (NEED_READCONV(fptr)) {
4906 SET_BINARY_MODE(fptr);
4907 r = 1; /* no invalid char yet */
4908 for (;;) {
4909 make_readconv(fptr, 0);
4910 for (;;) {
4911 if (fptr->cbuf.len) {
4912 if (fptr->encs.enc)
4913 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4914 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4915 fptr->encs.enc);
4916 else
4917 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4918 if (!MBCLEN_NEEDMORE_P(r))
4919 break;
4920 if (fptr->cbuf.len == fptr->cbuf.capa) {
4921 rb_raise(rb_eIOError, "too long character");
4922 }
4923 }
4924 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4925 clear_readconv(fptr);
4926 if (!MBCLEN_CHARFOUND_P(r)) {
4927 enc = fptr->encs.enc;
4928 goto invalid;
4929 }
4930 return io;
4931 }
4932 }
4933 if (MBCLEN_INVALID_P(r)) {
4934 enc = fptr->encs.enc;
4935 goto invalid;
4936 }
4937 n = MBCLEN_CHARFOUND_LEN(r);
4938 if (fptr->encs.enc) {
4939 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4940 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4941 fptr->encs.enc);
4942 }
4943 else {
4944 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4945 }
4946 fptr->cbuf.off += n;
4947 fptr->cbuf.len -= n;
4948 rb_yield(UINT2NUM(c));
4949 rb_io_check_byte_readable(fptr);
4950 }
4951 }
4952 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4953 enc = io_input_encoding(fptr);
4954 while (io_fillbuf(fptr) >= 0) {
4955 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4956 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4957 if (MBCLEN_CHARFOUND_P(r) &&
4958 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4959 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4960 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4961 fptr->rbuf.off += n;
4962 fptr->rbuf.len -= n;
4963 rb_yield(UINT2NUM(c));
4964 }
4965 else if (MBCLEN_INVALID_P(r)) {
4966 goto invalid;
4967 }
4968 else if (MBCLEN_NEEDMORE_P(r)) {
4969 char cbuf[8], *p = cbuf;
4970 int more = MBCLEN_NEEDMORE_LEN(r);
4971 if (more > numberof(cbuf)) goto invalid;
4972 more += n = fptr->rbuf.len;
4973 if (more > numberof(cbuf)) goto invalid;
4974 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4975 (p += n, (more -= n) > 0)) {
4976 if (io_fillbuf(fptr) < 0) goto invalid;
4977 if ((n = fptr->rbuf.len) > more) n = more;
4978 }
4979 r = rb_enc_precise_mbclen(cbuf, p, enc);
4980 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4981 c = rb_enc_codepoint(cbuf, p, enc);
4982 rb_yield(UINT2NUM(c));
4983 }
4984 else {
4985 continue;
4986 }
4987 rb_io_check_byte_readable(fptr);
4988 }
4989 return io;
4990
4991 invalid:
4992 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4993 UNREACHABLE_RETURN(Qundef);
4994}
4995
4996/*
4997 * call-seq:
4998 * getc -> character or nil
4999 *
5000 * Reads and returns the next 1-character string from the stream;
5001 * returns +nil+ if already at end-of-stream.
5002 * See {Character IO}[rdoc-ref:IO@Character+IO].
5003 *
5004 * f = File.open('t.txt')
5005 * f.getc # => "F"
5006 * f.close
5007 * f = File.open('t.rus')
5008 * f.getc.ord # => 1090
5009 * f.close
5010 *
5011 * Related: IO#readchar (may raise EOFError).
5012 *
5013 */
5014
5015static VALUE
5016rb_io_getc(VALUE io)
5017{
5018 rb_io_t *fptr;
5019 rb_encoding *enc;
5020
5021 GetOpenFile(io, fptr);
5022 rb_io_check_char_readable(fptr);
5023
5024 enc = io_input_encoding(fptr);
5025 READ_CHECK(fptr);
5026 return io_getc(fptr, enc);
5027}
5028
5029/*
5030 * call-seq:
5031 * readchar -> string
5032 *
5033 * Reads and returns the next 1-character string from the stream;
5034 * raises EOFError if already at end-of-stream.
5035 * See {Character IO}[rdoc-ref:IO@Character+IO].
5036 *
5037 * f = File.open('t.txt')
5038 * f.readchar # => "F"
5039 * f.close
5040 * f = File.open('t.rus')
5041 * f.readchar.ord # => 1090
5042 * f.close
5043 *
5044 * Related: IO#getc (will not raise EOFError).
5045 *
5046 */
5047
5048static VALUE
5049rb_io_readchar(VALUE io)
5050{
5051 VALUE c = rb_io_getc(io);
5052
5053 if (NIL_P(c)) {
5054 rb_eof_error();
5055 }
5056 return c;
5057}
5058
5059/*
5060 * call-seq:
5061 * getbyte -> integer or nil
5062 *
5063 * Reads and returns the next byte (in range 0..255) from the stream;
5064 * returns +nil+ if already at end-of-stream.
5065 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5066 *
5067 * f = File.open('t.txt')
5068 * f.getbyte # => 70
5069 * f.close
5070 * f = File.open('t.rus')
5071 * f.getbyte # => 209
5072 * f.close
5073 *
5074 * Related: IO#readbyte (may raise EOFError).
5075 */
5076
5077 VALUE
5078rb_io_getbyte(VALUE io)
5079{
5080 rb_io_t *fptr;
5081 int c;
5082
5083 GetOpenFile(io, fptr);
5084 rb_io_check_byte_readable(fptr);
5085 READ_CHECK(fptr);
5086 VALUE r_stdout = rb_ractor_stdout();
5087 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5088 rb_io_t *ofp;
5089 GetOpenFile(r_stdout, ofp);
5090 if (ofp->mode & FMODE_TTY) {
5091 rb_io_flush(r_stdout);
5092 }
5093 }
5094 if (io_fillbuf(fptr) < 0) {
5095 return Qnil;
5096 }
5097 fptr->rbuf.off++;
5098 fptr->rbuf.len--;
5099 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5100 return INT2FIX(c & 0xff);
5101}
5102
5103/*
5104 * call-seq:
5105 * readbyte -> integer
5106 *
5107 * Reads and returns the next byte (in range 0..255) from the stream;
5108 * raises EOFError if already at end-of-stream.
5109 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5110 *
5111 * f = File.open('t.txt')
5112 * f.readbyte # => 70
5113 * f.close
5114 * f = File.open('t.rus')
5115 * f.readbyte # => 209
5116 * f.close
5117 *
5118 * Related: IO#getbyte (will not raise EOFError).
5119 *
5120 */
5121
5122static VALUE
5123rb_io_readbyte(VALUE io)
5124{
5125 VALUE c = rb_io_getbyte(io);
5126
5127 if (NIL_P(c)) {
5128 rb_eof_error();
5129 }
5130 return c;
5131}
5132
5133/*
5134 * call-seq:
5135 * ungetbyte(integer) -> nil
5136 * ungetbyte(string) -> nil
5137 *
5138 * Pushes back ("unshifts") the given data onto the stream's buffer,
5139 * placing the data so that it is next to be read; returns +nil+.
5140 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5141 *
5142 * Note that:
5143 *
5144 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5145 * - Calling #rewind on the stream discards the pushed-back data.
5146 *
5147 * When argument +integer+ is given, uses only its low-order byte:
5148 *
5149 * File.write('t.tmp', '012')
5150 * f = File.open('t.tmp')
5151 * f.ungetbyte(0x41) # => nil
5152 * f.read # => "A012"
5153 * f.rewind
5154 * f.ungetbyte(0x4243) # => nil
5155 * f.read # => "C012"
5156 * f.close
5157 *
5158 * When argument +string+ is given, uses all bytes:
5159 *
5160 * File.write('t.tmp', '012')
5161 * f = File.open('t.tmp')
5162 * f.ungetbyte('A') # => nil
5163 * f.read # => "A012"
5164 * f.rewind
5165 * f.ungetbyte('BCDE') # => nil
5166 * f.read # => "BCDE012"
5167 * f.close
5168 *
5169 */
5170
5171 VALUE
5172rb_io_ungetbyte(VALUE io, VALUE b)
5173{
5174 rb_io_t *fptr;
5175
5176 GetOpenFile(io, fptr);
5177 rb_io_check_byte_readable(fptr);
5178 switch (TYPE(b)) {
5179 case T_NIL:
5180 return Qnil;
5181 case T_FIXNUM:
5182 case T_BIGNUM: ;
5183 VALUE v = rb_int_modulo(b, INT2FIX(256));
5184 unsigned char c = NUM2INT(v) & 0xFF;
5185 b = rb_str_new((const char *)&c, 1);
5186 break;
5187 default:
5188 StringValue(b);
5189 }
5190 io_ungetbyte(b, fptr);
5191 return Qnil;
5192}
5193
5194/*
5195 * call-seq:
5196 * ungetc(integer) -> nil
5197 * ungetc(string) -> nil
5198 *
5199 * Pushes back ("unshifts") the given data onto the stream's buffer,
5200 * placing the data so that it is next to be read; returns +nil+.
5201 * See {Character IO}[rdoc-ref:IO@Character+IO].
5202 *
5203 * Note that:
5204 *
5205 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5206 * - Calling #rewind on the stream discards the pushed-back data.
5207 *
5208 * When argument +integer+ is given, interprets the integer as a character:
5209 *
5210 * File.write('t.tmp', '012')
5211 * f = File.open('t.tmp')
5212 * f.ungetc(0x41) # => nil
5213 * f.read # => "A012"
5214 * f.rewind
5215 * f.ungetc(0x0442) # => nil
5216 * f.getc.ord # => 1090
5217 * f.close
5218 *
5219 * When argument +string+ is given, uses all characters:
5220 *
5221 * File.write('t.tmp', '012')
5222 * f = File.open('t.tmp')
5223 * f.ungetc('A') # => nil
5224 * f.read # => "A012"
5225 * f.rewind
5226 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5227 * f.getc.ord # => 1090
5228 * f.getc.ord # => 1077
5229 * f.getc.ord # => 1089
5230 * f.getc.ord # => 1090
5231 * f.close
5232 *
5233 */
5234
5235 VALUE
5236rb_io_ungetc(VALUE io, VALUE c)
5237{
5238 rb_io_t *fptr;
5239 long len;
5240
5241 GetOpenFile(io, fptr);
5242 rb_io_check_char_readable(fptr);
5243 if (FIXNUM_P(c)) {
5244 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5245 }
5246 else if (RB_BIGNUM_TYPE_P(c)) {
5247 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5248 }
5249 else {
5250 StringValue(c);
5251 }
5252 if (NEED_READCONV(fptr)) {
5253 SET_BINARY_MODE(fptr);
5254 len = RSTRING_LEN(c);
5255#if SIZEOF_LONG > SIZEOF_INT
5256 if (len > INT_MAX)
5257 rb_raise(rb_eIOError, "ungetc failed");
5258#endif
5259 make_readconv(fptr, (int)len);
5260 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5261 rb_raise(rb_eIOError, "ungetc failed");
5262 if (fptr->cbuf.off < len) {
5263 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5264 fptr->cbuf.ptr+fptr->cbuf.off,
5265 char, fptr->cbuf.len);
5266 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5267 }
5268 fptr->cbuf.off -= (int)len;
5269 fptr->cbuf.len += (int)len;
5270 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5271 }
5272 else {
5273 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5274 io_ungetbyte(c, fptr);
5275 }
5276 return Qnil;
5277}
5278
5279/*
5280 * call-seq:
5281 * isatty -> true or false
5282 *
5283 * Returns +true+ if the stream is associated with a terminal device (tty),
5284 * +false+ otherwise:
5285 *
5286 * f = File.new('t.txt').isatty #=> false
5287 * f.close
5288 * f = File.new('/dev/tty').isatty #=> true
5289 * f.close
5290 *
5291 */
5292
5293static VALUE
5294rb_io_isatty(VALUE io)
5295{
5296 rb_io_t *fptr;
5297
5298 GetOpenFile(io, fptr);
5299 return RBOOL(isatty(fptr->fd) != 0);
5300}
5301
5302#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5303/*
5304 * call-seq:
5305 * close_on_exec? -> true or false
5306 *
5307 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5308 *
5309 * f = File.open('t.txt')
5310 * f.close_on_exec? # => true
5311 * f.close_on_exec = false
5312 * f.close_on_exec? # => false
5313 * f.close
5314 *
5315 */
5316
5317static VALUE
5318rb_io_close_on_exec_p(VALUE io)
5319{
5320 rb_io_t *fptr;
5321 VALUE write_io;
5322 int fd, ret;
5323
5324 write_io = GetWriteIO(io);
5325 if (io != write_io) {
5326 GetOpenFile(write_io, fptr);
5327 if (fptr && 0 <= (fd = fptr->fd)) {
5328 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5329 if (!(ret & FD_CLOEXEC)) return Qfalse;
5330 }
5331 }
5332
5333 GetOpenFile(io, fptr);
5334 if (fptr && 0 <= (fd = fptr->fd)) {
5335 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5336 if (!(ret & FD_CLOEXEC)) return Qfalse;
5337 }
5338 return Qtrue;
5339}
5340#else
5341#define rb_io_close_on_exec_p rb_f_notimplement
5342#endif
5343
5344#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5345/*
5346 * call-seq:
5347 * self.close_on_exec = bool -> true or false
5348 *
5349 * Sets a close-on-exec flag.
5350 *
5351 * f = File.open(File::NULL)
5352 * f.close_on_exec = true
5353 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5354 * f.closed? #=> false
5355 *
5356 * Ruby sets close-on-exec flags of all file descriptors by default
5357 * since Ruby 2.0.0.
5358 * So you don't need to set by yourself.
5359 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5360 * if another thread use fork() and exec() (via system() method for example).
5361 * If you really needs file descriptor inheritance to child process,
5362 * use spawn()'s argument such as fd=>fd.
5363 */
5364
5365static VALUE
5366rb_io_set_close_on_exec(VALUE io, VALUE arg)
5367{
5368 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5369 rb_io_t *fptr;
5370 VALUE write_io;
5371 int fd, ret;
5372
5373 write_io = GetWriteIO(io);
5374 if (io != write_io) {
5375 GetOpenFile(write_io, fptr);
5376 if (fptr && 0 <= (fd = fptr->fd)) {
5377 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5378 if ((ret & FD_CLOEXEC) != flag) {
5379 ret = (ret & ~FD_CLOEXEC) | flag;
5380 ret = fcntl(fd, F_SETFD, ret);
5381 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5382 }
5383 }
5384
5385 }
5386
5387 GetOpenFile(io, fptr);
5388 if (fptr && 0 <= (fd = fptr->fd)) {
5389 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5390 if ((ret & FD_CLOEXEC) != flag) {
5391 ret = (ret & ~FD_CLOEXEC) | flag;
5392 ret = fcntl(fd, F_SETFD, ret);
5393 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5394 }
5395 }
5396 return Qnil;
5397}
5398#else
5399#define rb_io_set_close_on_exec rb_f_notimplement
5400#endif
5401
5402#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5403#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5404
5405static VALUE
5406finish_writeconv(rb_io_t *fptr, int noalloc)
5407{
5408 unsigned char *ds, *dp, *de;
5409 rb_econv_result_t res;
5410
5411 if (!fptr->wbuf.ptr) {
5412 unsigned char buf[1024];
5413
5414 res = econv_destination_buffer_full;
5415 while (res == econv_destination_buffer_full) {
5416 ds = dp = buf;
5417 de = buf + sizeof(buf);
5418 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5419 while (dp-ds) {
5420 size_t remaining = dp-ds;
5421 long result = rb_io_write_memory(fptr, ds, remaining);
5422
5423 if (result > 0) {
5424 ds += result;
5425 if ((size_t)result == remaining) break;
5426 }
5427 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5428 if (fptr->fd < 0)
5429 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5430 }
5431 else {
5432 return noalloc ? Qtrue : INT2NUM(errno);
5433 }
5434 }
5435 if (res == econv_invalid_byte_sequence ||
5436 res == econv_incomplete_input ||
5437 res == econv_undefined_conversion) {
5438 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5439 }
5440 }
5441
5442 return Qnil;
5443 }
5444
5445 res = econv_destination_buffer_full;
5446 while (res == econv_destination_buffer_full) {
5447 if (fptr->wbuf.len == fptr->wbuf.capa) {
5448 if (io_fflush(fptr) < 0) {
5449 return noalloc ? Qtrue : INT2NUM(errno);
5450 }
5451 }
5452
5453 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5454 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5455 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5456 fptr->wbuf.len += (int)(dp - ds);
5457 if (res == econv_invalid_byte_sequence ||
5458 res == econv_incomplete_input ||
5459 res == econv_undefined_conversion) {
5460 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5461 }
5462 }
5463 return Qnil;
5464}
5465
5466 struct finish_writeconv_arg {
5467 rb_io_t *fptr;
5468 int noalloc;
5469};
5470
5471static VALUE
5472finish_writeconv_sync(VALUE arg)
5473{
5474 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5475 return finish_writeconv(p->fptr, p->noalloc);
5476}
5477
5478static void*
5479nogvl_close(void *ptr)
5480{
5481 int *fd = ptr;
5482
5483 return (void*)(intptr_t)close(*fd);
5484}
5485
5486static int
5487maygvl_close(int fd, int keepgvl)
5488{
5489 if (keepgvl)
5490 return close(fd);
5491
5492 /*
5493 * close() may block for certain file types (NFS, SO_LINGER sockets,
5494 * inotify), so let other threads run.
5495 */
5496 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5497}
5498
5499static void*
5500nogvl_fclose(void *ptr)
5501{
5502 FILE *file = ptr;
5503
5504 return (void*)(intptr_t)fclose(file);
5505}
5506
5507static int
5508maygvl_fclose(FILE *file, int keepgvl)
5509{
5510 if (keepgvl)
5511 return fclose(file);
5512
5513 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5514}
5515
5516static void free_io_buffer(rb_io_buffer_t *buf);
5517
5518static void
5519fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5520 struct rb_io_close_wait_list *busy)
5521{
5522 VALUE error = Qnil;
5523 int fd = fptr->fd;
5524 FILE *stdio_file = fptr->stdio_file;
5525 int mode = fptr->mode;
5526
5527 if (fptr->writeconv) {
5528 if (!NIL_P(fptr->write_lock) && !noraise) {
5529 struct finish_writeconv_arg arg;
5530 arg.fptr = fptr;
5531 arg.noalloc = noraise;
5532 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5533 }
5534 else {
5535 error = finish_writeconv(fptr, noraise);
5536 }
5537 }
5538 if (fptr->wbuf.len) {
5539 if (noraise) {
5540 io_flush_buffer_sync(fptr);
5541 }
5542 else {
5543 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5544 error = INT2NUM(errno);
5545 }
5546 }
5547 }
5548
5549 int done = 0;
5550
5551 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5552 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5553 done = 1;
5554 }
5555
5556 fptr->fd = -1;
5557 fptr->stdio_file = 0;
5558 fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
5559
5560 // Ensure waiting_fd users do not hit EBADF.
5561 if (busy) {
5562 // Wait for them to exit before we call close().
5563 rb_notify_fd_close_wait(busy);
5564 }
5565
5566 // Disable for now.
5567 // if (!done && fd >= 0) {
5568 // VALUE scheduler = rb_fiber_scheduler_current();
5569 // if (scheduler != Qnil) {
5570 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5571 // if (!UNDEF_P(result)) done = 1;
5572 // }
5573 // }
5574
5575 if (!done && stdio_file) {
5576 // stdio_file is deallocated anyway even if fclose failed.
5577 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5578 if (!noraise) {
5579 error = INT2NUM(errno);
5580 }
5581 }
5582
5583 done = 1;
5584 }
5585
5586 if (!done && fd >= 0) {
5587 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5588 // We assumes it is closed.
5589
5590 keepgvl |= !(mode & FMODE_WRITABLE);
5591 keepgvl |= noraise;
5592 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5593 if (!noraise) {
5594 error = INT2NUM(errno);
5595 }
5596 }
5597
5598 done = 1;
5599 }
5600
5601 if (!NIL_P(error) && !noraise) {
5602 if (RB_INTEGER_TYPE_P(error))
5603 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5604 else
5605 rb_exc_raise(error);
5606 }
5607}
5608
5609static void
5610fptr_finalize(rb_io_t *fptr, int noraise)
5611{
5612 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5613 free_io_buffer(&fptr->rbuf);
5614 free_io_buffer(&fptr->wbuf);
5615 clear_codeconv(fptr);
5616}
5617
5618static void
5619rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5620{
5621 if (fptr->finalize) {
5622 (*fptr->finalize)(fptr, noraise);
5623 }
5624 else {
5625 fptr_finalize(fptr, noraise);
5626 }
5627}
5628
5629static void
5630free_io_buffer(rb_io_buffer_t *buf)
5631{
5632 if (buf->ptr) {
5633 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5634 buf->ptr = NULL;
5635 }
5636}
5637
5638static void
5639clear_readconv(rb_io_t *fptr)
5640{
5641 if (fptr->readconv) {
5642 rb_econv_close(fptr->readconv);
5643 fptr->readconv = NULL;
5644 }
5645 free_io_buffer(&fptr->cbuf);
5646}
5647
5648static void
5649clear_writeconv(rb_io_t *fptr)
5650{
5651 if (fptr->writeconv) {
5652 rb_econv_close(fptr->writeconv);
5653 fptr->writeconv = NULL;
5654 }
5655 fptr->writeconv_initialized = 0;
5656}
5657
5658static void
5659clear_codeconv(rb_io_t *fptr)
5660{
5661 clear_readconv(fptr);
5662 clear_writeconv(fptr);
5663}
5664
5665static void
5666rb_io_fptr_cleanup_all(rb_io_t *fptr)
5667{
5668 fptr->pathv = Qnil;
5669 if (0 <= fptr->fd)
5670 rb_io_fptr_cleanup(fptr, TRUE);
5671 fptr->write_lock = Qnil;
5672 free_io_buffer(&fptr->rbuf);
5673 free_io_buffer(&fptr->wbuf);
5674 clear_codeconv(fptr);
5675}
5676
5677void
5678rb_io_fptr_finalize_internal(void *ptr)
5679{
5680 if (!ptr) return;
5681 rb_io_fptr_cleanup_all(ptr);
5682 free(ptr);
5683}
5684
5685#undef rb_io_fptr_finalize
5686int
5687rb_io_fptr_finalize(rb_io_t *fptr)
5688{
5689 if (!fptr) {
5690 return 0;
5691 }
5692 else {
5693 rb_io_fptr_finalize_internal(fptr);
5694 return 1;
5695 }
5696}
5697#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5698
5699size_t
5700rb_io_memsize(const rb_io_t *fptr)
5701{
5702 size_t size = sizeof(rb_io_t);
5703 size += fptr->rbuf.capa;
5704 size += fptr->wbuf.capa;
5705 size += fptr->cbuf.capa;
5706 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5707 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5708 return size;
5709}
5710
5711#ifdef _WIN32
5712/* keep GVL while closing to prevent crash on Windows */
5713# define KEEPGVL TRUE
5714#else
5715# define KEEPGVL FALSE
5716#endif
5717
5718static rb_io_t *
5719io_close_fptr(VALUE io)
5720{
5721 rb_io_t *fptr;
5722 VALUE write_io;
5723 rb_io_t *write_fptr;
5724 struct rb_io_close_wait_list busy;
5725
5726 write_io = GetWriteIO(io);
5727 if (io != write_io) {
5728 write_fptr = RFILE(write_io)->fptr;
5729 if (write_fptr && 0 <= write_fptr->fd) {
5730 rb_io_fptr_cleanup(write_fptr, TRUE);
5731 }
5732 }
5733
5734 fptr = RFILE(io)->fptr;
5735 if (!fptr) return 0;
5736 if (fptr->fd < 0) return 0;
5737
5738 if (rb_notify_fd_close(fptr->fd, &busy)) {
5739 /* calls close(fptr->fd): */
5740 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5741 }
5742 rb_io_fptr_cleanup(fptr, FALSE);
5743 return fptr;
5744}
5745
5746static void
5747fptr_waitpid(rb_io_t *fptr, int nohang)
5748{
5749 int status;
5750 if (fptr->pid) {
5751 rb_last_status_clear();
5752 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5753 fptr->pid = 0;
5754 }
5755}
5756
5757 VALUE
5758rb_io_close(VALUE io)
5759{
5760 rb_io_t *fptr = io_close_fptr(io);
5761 if (fptr) fptr_waitpid(fptr, 0);
5762 return Qnil;
5763}
5764
5765/*
5766 * call-seq:
5767 * close -> nil
5768 *
5769 * Closes the stream for both reading and writing
5770 * if open for either or both; returns +nil+.
5771 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5772 *
5773 * If the stream is open for writing, flushes any buffered writes
5774 * to the operating system before closing.
5775 *
5776 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5777 * (child exit status).
5778 *
5779 * It is not an error to close an IO object that has already been closed.
5780 * It just returns nil.
5781 *
5782 * Example:
5783 *
5784 * IO.popen('ruby', 'r+') do |pipe|
5785 * puts pipe.closed?
5786 * pipe.close
5787 * puts $?
5788 * puts pipe.closed?
5789 * end
5790 *
5791 * Output:
5792 *
5793 * false
5794 * pid 13760 exit 0
5795 * true
5796 *
5797 * Related: IO#close_read, IO#close_write, IO#closed?.
5798 */
5799
5800static VALUE
5801rb_io_close_m(VALUE io)
5802{
5803 rb_io_t *fptr = rb_io_get_fptr(io);
5804 if (fptr->fd < 0) {
5805 return Qnil;
5806 }
5807 rb_io_close(io);
5808 return Qnil;
5809}
5810
5811static VALUE
5812io_call_close(VALUE io)
5813{
5814 rb_check_funcall(io, rb_intern("close"), 0, 0);
5815 return io;
5816}
5817
5818static VALUE
5819ignore_closed_stream(VALUE io, VALUE exc)
5820{
5821 enum {mesg_len = sizeof(closed_stream)-1};
5822 VALUE mesg = rb_attr_get(exc, idMesg);
5823 if (!RB_TYPE_P(mesg, T_STRING) ||
5824 RSTRING_LEN(mesg) != mesg_len ||
5825 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5826 rb_exc_raise(exc);
5827 }
5828 return io;
5829}
5830
5831static VALUE
5832io_close(VALUE io)
5833{
5834 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5835 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5836 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5837 rb_eIOError, (VALUE)0);
5838 return io;
5839}
5840
5841/*
5842 * call-seq:
5843 * closed? -> true or false
5844 *
5845 * Returns +true+ if the stream is closed for both reading and writing,
5846 * +false+ otherwise.
5847 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5848 *
5849 * IO.popen('ruby', 'r+') do |pipe|
5850 * puts pipe.closed?
5851 * pipe.close_read
5852 * puts pipe.closed?
5853 * pipe.close_write
5854 * puts pipe.closed?
5855 * end
5856 *
5857 * Output:
5858 *
5859 * false
5860 * false
5861 * true
5862 *
5863 * Related: IO#close_read, IO#close_write, IO#close.
5864 */
5865 VALUE
5866rb_io_closed_p(VALUE io)
5867{
5868 rb_io_t *fptr;
5869 VALUE write_io;
5870 rb_io_t *write_fptr;
5871
5872 write_io = GetWriteIO(io);
5873 if (io != write_io) {
5874 write_fptr = RFILE(write_io)->fptr;
5875 if (write_fptr && 0 <= write_fptr->fd) {
5876 return Qfalse;
5877 }
5878 }
5879
5880 fptr = rb_io_get_fptr(io);
5881 return RBOOL(0 > fptr->fd);
5882}
5883
5884/*
5885 * call-seq:
5886 * close_read -> nil
5887 *
5888 * Closes the stream for reading if open for reading;
5889 * returns +nil+.
5890 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5891 *
5892 * If the stream was opened by IO.popen and is also closed for writing,
5893 * sets global variable <tt>$?</tt> (child exit status).
5894 *
5895 * Example:
5896 *
5897 * IO.popen('ruby', 'r+') do |pipe|
5898 * puts pipe.closed?
5899 * pipe.close_write
5900 * puts pipe.closed?
5901 * pipe.close_read
5902 * puts $?
5903 * puts pipe.closed?
5904 * end
5905 *
5906 * Output:
5907 *
5908 * false
5909 * false
5910 * pid 14748 exit 0
5911 * true
5912 *
5913 * Related: IO#close, IO#close_write, IO#closed?.
5914 */
5915
5916static VALUE
5917rb_io_close_read(VALUE io)
5918{
5919 rb_io_t *fptr;
5920 VALUE write_io;
5921
5922 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5923 if (fptr->fd < 0) return Qnil;
5924 if (is_socket(fptr->fd, fptr->pathv)) {
5925#ifndef SHUT_RD
5926# define SHUT_RD 0
5927#endif
5928 if (shutdown(fptr->fd, SHUT_RD) < 0)
5929 rb_sys_fail_path(fptr->pathv);
5930 fptr->mode &= ~FMODE_READABLE;
5931 if (!(fptr->mode & FMODE_WRITABLE))
5932 return rb_io_close(io);
5933 return Qnil;
5934 }
5935
5936 write_io = GetWriteIO(io);
5937 if (io != write_io) {
5938 rb_io_t *wfptr;
5939 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5940 wfptr->pid = fptr->pid;
5941 fptr->pid = 0;
5942 RFILE(io)->fptr = wfptr;
5943 /* bind to write_io temporarily to get rid of memory/fd leak */
5944 fptr->tied_io_for_writing = 0;
5945 RFILE(write_io)->fptr = fptr;
5946 rb_io_fptr_cleanup(fptr, FALSE);
5947 /* should not finalize fptr because another thread may be reading it */
5948 return Qnil;
5949 }
5950
5951 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5952 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5953 }
5954 return rb_io_close(io);
5955}
5956
5957/*
5958 * call-seq:
5959 * close_write -> nil
5960 *
5961 * Closes the stream for writing if open for writing;
5962 * returns +nil+.
5963 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5964 *
5965 * Flushes any buffered writes to the operating system before closing.
5966 *
5967 * If the stream was opened by IO.popen and is also closed for reading,
5968 * sets global variable <tt>$?</tt> (child exit status).
5969 *
5970 * IO.popen('ruby', 'r+') do |pipe|
5971 * puts pipe.closed?
5972 * pipe.close_read
5973 * puts pipe.closed?
5974 * pipe.close_write
5975 * puts $?
5976 * puts pipe.closed?
5977 * end
5978 *
5979 * Output:
5980 *
5981 * false
5982 * false
5983 * pid 15044 exit 0
5984 * true
5985 *
5986 * Related: IO#close, IO#close_read, IO#closed?.
5987 */
5988
5989static VALUE
5990rb_io_close_write(VALUE io)
5991{
5992 rb_io_t *fptr;
5993 VALUE write_io;
5994
5995 write_io = GetWriteIO(io);
5996 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5997 if (fptr->fd < 0) return Qnil;
5998 if (is_socket(fptr->fd, fptr->pathv)) {
5999#ifndef SHUT_WR
6000# define SHUT_WR 1
6001#endif
6002 if (shutdown(fptr->fd, SHUT_WR) < 0)
6003 rb_sys_fail_path(fptr->pathv);
6004 fptr->mode &= ~FMODE_WRITABLE;
6005 if (!(fptr->mode & FMODE_READABLE))
6006 return rb_io_close(write_io);
6007 return Qnil;
6008 }
6009
6010 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6011 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6012 }
6013
6014 if (io != write_io) {
6015 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6016 fptr->tied_io_for_writing = 0;
6017 }
6018 rb_io_close(write_io);
6019 return Qnil;
6020}
6021
6022/*
6023 * call-seq:
6024 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6025 *
6026 * Behaves like IO#seek, except that it:
6027 *
6028 * - Uses low-level system functions.
6029 * - Returns the new position.
6030 *
6031 */
6032
6033static VALUE
6034rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6035{
6036 VALUE offset, ptrname;
6037 int whence = SEEK_SET;
6038 rb_io_t *fptr;
6039 rb_off_t pos;
6040
6041 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6042 whence = interpret_seek_whence(ptrname);
6043 }
6044 pos = NUM2OFFT(offset);
6045 GetOpenFile(io, fptr);
6046 if ((fptr->mode & FMODE_READABLE) &&
6047 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6048 rb_raise(rb_eIOError, "sysseek for buffered IO");
6049 }
6050 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6051 rb_warn("sysseek for buffered IO");
6052 }
6053 errno = 0;
6054 pos = lseek(fptr->fd, pos, whence);
6055 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6056
6057 return OFFT2NUM(pos);
6058}
6059
6060/*
6061 * call-seq:
6062 * syswrite(object) -> integer
6063 *
6064 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6065 * returns the number bytes written.
6066 * If +object+ is not a string is converted via method to_s:
6067 *
6068 * f = File.new('t.tmp', 'w')
6069 * f.syswrite('foo') # => 3
6070 * f.syswrite(30) # => 2
6071 * f.syswrite(:foo) # => 3
6072 * f.close
6073 *
6074 * This methods should not be used with other stream-writer methods.
6075 *
6076 */
6077
6078static VALUE
6079rb_io_syswrite(VALUE io, VALUE str)
6080{
6081 VALUE tmp;
6082 rb_io_t *fptr;
6083 long n, len;
6084 const char *ptr;
6085
6086 if (!RB_TYPE_P(str, T_STRING))
6087 str = rb_obj_as_string(str);
6088
6089 io = GetWriteIO(io);
6090 GetOpenFile(io, fptr);
6091 rb_io_check_writable(fptr);
6092
6093 if (fptr->wbuf.len) {
6094 rb_warn("syswrite for buffered IO");
6095 }
6096
6097 tmp = rb_str_tmp_frozen_acquire(str);
6098 RSTRING_GETMEM(tmp, ptr, len);
6099 n = rb_io_write_memory(fptr, ptr, len);
6100 if (n < 0) rb_sys_fail_path(fptr->pathv);
6101 rb_str_tmp_frozen_release(str, tmp);
6102
6103 return LONG2FIX(n);
6104}
6105
6106/*
6107 * call-seq:
6108 * sysread(maxlen) -> string
6109 * sysread(maxlen, out_string) -> string
6110 *
6111 * Behaves like IO#readpartial, except that it uses low-level system functions.
6112 *
6113 * This method should not be used with other stream-reader methods.
6114 *
6115 */
6116
6117static VALUE
6118rb_io_sysread(int argc, VALUE *argv, VALUE io)
6119{
6120 VALUE len, str;
6121 rb_io_t *fptr;
6122 long n, ilen;
6123 struct io_internal_read_struct iis;
6124 int shrinkable;
6125
6126 rb_scan_args(argc, argv, "11", &len, &str);
6127 ilen = NUM2LONG(len);
6128
6129 shrinkable = io_setstrbuf(&str, ilen);
6130 if (ilen == 0) return str;
6131
6132 GetOpenFile(io, fptr);
6133 rb_io_check_byte_readable(fptr);
6134
6135 if (READ_DATA_BUFFERED(fptr)) {
6136 rb_raise(rb_eIOError, "sysread for buffered IO");
6137 }
6138
6139 rb_io_check_closed(fptr);
6140
6141 io_setstrbuf(&str, ilen);
6142 iis.th = rb_thread_current();
6143 iis.fptr = fptr;
6144 iis.nonblock = 0;
6145 iis.fd = fptr->fd;
6146 iis.buf = RSTRING_PTR(str);
6147 iis.capa = ilen;
6148 iis.timeout = NULL;
6149 n = io_read_memory_locktmp(str, &iis);
6150
6151 if (n < 0) {
6152 rb_sys_fail_path(fptr->pathv);
6153 }
6154
6155 io_set_read_length(str, n, shrinkable);
6156
6157 if (n == 0 && ilen > 0) {
6158 rb_eof_error();
6159 }
6160
6161 return str;
6162}
6163
6164 struct prdwr_internal_arg {
6165 struct rb_io *io;
6166 int fd;
6167 void *buf;
6168 size_t count;
6169 rb_off_t offset;
6170};
6171
6172static VALUE
6173internal_pread_func(void *_arg)
6174{
6175 struct prdwr_internal_arg *arg = _arg;
6176
6177 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6178}
6179
6180static VALUE
6181pread_internal_call(VALUE _arg)
6182{
6183 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6184
6185 VALUE scheduler = rb_fiber_scheduler_current();
6186 if (scheduler != Qnil) {
6187 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6188
6189 if (!UNDEF_P(result)) {
6190 return rb_fiber_scheduler_io_result_apply(result);
6191 }
6192 }
6193
6194 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6195}
6196
6197/*
6198 * call-seq:
6199 * pread(maxlen, offset) -> string
6200 * pread(maxlen, offset, out_string) -> string
6201 *
6202 * Behaves like IO#readpartial, except that it:
6203 *
6204 * - Reads at the given +offset+ (in bytes).
6205 * - Disregards, and does not modify, the stream's position
6206 * (see {Position}[rdoc-ref:IO@Position]).
6207 * - Bypasses any user space buffering in the stream.
6208 *
6209 * Because this method does not disturb the stream's state
6210 * (its position, in particular), +pread+ allows multiple threads and processes
6211 * to use the same \IO object for reading at various offsets.
6212 *
6213 * f = File.open('t.txt')
6214 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6215 * f.pos # => 52
6216 * # Read 12 bytes at offset 0.
6217 * f.pread(12, 0) # => "First line\n"
6218 * # Read 9 bytes at offset 8.
6219 * f.pread(9, 8) # => "ne\nSecon"
6220 * f.close
6221 *
6222 * Not available on some platforms.
6223 *
6224 */
6225static VALUE
6226rb_io_pread(int argc, VALUE *argv, VALUE io)
6227{
6228 VALUE len, offset, str;
6229 rb_io_t *fptr;
6230 ssize_t n;
6231 struct prdwr_internal_arg arg;
6232 int shrinkable;
6233
6234 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6235 arg.count = NUM2SIZET(len);
6236 arg.offset = NUM2OFFT(offset);
6237
6238 shrinkable = io_setstrbuf(&str, (long)arg.count);
6239 if (arg.count == 0) return str;
6240 arg.buf = RSTRING_PTR(str);
6241
6242 GetOpenFile(io, fptr);
6243 rb_io_check_byte_readable(fptr);
6244
6245 arg.io = fptr;
6246 arg.fd = fptr->fd;
6247 rb_io_check_closed(fptr);
6248
6249 rb_str_locktmp(str);
6250 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6251
6252 if (n < 0) {
6253 rb_sys_fail_path(fptr->pathv);
6254 }
6255 io_set_read_length(str, n, shrinkable);
6256 if (n == 0 && arg.count > 0) {
6257 rb_eof_error();
6258 }
6259
6260 return str;
6261}
6262
6263static VALUE
6264internal_pwrite_func(void *_arg)
6265{
6266 struct prdwr_internal_arg *arg = _arg;
6267
6268 VALUE scheduler = rb_fiber_scheduler_current();
6269 if (scheduler != Qnil) {
6270 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6271
6272 if (!UNDEF_P(result)) {
6273 return rb_fiber_scheduler_io_result_apply(result);
6274 }
6275 }
6276
6277
6278 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6279}
6280
6281/*
6282 * call-seq:
6283 * pwrite(object, offset) -> integer
6284 *
6285 * Behaves like IO#write, except that it:
6286 *
6287 * - Writes at the given +offset+ (in bytes).
6288 * - Disregards, and does not modify, the stream's position
6289 * (see {Position}[rdoc-ref:IO@Position]).
6290 * - Bypasses any user space buffering in the stream.
6291 *
6292 * Because this method does not disturb the stream's state
6293 * (its position, in particular), +pwrite+ allows multiple threads and processes
6294 * to use the same \IO object for writing at various offsets.
6295 *
6296 * f = File.open('t.tmp', 'w+')
6297 * # Write 6 bytes at offset 3.
6298 * f.pwrite('ABCDEF', 3) # => 6
6299 * f.rewind
6300 * f.read # => "\u0000\u0000\u0000ABCDEF"
6301 * f.close
6302 *
6303 * Not available on some platforms.
6304 *
6305 */
6306static VALUE
6307rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6308{
6309 rb_io_t *fptr;
6310 ssize_t n;
6311 struct prdwr_internal_arg arg;
6312 VALUE tmp;
6313
6314 if (!RB_TYPE_P(str, T_STRING))
6315 str = rb_obj_as_string(str);
6316
6317 arg.offset = NUM2OFFT(offset);
6318
6319 io = GetWriteIO(io);
6320 GetOpenFile(io, fptr);
6321 rb_io_check_writable(fptr);
6322
6323 arg.io = fptr;
6324 arg.fd = fptr->fd;
6325
6326 tmp = rb_str_tmp_frozen_acquire(str);
6327 arg.buf = RSTRING_PTR(tmp);
6328 arg.count = (size_t)RSTRING_LEN(tmp);
6329
6330 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
6331 if (n < 0) rb_sys_fail_path(fptr->pathv);
6332 rb_str_tmp_frozen_release(str, tmp);
6333
6334 return SSIZET2NUM(n);
6335}
6336
6337 VALUE
6338rb_io_binmode(VALUE io)
6339{
6340 rb_io_t *fptr;
6341
6342 GetOpenFile(io, fptr);
6343 if (fptr->readconv)
6344 rb_econv_binmode(fptr->readconv);
6345 if (fptr->writeconv)
6346 rb_econv_binmode(fptr->writeconv);
6347 fptr->mode |= FMODE_BINMODE;
6348 fptr->mode &= ~FMODE_TEXTMODE;
6349 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6350#ifdef O_BINARY
6351 if (!fptr->readconv) {
6352 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6353 }
6354 else {
6355 setmode(fptr->fd, O_BINARY);
6356 }
6357#endif
6358 return io;
6359}
6360
6361static void
6362io_ascii8bit_binmode(rb_io_t *fptr)
6363{
6364 if (fptr->readconv) {
6365 rb_econv_close(fptr->readconv);
6366 fptr->readconv = NULL;
6367 }
6368 if (fptr->writeconv) {
6369 rb_econv_close(fptr->writeconv);
6370 fptr->writeconv = NULL;
6371 }
6372 fptr->mode |= FMODE_BINMODE;
6373 fptr->mode &= ~FMODE_TEXTMODE;
6374 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6375
6376 fptr->encs.enc = rb_ascii8bit_encoding();
6377 fptr->encs.enc2 = NULL;
6378 fptr->encs.ecflags = 0;
6379 fptr->encs.ecopts = Qnil;
6380 clear_codeconv(fptr);
6381}
6382
6383 VALUE
6384rb_io_ascii8bit_binmode(VALUE io)
6385{
6386 rb_io_t *fptr;
6387
6388 GetOpenFile(io, fptr);
6389 io_ascii8bit_binmode(fptr);
6390
6391 return io;
6392}
6393
6394/*
6395 * call-seq:
6396 * binmode -> self
6397 *
6398 * Sets the stream's data mode as binary
6399 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6400 *
6401 * A stream's data mode may not be changed from binary to text.
6402 *
6403 */
6404
6405static VALUE
6406rb_io_binmode_m(VALUE io)
6407{
6408 VALUE write_io;
6409
6410 rb_io_ascii8bit_binmode(io);
6411
6412 write_io = GetWriteIO(io);
6413 if (write_io != io)
6414 rb_io_ascii8bit_binmode(write_io);
6415 return io;
6416}
6417
6418/*
6419 * call-seq:
6420 * binmode? -> true or false
6421 *
6422 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6423 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6424 *
6425 */
6426static VALUE
6427rb_io_binmode_p(VALUE io)
6428{
6429 rb_io_t *fptr;
6430 GetOpenFile(io, fptr);
6431 return RBOOL(fptr->mode & FMODE_BINMODE);
6432}
6433
6434static const char*
6435rb_io_fmode_modestr(int fmode)
6436{
6437 if (fmode & FMODE_APPEND) {
6438 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6439 return MODE_BTMODE("a+", "ab+", "at+");
6440 }
6441 return MODE_BTMODE("a", "ab", "at");
6442 }
6443 switch (fmode & FMODE_READWRITE) {
6444 default:
6445 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6446 case FMODE_READABLE:
6447 return MODE_BTMODE("r", "rb", "rt");
6448 case FMODE_WRITABLE:
6449 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6450 case FMODE_READWRITE:
6451 if (fmode & FMODE_CREATE) {
6452 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6453 }
6454 return MODE_BTMODE("r+", "rb+", "rt+");
6455 }
6456}
6457
6458static const char bom_prefix[] = "bom|";
6459static const char utf_prefix[] = "utf-";
6460enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6461enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6462
6463static int
6464io_encname_bom_p(const char *name, long len)
6465{
6466 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6467}
6468
6469int
6470rb_io_modestr_fmode(const char *modestr)
6471{
6472 int fmode = 0;
6473 const char *m = modestr, *p = NULL;
6474
6475 switch (*m++) {
6476 case 'r':
6477 fmode |= FMODE_READABLE;
6478 break;
6479 case 'w':
6480 fmode |= FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE;
6481 break;
6482 case 'a':
6483 fmode |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
6484 break;
6485 default:
6486 goto error;
6487 }
6488
6489 while (*m) {
6490 switch (*m++) {
6491 case 'b':
6492 fmode |= FMODE_BINMODE;
6493 break;
6494 case 't':
6495 fmode |= FMODE_TEXTMODE;
6496 break;
6497 case '+':
6498 fmode |= FMODE_READWRITE;
6499 break;
6500 case 'x':
6501 if (modestr[0] != 'w')
6502 goto error;
6503 fmode |= FMODE_EXCL;
6504 break;
6505 default:
6506 goto error;
6507 case ':':
6508 p = strchr(m, ':');
6509 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6510 fmode |= FMODE_SETENC_BY_BOM;
6511 goto finished;
6512 }
6513 }
6514
6515 finished:
6516 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6517 goto error;
6518
6519 return fmode;
6520
6521 error:
6522 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6523 UNREACHABLE_RETURN(Qundef);
6524}
6525
6526int
6527rb_io_oflags_fmode(int oflags)
6528{
6529 int fmode = 0;
6530
6531 switch (oflags & O_ACCMODE) {
6532 case O_RDONLY:
6533 fmode = FMODE_READABLE;
6534 break;
6535 case O_WRONLY:
6536 fmode = FMODE_WRITABLE;
6537 break;
6538 case O_RDWR:
6539 fmode = FMODE_READWRITE;
6540 break;
6541 }
6542
6543 if (oflags & O_APPEND) {
6544 fmode |= FMODE_APPEND;
6545 }
6546 if (oflags & O_TRUNC) {
6547 fmode |= FMODE_TRUNC;
6548 }
6549 if (oflags & O_CREAT) {
6550 fmode |= FMODE_CREATE;
6551 }
6552 if (oflags & O_EXCL) {
6553 fmode |= FMODE_EXCL;
6554 }
6555#ifdef O_BINARY
6556 if (oflags & O_BINARY) {
6557 fmode |= FMODE_BINMODE;
6558 }
6559#endif
6560
6561 return fmode;
6562}
6563
6564static int
6565rb_io_fmode_oflags(int fmode)
6566{
6567 int oflags = 0;
6568
6569 switch (fmode & FMODE_READWRITE) {
6570 case FMODE_READABLE:
6571 oflags |= O_RDONLY;
6572 break;
6573 case FMODE_WRITABLE:
6574 oflags |= O_WRONLY;
6575 break;
6576 case FMODE_READWRITE:
6577 oflags |= O_RDWR;
6578 break;
6579 }
6580
6581 if (fmode & FMODE_APPEND) {
6582 oflags |= O_APPEND;
6583 }
6584 if (fmode & FMODE_TRUNC) {
6585 oflags |= O_TRUNC;
6586 }
6587 if (fmode & FMODE_CREATE) {
6588 oflags |= O_CREAT;
6589 }
6590 if (fmode & FMODE_EXCL) {
6591 oflags |= O_EXCL;
6592 }
6593#ifdef O_BINARY
6594 if (fmode & FMODE_BINMODE) {
6595 oflags |= O_BINARY;
6596 }
6597#endif
6598
6599 return oflags;
6600}
6601
6602int
6603rb_io_modestr_oflags(const char *modestr)
6604{
6605 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6606}
6607
6608static const char*
6609rb_io_oflags_modestr(int oflags)
6610{
6611#ifdef O_BINARY
6612# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6613#else
6614# define MODE_BINARY(a,b) (a)
6615#endif
6616 int accmode;
6617 if (oflags & O_EXCL) {
6618 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6619 }
6620 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6621 if (oflags & O_APPEND) {
6622 if (accmode == O_WRONLY) {
6623 return MODE_BINARY("a", "ab");
6624 }
6625 if (accmode == O_RDWR) {
6626 return MODE_BINARY("a+", "ab+");
6627 }
6628 }
6629 switch (accmode) {
6630 default:
6631 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6632 case O_RDONLY:
6633 return MODE_BINARY("r", "rb");
6634 case O_WRONLY:
6635 return MODE_BINARY("w", "wb");
6636 case O_RDWR:
6637 if (oflags & O_TRUNC) {
6638 return MODE_BINARY("w+", "wb+");
6639 }
6640 return MODE_BINARY("r+", "rb+");
6641 }
6642}
6643
6644/*
6645 * Convert external/internal encodings to enc/enc2
6646 * NULL => use default encoding
6647 * Qnil => no encoding specified (internal only)
6648 */
6649static void
6650rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6651{
6652 int default_ext = 0;
6653
6654 if (ext == NULL) {
6655 ext = rb_default_external_encoding();
6656 default_ext = 1;
6657 }
6658 if (rb_is_ascii8bit_enc(ext)) {
6659 /* If external is ASCII-8BIT, no transcoding */
6660 intern = NULL;
6661 }
6662 else if (intern == NULL) {
6663 intern = rb_default_internal_encoding();
6664 }
6665 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6666 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6667 /* No internal encoding => use external + no transcoding */
6668 *enc = (default_ext && intern != ext) ? NULL : ext;
6669 *enc2 = NULL;
6670 }
6671 else {
6672 *enc = intern;
6673 *enc2 = ext;
6674 }
6675}
6676
6677static void
6678unsupported_encoding(const char *name, rb_encoding *enc)
6679{
6680 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6681}
6682
6683static void
6684parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6685 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6686{
6687 const char *p;
6688 char encname[ENCODING_MAXNAMELEN+1];
6689 int idx, idx2;
6690 int fmode = fmode_p ? *fmode_p : 0;
6691 rb_encoding *ext_enc, *int_enc;
6692 long len;
6693
6694 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6695
6696 p = strrchr(estr, ':');
6697 len = p ? (p++ - estr) : (long)strlen(estr);
6698 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6699 estr += bom_prefix_len;
6700 len -= bom_prefix_len;
6701 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6702 fmode |= FMODE_SETENC_BY_BOM;
6703 }
6704 else {
6705 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6706 fmode &= ~FMODE_SETENC_BY_BOM;
6707 }
6708 }
6709 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6710 idx = -1;
6711 }
6712 else {
6713 if (p) {
6714 memcpy(encname, estr, len);
6715 encname[len] = '\0';
6716 estr = encname;
6717 }
6718 idx = rb_enc_find_index(estr);
6719 }
6720 if (fmode_p) *fmode_p = fmode;
6721
6722 if (idx >= 0)
6723 ext_enc = rb_enc_from_index(idx);
6724 else {
6725 if (idx != -2)
6726 unsupported_encoding(estr, estr_enc);
6727 ext_enc = NULL;
6728 }
6729
6730 int_enc = NULL;
6731 if (p) {
6732 if (*p == '-' && *(p+1) == '\0') {
6733 /* Special case - "-" => no transcoding */
6734 int_enc = (rb_encoding *)Qnil;
6735 }
6736 else {
6737 idx2 = rb_enc_find_index(p);
6738 if (idx2 < 0)
6739 unsupported_encoding(p, estr_enc);
6740 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6741 int_enc = (rb_encoding *)Qnil;
6742 }
6743 else
6744 int_enc = rb_enc_from_index(idx2);
6745 }
6746 }
6747
6748 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6749}
6750
6751int
6752rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6753{
6754 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6755 int extracted = 0;
6756 rb_encoding *extencoding = NULL;
6757 rb_encoding *intencoding = NULL;
6758
6759 if (!NIL_P(opt)) {
6760 VALUE v;
6761 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6762 if (v != Qnil) encoding = v;
6763 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6764 if (v != Qnil) extenc = v;
6765 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6766 if (!UNDEF_P(v)) intenc = v;
6767 }
6768 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6769 if (!NIL_P(ruby_verbose)) {
6770 int idx = rb_to_encoding_index(encoding);
6771 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6772 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6773 encoding, UNDEF_P(extenc) ? "internal" : "external");
6774 }
6775 encoding = Qnil;
6776 }
6777 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6778 extencoding = rb_to_encoding(extenc);
6779 }
6780 if (!UNDEF_P(intenc)) {
6781 if (NIL_P(intenc)) {
6782 /* internal_encoding: nil => no transcoding */
6783 intencoding = (rb_encoding *)Qnil;
6784 }
6785 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6786 char *p = StringValueCStr(tmp);
6787
6788 if (*p == '-' && *(p+1) == '\0') {
6789 /* Special case - "-" => no transcoding */
6790 intencoding = (rb_encoding *)Qnil;
6791 }
6792 else {
6793 intencoding = rb_to_encoding(intenc);
6794 }
6795 }
6796 else {
6797 intencoding = rb_to_encoding(intenc);
6798 }
6799 if (extencoding == intencoding) {
6800 intencoding = (rb_encoding *)Qnil;
6801 }
6802 }
6803 if (!NIL_P(encoding)) {
6804 extracted = 1;
6805 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6806 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6807 enc_p, enc2_p, fmode_p);
6808 }
6809 else {
6810 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6811 }
6812 }
6813 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6814 extracted = 1;
6815 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6816 }
6817 return extracted;
6818}
6819
6820static void
6821validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6822{
6823 int fmode = *fmode_p;
6824
6825 if ((fmode & FMODE_READABLE) &&
6826 !enc2 &&
6827 !(fmode & FMODE_BINMODE) &&
6828 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6829 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6830
6831 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6832 rb_raise(rb_eArgError, "newline decorator with binary mode");
6833 }
6834 if (!(fmode & FMODE_BINMODE) &&
6835 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6836 fmode |= FMODE_TEXTMODE;
6837 *fmode_p = fmode;
6838 }
6839#if !DEFAULT_TEXTMODE
6840 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6841 fmode &= ~FMODE_TEXTMODE;
6842 *fmode_p = fmode;
6843 }
6844#endif
6845}
6846
6847static void
6848extract_binmode(VALUE opthash, int *fmode)
6849{
6850 if (!NIL_P(opthash)) {
6851 VALUE v;
6852 v = rb_hash_aref(opthash, sym_textmode);
6853 if (!NIL_P(v)) {
6854 if (*fmode & FMODE_TEXTMODE)
6855 rb_raise(rb_eArgError, "textmode specified twice");
6856 if (*fmode & FMODE_BINMODE)
6857 rb_raise(rb_eArgError, "both textmode and binmode specified");
6858 if (RTEST(v))
6859 *fmode |= FMODE_TEXTMODE;
6860 }
6861 v = rb_hash_aref(opthash, sym_binmode);
6862 if (!NIL_P(v)) {
6863 if (*fmode & FMODE_BINMODE)
6864 rb_raise(rb_eArgError, "binmode specified twice");
6865 if (*fmode & FMODE_TEXTMODE)
6866 rb_raise(rb_eArgError, "both textmode and binmode specified");
6867 if (RTEST(v))
6868 *fmode |= FMODE_BINMODE;
6869 }
6870
6871 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6872 rb_raise(rb_eArgError, "both textmode and binmode specified");
6873 }
6874}
6875
6876void
6877rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6878 int *oflags_p, int *fmode_p, struct rb_io_encoding *convconfig_p)
6879{
6880 VALUE vmode;
6881 int oflags, fmode;
6882 rb_encoding *enc, *enc2;
6883 int ecflags;
6884 VALUE ecopts;
6885 int has_enc = 0, has_vmode = 0;
6886 VALUE intmode;
6887
6888 vmode = *vmode_p;
6889
6890 /* Set to defaults */
6891 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6892
6893 vmode_handle:
6894 if (NIL_P(vmode)) {
6895 fmode = FMODE_READABLE;
6896 oflags = O_RDONLY;
6897 }
6898 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6899 vmode = intmode;
6900 oflags = NUM2INT(intmode);
6901 fmode = rb_io_oflags_fmode(oflags);
6902 }
6903 else {
6904 const char *p;
6905
6906 StringValue(vmode);
6907 p = StringValueCStr(vmode);
6908 fmode = rb_io_modestr_fmode(p);
6909 oflags = rb_io_fmode_oflags(fmode);
6910 p = strchr(p, ':');
6911 if (p) {
6912 has_enc = 1;
6913 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6914 }
6915 else {
6916 rb_encoding *e;
6917
6918 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6919 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6920 }
6921 }
6922
6923 if (NIL_P(opthash)) {
6924 ecflags = (fmode & FMODE_READABLE) ?
6925 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6926 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6927#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6928 ecflags |= (fmode & FMODE_WRITABLE) ?
6929 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6930 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6931#endif
6932 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6933 ecopts = Qnil;
6934 if (fmode & FMODE_BINMODE) {
6935#ifdef O_BINARY
6936 oflags |= O_BINARY;
6937#endif
6938 if (!has_enc)
6939 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6940 }
6941#if DEFAULT_TEXTMODE
6942 else if (NIL_P(vmode)) {
6943 fmode |= DEFAULT_TEXTMODE;
6944 }
6945#endif
6946 }
6947 else {
6948 VALUE v;
6949 if (!has_vmode) {
6950 v = rb_hash_aref(opthash, sym_mode);
6951 if (!NIL_P(v)) {
6952 if (!NIL_P(vmode)) {
6953 rb_raise(rb_eArgError, "mode specified twice");
6954 }
6955 has_vmode = 1;
6956 vmode = v;
6957 goto vmode_handle;
6958 }
6959 }
6960 v = rb_hash_aref(opthash, sym_flags);
6961 if (!NIL_P(v)) {
6962 v = rb_to_int(v);
6963 oflags |= NUM2INT(v);
6964 vmode = INT2NUM(oflags);
6965 fmode = rb_io_oflags_fmode(oflags);
6966 }
6967 extract_binmode(opthash, &fmode);
6968 if (fmode & FMODE_BINMODE) {
6969#ifdef O_BINARY
6970 oflags |= O_BINARY;
6971#endif
6972 if (!has_enc)
6973 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6974 }
6975#if DEFAULT_TEXTMODE
6976 else if (NIL_P(vmode)) {
6977 fmode |= DEFAULT_TEXTMODE;
6978 }
6979#endif
6980 v = rb_hash_aref(opthash, sym_perm);
6981 if (!NIL_P(v)) {
6982 if (vperm_p) {
6983 if (!NIL_P(*vperm_p)) {
6984 rb_raise(rb_eArgError, "perm specified twice");
6985 }
6986 *vperm_p = v;
6987 }
6988 else {
6989 /* perm no use, just ignore */
6990 }
6991 }
6992 ecflags = (fmode & FMODE_READABLE) ?
6993 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6994 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6995#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6996 ecflags |= (fmode & FMODE_WRITABLE) ?
6997 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6998 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6999#endif
7000
7001 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7002 if (has_enc) {
7003 rb_raise(rb_eArgError, "encoding specified twice");
7004 }
7005 }
7006 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7007 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7008 }
7009
7010 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7011
7012 *vmode_p = vmode;
7013
7014 *oflags_p = oflags;
7015 *fmode_p = fmode;
7016 convconfig_p->enc = enc;
7017 convconfig_p->enc2 = enc2;
7018 convconfig_p->ecflags = ecflags;
7019 convconfig_p->ecopts = ecopts;
7020}
7021
7022 struct sysopen_struct {
7023 VALUE fname;
7024 int oflags;
7025 mode_t perm;
7026};
7027
7028static void *
7029sysopen_func(void *ptr)
7030{
7031 const struct sysopen_struct *data = ptr;
7032 const char *fname = RSTRING_PTR(data->fname);
7033 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7034}
7035
7036static inline int
7037rb_sysopen_internal(struct sysopen_struct *data)
7038{
7039 int fd;
7040 do {
7041 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7042 } while (fd < 0 && errno == EINTR);
7043 if (0 <= fd)
7044 rb_update_max_fd(fd);
7045 return fd;
7046}
7047
7048static int
7049rb_sysopen(VALUE fname, int oflags, mode_t perm)
7050{
7051 int fd = -1;
7052 struct sysopen_struct data;
7053
7054 data.fname = rb_str_encode_ospath(fname);
7055 StringValueCStr(data.fname);
7056 data.oflags = oflags;
7057 data.perm = perm;
7058
7059 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7060 rb_syserr_fail_path(first_errno, fname);
7061 }
7062 return fd;
7063}
7064
7065static inline FILE *
7066fdopen_internal(int fd, const char *modestr)
7067{
7068 FILE *file;
7069
7070#if defined(__sun)
7071 errno = 0;
7072#endif
7073 file = fdopen(fd, modestr);
7074 if (!file) {
7075#ifdef _WIN32
7076 if (errno == 0) errno = EINVAL;
7077#elif defined(__sun)
7078 if (errno == 0) errno = EMFILE;
7079#endif
7080 }
7081 return file;
7082}
7083
7084FILE *
7085rb_fdopen(int fd, const char *modestr)
7086{
7087 FILE *file = 0;
7088
7089 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7090 rb_syserr_fail(first_errno, 0);
7091 }
7092
7093 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7094#ifdef USE_SETVBUF
7095 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7096 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7097#endif
7098 return file;
7099}
7100
7101static int
7102io_check_tty(rb_io_t *fptr)
7103{
7104 int t = isatty(fptr->fd);
7105 if (t)
7106 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7107 return t;
7108}
7109
7110static VALUE rb_io_internal_encoding(VALUE);
7111static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7112
7113static int
7114io_strip_bom(VALUE io)
7115{
7116 VALUE b1, b2, b3, b4;
7117 rb_io_t *fptr;
7118
7119 GetOpenFile(io, fptr);
7120 if (!(fptr->mode & FMODE_READABLE)) return 0;
7121 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7122 switch (b1) {
7123 case INT2FIX(0xEF):
7124 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7125 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7126 if (b3 == INT2FIX(0xBF)) {
7127 return rb_utf8_encindex();
7128 }
7129 rb_io_ungetbyte(io, b3);
7130 }
7131 rb_io_ungetbyte(io, b2);
7132 break;
7133
7134 case INT2FIX(0xFE):
7135 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7136 if (b2 == INT2FIX(0xFF)) {
7137 return ENCINDEX_UTF_16BE;
7138 }
7139 rb_io_ungetbyte(io, b2);
7140 break;
7141
7142 case INT2FIX(0xFF):
7143 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7144 if (b2 == INT2FIX(0xFE)) {
7145 b3 = rb_io_getbyte(io);
7146 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7147 if (b4 == INT2FIX(0)) {
7148 return ENCINDEX_UTF_32LE;
7149 }
7150 rb_io_ungetbyte(io, b4);
7151 }
7152 rb_io_ungetbyte(io, b3);
7153 return ENCINDEX_UTF_16LE;
7154 }
7155 rb_io_ungetbyte(io, b2);
7156 break;
7157
7158 case INT2FIX(0):
7159 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7160 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7161 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7162 if (b4 == INT2FIX(0xFF)) {
7163 return ENCINDEX_UTF_32BE;
7164 }
7165 rb_io_ungetbyte(io, b4);
7166 }
7167 rb_io_ungetbyte(io, b3);
7168 }
7169 rb_io_ungetbyte(io, b2);
7170 break;
7171 }
7172 rb_io_ungetbyte(io, b1);
7173 return 0;
7174}
7175
7176static rb_encoding *
7177io_set_encoding_by_bom(VALUE io)
7178{
7179 int idx = io_strip_bom(io);
7180 rb_io_t *fptr;
7181 rb_encoding *extenc = NULL;
7182
7183 GetOpenFile(io, fptr);
7184 if (idx) {
7185 extenc = rb_enc_from_index(idx);
7186 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7187 rb_io_internal_encoding(io), Qnil);
7188 }
7189 else {
7190 fptr->encs.enc2 = NULL;
7191 }
7192 return extenc;
7193}
7194
7195static VALUE
7196rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7197 const struct rb_io_encoding *convconfig, mode_t perm)
7198{
7199 VALUE pathv;
7200 rb_io_t *fptr;
7201 struct rb_io_encoding cc;
7202 if (!convconfig) {
7203 /* Set to default encodings */
7204 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7205 cc.ecflags = 0;
7206 cc.ecopts = Qnil;
7207 convconfig = &cc;
7208 }
7209 validate_enc_binmode(&fmode, convconfig->ecflags,
7210 convconfig->enc, convconfig->enc2);
7211
7212 MakeOpenFile(io, fptr);
7213 fptr->mode = fmode;
7214 fptr->encs = *convconfig;
7215 pathv = rb_str_new_frozen(filename);
7216#ifdef O_TMPFILE
7217 if (!(oflags & O_TMPFILE)) {
7218 fptr->pathv = pathv;
7219 }
7220#else
7221 fptr->pathv = pathv;
7222#endif
7223 fptr->fd = rb_sysopen(pathv, oflags, perm);
7224 io_check_tty(fptr);
7225 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7226
7227 return io;
7228}
7229
7230static VALUE
7231rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7232{
7233 int fmode = rb_io_modestr_fmode(modestr);
7234 const char *p = strchr(modestr, ':');
7235 struct rb_io_encoding convconfig;
7236
7237 if (p) {
7238 parse_mode_enc(p+1, rb_usascii_encoding(),
7239 &convconfig.enc, &convconfig.enc2, &fmode);
7240 }
7241 else {
7242 rb_encoding *e;
7243 /* Set to default encodings */
7244
7245 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7246 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7247 }
7248
7249 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7250 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
7251 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
7252#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7253 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7254 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7255 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7256#endif
7257 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7258 convconfig.ecopts = Qnil;
7259
7260 return rb_file_open_generic(io, filename,
7261 rb_io_fmode_oflags(fmode),
7262 fmode,
7263 &convconfig,
7264 0666);
7265}
7266
7267 VALUE
7268rb_file_open_str(VALUE fname, const char *modestr)
7269{
7270 FilePathValue(fname);
7271 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7272}
7273
7274 VALUE
7275rb_file_open(const char *fname, const char *modestr)
7276{
7277 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7278}
7279
7280#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7281 static struct pipe_list {
7282 rb_io_t *fptr;
7283 struct pipe_list *next;
7284} *pipe_list;
7285
7286static void
7287pipe_add_fptr(rb_io_t *fptr)
7288{
7289 struct pipe_list *list;
7290
7291 list = ALLOC(struct pipe_list);
7292 list->fptr = fptr;
7293 list->next = pipe_list;
7294 pipe_list = list;
7295}
7296
7297static void
7298pipe_del_fptr(rb_io_t *fptr)
7299{
7300 struct pipe_list **prev = &pipe_list;
7301 struct pipe_list *tmp;
7302
7303 while ((tmp = *prev) != 0) {
7304 if (tmp->fptr == fptr) {
7305 *prev = tmp->next;
7306 free(tmp);
7307 return;
7308 }
7309 prev = &tmp->next;
7310 }
7311}
7312
7313#if defined (_WIN32) || defined(__CYGWIN__)
7314static void
7315pipe_atexit(void)
7316{
7317 struct pipe_list *list = pipe_list;
7318 struct pipe_list *tmp;
7319
7320 while (list) {
7321 tmp = list->next;
7322 rb_io_fptr_finalize(list->fptr);
7323 list = tmp;
7324 }
7325}
7326#endif
7327
7328static void
7329pipe_finalize(rb_io_t *fptr, int noraise)
7330{
7331#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7332 int status = 0;
7333 if (fptr->stdio_file) {
7334 status = pclose(fptr->stdio_file);
7335 }
7336 fptr->fd = -1;
7337 fptr->stdio_file = 0;
7338 rb_last_status_set(status, fptr->pid);
7339#else
7340 fptr_finalize(fptr, noraise);
7341#endif
7342 pipe_del_fptr(fptr);
7343}
7344#endif
7345
7346static void
7347fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7348{
7349#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7350 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7351
7352 if (old_finalize == orig->finalize) return;
7353#endif
7354
7355 fptr->finalize = orig->finalize;
7356
7357#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7358 if (old_finalize != pipe_finalize) {
7359 struct pipe_list *list;
7360 for (list = pipe_list; list; list = list->next) {
7361 if (list->fptr == fptr) break;
7362 }
7363 if (!list) pipe_add_fptr(fptr);
7364 }
7365 else {
7366 pipe_del_fptr(fptr);
7367 }
7368#endif
7369}
7370
7371void
7372rb_io_synchronized(rb_io_t *fptr)
7373{
7374 rb_io_check_initialized(fptr);
7375 fptr->mode |= FMODE_SYNC;
7376}
7377
7378void
7379rb_io_unbuffered(rb_io_t *fptr)
7380{
7381 rb_io_synchronized(fptr);
7382}
7383
7384int
7385rb_pipe(int *pipes)
7386{
7387 int ret;
7388 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7389 if (ret == 0) {
7390 rb_update_max_fd(pipes[0]);
7391 rb_update_max_fd(pipes[1]);
7392 }
7393 return ret;
7394}
7395
7396#ifdef _WIN32
7397#define HAVE_SPAWNV 1
7398#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7399#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7400#endif
7401
7402#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7403struct popen_arg {
7404 VALUE execarg_obj;
7405 struct rb_execarg *eargp;
7406 int modef;
7407 int pair[2];
7408 int write_pair[2];
7409};
7410#endif
7411
7412#ifdef HAVE_WORKING_FORK
7413# ifndef __EMSCRIPTEN__
7414static void
7415popen_redirect(struct popen_arg *p)
7416{
7417 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7418 close(p->write_pair[1]);
7419 if (p->write_pair[0] != 0) {
7420 dup2(p->write_pair[0], 0);
7421 close(p->write_pair[0]);
7422 }
7423 close(p->pair[0]);
7424 if (p->pair[1] != 1) {
7425 dup2(p->pair[1], 1);
7426 close(p->pair[1]);
7427 }
7428 }
7429 else if (p->modef & FMODE_READABLE) {
7430 close(p->pair[0]);
7431 if (p->pair[1] != 1) {
7432 dup2(p->pair[1], 1);
7433 close(p->pair[1]);
7434 }
7435 }
7436 else {
7437 close(p->pair[1]);
7438 if (p->pair[0] != 0) {
7439 dup2(p->pair[0], 0);
7440 close(p->pair[0]);
7441 }
7442 }
7443}
7444# endif
7445
7446#if defined(__linux__)
7447/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7448 * Since /proc may not be available, linux_get_maxfd is just a hint.
7449 * This function, linux_get_maxfd, must be async-signal-safe.
7450 * I.e. opendir() is not usable.
7451 *
7452 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7453 * However they are easy to re-implement in async-signal-safe manner.
7454 * (Also note that there is missing/memcmp.c.)
7455 */
7456static int
7457linux_get_maxfd(void)
7458{
7459 int fd;
7460 char buf[4096], *p, *np, *e;
7461 ssize_t ss;
7462 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7463 if (fd < 0) return fd;
7464 ss = read(fd, buf, sizeof(buf));
7465 if (ss < 0) goto err;
7466 p = buf;
7467 e = buf + ss;
7468 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7469 (np = memchr(p, '\n', e-p)) != NULL) {
7470 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7471 int fdsize;
7472 p += sizeof("FDSize:")-1;
7473 *np = '\0';
7474 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7475 close(fd);
7476 return fdsize;
7477 }
7478 p = np+1;
7479 }
7480 /* fall through */
7481
7482 err:
7483 close(fd);
7484 return (int)ss;
7485}
7486#endif
7487
7488/* This function should be async-signal-safe. */
7489void
7490 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7491{
7492#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7493 int fd, ret;
7494 int max = (int)max_file_descriptor;
7495# ifdef F_MAXFD
7496 /* F_MAXFD is available since NetBSD 2.0. */
7497 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7498 if (ret != -1)
7499 maxhint = max = ret;
7500# elif defined(__linux__)
7501 ret = linux_get_maxfd();
7502 if (maxhint < ret)
7503 maxhint = ret;
7504 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7505# endif
7506 if (max < maxhint)
7507 max = maxhint;
7508 for (fd = lowfd; fd <= max; fd++) {
7509 if (!NIL_P(noclose_fds) &&
7510 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7511 continue;
7512 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7513 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7514 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7515 }
7516# define CONTIGUOUS_CLOSED_FDS 20
7517 if (ret != -1) {
7518 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7519 max = fd + CONTIGUOUS_CLOSED_FDS;
7520 }
7521 }
7522#endif
7523}
7524
7525# ifndef __EMSCRIPTEN__
7526static int
7527popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7528{
7529 struct popen_arg *p = (struct popen_arg*)pp;
7530
7531 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7532}
7533# endif
7534#endif
7535
7536#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7537static VALUE
7538rb_execarg_fixup_v(VALUE execarg_obj)
7539{
7540 rb_execarg_parent_start(execarg_obj);
7541 return Qnil;
7542}
7543#else
7544char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7545#endif
7546
7547#ifndef __EMSCRIPTEN__
7548static VALUE
7549pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7550 const struct rb_io_encoding *convconfig)
7551{
7552 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7553 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7554 rb_pid_t pid = 0;
7555 rb_io_t *fptr;
7556 VALUE port;
7557 rb_io_t *write_fptr;
7558 VALUE write_port;
7559#if defined(HAVE_WORKING_FORK)
7560 int status;
7561 char errmsg[80] = { '\0' };
7562#endif
7563#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7564 int state;
7565 struct popen_arg arg;
7566#endif
7567 int e = 0;
7568#if defined(HAVE_SPAWNV)
7569# if defined(HAVE_SPAWNVE)
7570# define DO_SPAWN(cmd, args, envp) ((args) ? \
7571 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7572 spawne(P_NOWAIT, (cmd), (envp)))
7573# else
7574# define DO_SPAWN(cmd, args, envp) ((args) ? \
7575 spawnv(P_NOWAIT, (cmd), (args)) : \
7576 spawn(P_NOWAIT, (cmd)))
7577# endif
7578# if !defined(HAVE_WORKING_FORK)
7579 char **args = NULL;
7580# if defined(HAVE_SPAWNVE)
7581 char **envp = NULL;
7582# endif
7583# endif
7584#endif
7585#if !defined(HAVE_WORKING_FORK)
7586 struct rb_execarg sarg, *sargp = &sarg;
7587#endif
7588 FILE *fp = 0;
7589 int fd = -1;
7590 int write_fd = -1;
7591#if !defined(HAVE_WORKING_FORK)
7592 const char *cmd = 0;
7593
7594 if (prog)
7595 cmd = StringValueCStr(prog);
7596#endif
7597
7598#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7599 arg.execarg_obj = execarg_obj;
7600 arg.eargp = eargp;
7601 arg.modef = fmode;
7602 arg.pair[0] = arg.pair[1] = -1;
7603 arg.write_pair[0] = arg.write_pair[1] = -1;
7604# if !defined(HAVE_WORKING_FORK)
7605 if (eargp && !eargp->use_shell) {
7606 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7607 }
7608# endif
7609 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7610 case FMODE_READABLE|FMODE_WRITABLE:
7611 if (rb_pipe(arg.write_pair) < 0)
7612 rb_sys_fail_str(prog);
7613 if (rb_pipe(arg.pair) < 0) {
7614 e = errno;
7615 close(arg.write_pair[0]);
7616 close(arg.write_pair[1]);
7617 rb_syserr_fail_str(e, prog);
7618 }
7619 if (eargp) {
7620 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7621 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7622 }
7623 break;
7624 case FMODE_READABLE:
7625 if (rb_pipe(arg.pair) < 0)
7626 rb_sys_fail_str(prog);
7627 if (eargp)
7628 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7629 break;
7630 case FMODE_WRITABLE:
7631 if (rb_pipe(arg.pair) < 0)
7632 rb_sys_fail_str(prog);
7633 if (eargp)
7634 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7635 break;
7636 default:
7637 rb_sys_fail_str(prog);
7638 }
7639 if (!NIL_P(execarg_obj)) {
7640 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7641 if (state) {
7642 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7643 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7644 if (0 <= arg.pair[0]) close(arg.pair[0]);
7645 if (0 <= arg.pair[1]) close(arg.pair[1]);
7646 rb_execarg_parent_end(execarg_obj);
7647 rb_jump_tag(state);
7648 }
7649
7650# if defined(HAVE_WORKING_FORK)
7651 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7652# else
7653 rb_execarg_run_options(eargp, sargp, NULL, 0);
7654# if defined(HAVE_SPAWNVE)
7655 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7656# endif
7657 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7658 /* exec failed */
7659 switch (e = errno) {
7660 case EAGAIN:
7661# if EWOULDBLOCK != EAGAIN
7662 case EWOULDBLOCK:
7663# endif
7664 rb_thread_sleep(1);
7665 continue;
7666 }
7667 break;
7668 }
7669 if (eargp)
7670 rb_execarg_run_options(sargp, NULL, NULL, 0);
7671# endif
7672 rb_execarg_parent_end(execarg_obj);
7673 }
7674 else {
7675# if defined(HAVE_WORKING_FORK)
7676 pid = rb_call_proc__fork();
7677 if (pid == 0) { /* child */
7678 popen_redirect(&arg);
7679 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7680 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7681 return Qnil;
7682 }
7683# else
7684 rb_notimplement();
7685# endif
7686 }
7687
7688 /* parent */
7689 if (pid < 0) {
7690# if defined(HAVE_WORKING_FORK)
7691 e = errno;
7692# endif
7693 close(arg.pair[0]);
7694 close(arg.pair[1]);
7695 if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) {
7696 close(arg.write_pair[0]);
7697 close(arg.write_pair[1]);
7698 }
7699# if defined(HAVE_WORKING_FORK)
7700 if (errmsg[0])
7701 rb_syserr_fail(e, errmsg);
7702# endif
7703 rb_syserr_fail_str(e, prog);
7704 }
7705 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7706 close(arg.pair[1]);
7707 fd = arg.pair[0];
7708 close(arg.write_pair[0]);
7709 write_fd = arg.write_pair[1];
7710 }
7711 else if (fmode & FMODE_READABLE) {
7712 close(arg.pair[1]);
7713 fd = arg.pair[0];
7714 }
7715 else {
7716 close(arg.pair[0]);
7717 fd = arg.pair[1];
7718 }
7719#else
7720 cmd = rb_execarg_commandline(eargp, &prog);
7721 if (!NIL_P(execarg_obj)) {
7722 rb_execarg_parent_start(execarg_obj);
7723 rb_execarg_run_options(eargp, sargp, NULL, 0);
7724 }
7725 fp = popen(cmd, modestr);
7726 e = errno;
7727 if (eargp) {
7728 rb_execarg_parent_end(execarg_obj);
7729 rb_execarg_run_options(sargp, NULL, NULL, 0);
7730 }
7731 if (!fp) rb_syserr_fail_path(e, prog);
7732 fd = fileno(fp);
7733#endif
7734
7735 port = io_alloc(rb_cIO);
7736 MakeOpenFile(port, fptr);
7737 fptr->fd = fd;
7738 fptr->stdio_file = fp;
7739 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7740 if (convconfig) {
7741 fptr->encs = *convconfig;
7742#if RUBY_CRLF_ENVIRONMENT
7743 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
7744 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7745 }
7746#endif
7747 }
7748 else {
7749 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7750 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7751 }
7752#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7753 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7754 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7755 }
7756#endif
7757 }
7758 fptr->pid = pid;
7759
7760 if (0 <= write_fd) {
7761 write_port = io_alloc(rb_cIO);
7762 MakeOpenFile(write_port, write_fptr);
7763 write_fptr->fd = write_fd;
7764 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7765 fptr->mode &= ~FMODE_WRITABLE;
7766 fptr->tied_io_for_writing = write_port;
7767 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7768 }
7769
7770#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7771 fptr->finalize = pipe_finalize;
7772 pipe_add_fptr(fptr);
7773#endif
7774 return port;
7775}
7776#else
7777static VALUE
7778pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7779 const struct rb_io_encoding *convconfig)
7780{
7781 rb_raise(rb_eNotImpError, "popen() is not available");
7782}
7783#endif
7784
7785static int
7786is_popen_fork(VALUE prog)
7787{
7788 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7789#if !defined(HAVE_WORKING_FORK)
7790 rb_raise(rb_eNotImpError,
7791 "fork() function is unimplemented on this machine");
7792#else
7793 return TRUE;
7794#endif
7795 }
7796 return FALSE;
7797}
7798
7799static VALUE
7800pipe_open_s(VALUE prog, const char *modestr, int fmode,
7801 const struct rb_io_encoding *convconfig)
7802{
7803 int argc = 1;
7804 VALUE *argv = &prog;
7805 VALUE execarg_obj = Qnil;
7806
7807 if (!is_popen_fork(prog))
7808 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7809 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7810}
7811
7812static VALUE
7813pipe_close(VALUE io)
7814{
7815 rb_io_t *fptr = io_close_fptr(io);
7816 if (fptr) {
7817 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7818 }
7819 return Qnil;
7820}
7821
7822static VALUE popen_finish(VALUE port, VALUE klass);
7823
7824/*
7825 * call-seq:
7826 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7827 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7828 *
7829 * Executes the given command +cmd+ as a subprocess
7830 * whose $stdin and $stdout are connected to a new stream +io+.
7831 *
7832 * This method has potential security vulnerabilities if called with untrusted input;
7833 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7834 *
7835 * If no block is given, returns the new stream,
7836 * which depending on given +mode+ may be open for reading, writing, or both.
7837 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7838 *
7839 * If a block is given, the stream is passed to the block
7840 * (again, open for reading, writing, or both);
7841 * when the block exits, the stream is closed,
7842 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7843 *
7844 * Optional argument +mode+ may be any valid \IO mode.
7845 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7846 *
7847 * Required argument +cmd+ determines which of the following occurs:
7848 *
7849 * - The process forks.
7850 * - A specified program runs in a shell.
7851 * - A specified program runs with specified arguments.
7852 * - A specified program runs with specified arguments and a specified +argv0+.
7853 *
7854 * Each of these is detailed below.
7855 *
7856 * The optional hash argument +env+ specifies name/value pairs that are to be added
7857 * to the environment variables for the subprocess:
7858 *
7859 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7860 * pipe.puts 'puts ENV["FOO"]'
7861 * pipe.close_write
7862 * pipe.gets
7863 * end => "bar\n"
7864 *
7865 * Optional keyword arguments +opts+ specify:
7866 *
7867 * - {Open options}[rdoc-ref:IO@Open+Options].
7868 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7869 * - Options for Kernel#spawn.
7870 *
7871 * <b>Forked \Process</b>
7872 *
7873 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7874 * IO.popen('-') do |pipe|
7875 * if pipe
7876 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7877 * else
7878 * $stderr.puts "In child, pid is #{$$}\n"
7879 * end
7880 * end
7881 *
7882 * Output:
7883 *
7884 * In parent, child pid is 26253
7885 * In child, pid is 26253
7886 *
7887 * Note that this is not supported on all platforms.
7888 *
7889 * <b>Shell Subprocess</b>
7890 *
7891 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7892 * the program named +cmd+ is run as a shell command:
7893 *
7894 * IO.popen('uname') do |pipe|
7895 * pipe.readlines
7896 * end
7897 *
7898 * Output:
7899 *
7900 * ["Linux\n"]
7901 *
7902 * Another example:
7903 *
7904 * IO.popen('/bin/sh', 'r+') do |pipe|
7905 * pipe.puts('ls')
7906 * pipe.close_write
7907 * $stderr.puts pipe.readlines.size
7908 * end
7909 *
7910 * Output:
7911 *
7912 * 213
7913 *
7914 * <b>Program Subprocess</b>
7915 *
7916 * When argument +cmd+ is an array of strings,
7917 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7918 *
7919 * IO.popen(['du', '..', '.']) do |pipe|
7920 * $stderr.puts pipe.readlines.size
7921 * end
7922 *
7923 * Output:
7924 *
7925 * 1111
7926 *
7927 * <b>Program Subprocess with <tt>argv0</tt></b>
7928 *
7929 * When argument +cmd+ is an array whose first element is a 2-element string array
7930 * and whose remaining elements (if any) are strings:
7931 *
7932 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7933 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7934 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7935 *
7936 * Example (sets <tt>$0</tt> to 'foo'):
7937 *
7938 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7939 *
7940 * <b>Some Special Examples</b>
7941 *
7942 * # Set IO encoding.
7943 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7944 * euc_jp_string = nkf_io.read
7945 * }
7946 *
7947 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7948 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7949 * ls_result_with_error = io.read
7950 * end
7951 *
7952 * # Use mixture of spawn options and IO options.
7953 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7954 * ls_result_with_error = io.read
7955 * end
7956 *
7957 * f = IO.popen("uname")
7958 * p f.readlines
7959 * f.close
7960 * puts "Parent is #{Process.pid}"
7961 * IO.popen("date") {|f| puts f.gets }
7962 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7963 * p $?
7964 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7965 * f.puts "bar"; f.close_write; puts f.gets
7966 * }
7967 *
7968 * Output (from last section):
7969 *
7970 * ["Linux\n"]
7971 * Parent is 21346
7972 * Thu Jan 15 22:41:19 JST 2009
7973 * 21346 is here, f is #<IO:fd 3>
7974 * 21352 is here, f is nil
7975 * #<Process::Status: pid 21352 exit 0>
7976 * <foo>bar;zot;
7977 *
7978 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7979 *
7980 */
7981
7982static VALUE
7983rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7984{
7985 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7986
7987 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7988 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7989 switch (argc) {
7990 case 2:
7991 pmode = argv[1];
7992 case 1:
7993 pname = argv[0];
7994 break;
7995 default:
7996 {
7997 int ex = !NIL_P(opt);
7998 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7999 }
8000 }
8001 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8002}
8003
8004 VALUE
8005rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8006{
8007 const char *modestr;
8008 VALUE tmp, execarg_obj = Qnil;
8009 int oflags, fmode;
8010 struct rb_io_encoding convconfig;
8011
8012 tmp = rb_check_array_type(pname);
8013 if (!NIL_P(tmp)) {
8014 long len = RARRAY_LEN(tmp);
8015#if SIZEOF_LONG > SIZEOF_INT
8016 if (len > INT_MAX) {
8017 rb_raise(rb_eArgError, "too many arguments");
8018 }
8019#endif
8020 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8021 RB_GC_GUARD(tmp);
8022 }
8023 else {
8024 StringValue(pname);
8025 execarg_obj = Qnil;
8026 if (!is_popen_fork(pname))
8027 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8028 }
8029 if (!NIL_P(execarg_obj)) {
8030 if (!NIL_P(opt))
8031 opt = rb_execarg_extract_options(execarg_obj, opt);
8032 if (!NIL_P(env))
8033 rb_execarg_setenv(execarg_obj, env);
8034 }
8035 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8036 modestr = rb_io_oflags_modestr(oflags);
8037
8038 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8039}
8040
8041static VALUE
8042popen_finish(VALUE port, VALUE klass)
8043{
8044 if (NIL_P(port)) {
8045 /* child */
8046 if (rb_block_given_p()) {
8047 rb_protect(rb_yield, Qnil, NULL);
8048 rb_io_flush(rb_ractor_stdout());
8049 rb_io_flush(rb_ractor_stderr());
8050 _exit(0);
8051 }
8052 return Qnil;
8053 }
8054 RBASIC_SET_CLASS(port, klass);
8055 if (rb_block_given_p()) {
8056 return rb_ensure(rb_yield, port, pipe_close, port);
8057 }
8058 return port;
8059}
8060
8061#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8062struct popen_writer_arg {
8063 char *const *argv;
8064 struct popen_arg popen;
8065};
8066
8067static int
8068exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8069{
8070 struct popen_writer_arg *pw = arg;
8071 pw->popen.modef = FMODE_WRITABLE;
8072 popen_redirect(&pw->popen);
8073 execv(pw->argv[0], pw->argv);
8074 strlcpy(errmsg, strerror(errno), buflen);
8075 return -1;
8076}
8077#endif
8078
8079FILE *
8080ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8081{
8082#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8083# ifdef HAVE_WORKING_FORK
8084 struct popen_writer_arg pw;
8085 int *const write_pair = pw.popen.pair;
8086# else
8087 int write_pair[2];
8088# endif
8089
8090 int result = rb_cloexec_pipe(write_pair);
8091 *pid = -1;
8092 if (result == 0) {
8093# ifdef HAVE_WORKING_FORK
8094 pw.argv = argv;
8095 int status;
8096 char errmsg[80] = {'\0'};
8097 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8098# else
8099 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8100 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8101# endif
8102 close(write_pair[0]);
8103 if (*pid < 0) {
8104 close(write_pair[1]);
8105 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8106 }
8107 else {
8108 return fdopen(write_pair[1], "w");
8109 }
8110 }
8111#endif
8112 return NULL;
8113}
8114
8115static VALUE
8116rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8117{
8118 struct rb_io_encoding convconfig;
8119 int oflags, fmode;
8120 mode_t perm;
8121
8122 FilePathValue(fname);
8123
8124 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8125 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8126
8127 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8128
8129 return io;
8130}
8131
8132/*
8133 * Document-method: File::open
8134 *
8135 * call-seq:
8136 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8137 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8138 *
8139 * Creates a new File object, via File.new with the given arguments.
8140 *
8141 * With no block given, returns the File object.
8142 *
8143 * With a block given, calls the block with the File object
8144 * and returns the block's value.
8145 *
8146 */
8147
8148/*
8149 * Document-method: IO::open
8150 *
8151 * call-seq:
8152 * IO.open(fd, mode = 'r', **opts) -> io
8153 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8154 *
8155 * Creates a new \IO object, via IO.new with the given arguments.
8156 *
8157 * With no block given, returns the \IO object.
8158 *
8159 * With a block given, calls the block with the \IO object
8160 * and returns the block's value.
8161 *
8162 */
8163
8164static VALUE
8165rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8166{
8167 VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
8168
8169 if (rb_block_given_p()) {
8170 return rb_ensure(rb_yield, io, io_close, io);
8171 }
8172
8173 return io;
8174}
8175
8176/*
8177 * call-seq:
8178 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8179 *
8180 * Opens the file at the given path with the given mode and permissions;
8181 * returns the integer file descriptor.
8182 *
8183 * If the file is to be readable, it must exist;
8184 * if the file is to be writable and does not exist,
8185 * it is created with the given permissions:
8186 *
8187 * File.write('t.tmp', '') # => 0
8188 * IO.sysopen('t.tmp') # => 8
8189 * IO.sysopen('t.tmp', 'w') # => 9
8190 *
8191 *
8192 */
8193
8194static VALUE
8195rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8196{
8197 VALUE fname, vmode, vperm;
8198 VALUE intmode;
8199 int oflags, fd;
8200 mode_t perm;
8201
8202 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8203 FilePathValue(fname);
8204
8205 if (NIL_P(vmode))
8206 oflags = O_RDONLY;
8207 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8208 oflags = NUM2INT(intmode);
8209 else {
8210 StringValue(vmode);
8211 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8212 }
8213 if (NIL_P(vperm)) perm = 0666;
8214 else perm = NUM2MODET(vperm);
8215
8216 RB_GC_GUARD(fname) = rb_str_new4(fname);
8217 fd = rb_sysopen(fname, oflags, perm);
8218 return INT2NUM(fd);
8219}
8220
8221static VALUE
8222check_pipe_command(VALUE filename_or_command)
8223{
8224 char *s = RSTRING_PTR(filename_or_command);
8225 long l = RSTRING_LEN(filename_or_command);
8226 char *e = s + l;
8227 int chlen;
8228
8229 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8230 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8231 return cmd;
8232 }
8233 return Qnil;
8234}
8235
8236/*
8237 * call-seq:
8238 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8239 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8240 *
8241 * Creates an IO object connected to the given file.
8242 *
8243 * This method has potential security vulnerabilities if called with untrusted input;
8244 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8245 *
8246 * With no block given, file stream is returned:
8247 *
8248 * open('t.txt') # => #<File:t.txt>
8249 *
8250 * With a block given, calls the block with the open file stream,
8251 * then closes the stream:
8252 *
8253 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8254 *
8255 * Output:
8256 *
8257 * #<File:t.txt>
8258 *
8259 * See File.open for details.
8260 *
8261 */
8262
8263static VALUE
8264rb_f_open(int argc, VALUE *argv, VALUE _)
8265{
8266 ID to_open = 0;
8267 int redirect = FALSE;
8268
8269 if (argc >= 1) {
8270 CONST_ID(to_open, "to_open");
8271 if (rb_respond_to(argv[0], to_open)) {
8272 redirect = TRUE;
8273 }
8274 else {
8275 VALUE tmp = argv[0];
8276 FilePathValue(tmp);
8277 if (NIL_P(tmp)) {
8278 redirect = TRUE;
8279 }
8280 else {
8281 VALUE cmd = check_pipe_command(tmp);
8282 if (!NIL_P(cmd)) {
8283 // TODO: when removed in 4.0, update command_injection.rdoc
8284 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8285 argv[0] = cmd;
8286 return rb_io_s_popen(argc, argv, rb_cIO);
8287 }
8288 }
8289 }
8290 }
8291 if (redirect) {
8292 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8293
8294 if (rb_block_given_p()) {
8295 return rb_ensure(rb_yield, io, io_close, io);
8296 }
8297 return io;
8298 }
8299 return rb_io_s_open(argc, argv, rb_cFile);
8300}
8301
8302static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const struct rb_io_encoding *, mode_t);
8303
8304static VALUE
8305rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8306{
8307 int oflags, fmode;
8308 struct rb_io_encoding convconfig;
8309 mode_t perm;
8310
8311 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8312 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8313 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8314}
8315
8316static VALUE
8317rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8318 const struct rb_io_encoding *convconfig, mode_t perm)
8319{
8320 VALUE cmd;
8321 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8322 // TODO: when removed in 4.0, update command_injection.rdoc
8323 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8324 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8325 }
8326 else {
8327 return rb_file_open_generic(io_alloc(klass), filename,
8328 oflags, fmode, convconfig, perm);
8329 }
8330}
8331
8332static VALUE
8333io_reopen(VALUE io, VALUE nfile)
8334{
8335 rb_io_t *fptr, *orig;
8336 int fd, fd2;
8337 rb_off_t pos = 0;
8338
8339 nfile = rb_io_get_io(nfile);
8340 GetOpenFile(io, fptr);
8341 GetOpenFile(nfile, orig);
8342
8343 if (fptr == orig) return io;
8344 if (RUBY_IO_EXTERNAL_P(fptr)) {
8345 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8346 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8347 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8348 rb_raise(rb_eArgError,
8349 "%s can't change access mode from \"%s\" to \"%s\"",
8350 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8351 rb_io_fmode_modestr(orig->mode));
8352 }
8353 }
8354 if (fptr->mode & FMODE_WRITABLE) {
8355 if (io_fflush(fptr) < 0)
8356 rb_sys_fail_on_write(fptr);
8357 }
8358 else {
8359 flush_before_seek(fptr, true);
8360 }
8361 if (orig->mode & FMODE_READABLE) {
8362 pos = io_tell(orig);
8363 }
8364 if (orig->mode & FMODE_WRITABLE) {
8365 if (io_fflush(orig) < 0)
8366 rb_sys_fail_on_write(fptr);
8367 }
8368
8369 /* copy rb_io_t structure */
8370 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8371 fptr->encs = orig->encs;
8372 fptr->pid = orig->pid;
8373 fptr->lineno = orig->lineno;
8374 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8375 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8376 fptr_copy_finalizer(fptr, orig);
8377
8378 fd = fptr->fd;
8379 fd2 = orig->fd;
8380 if (fd != fd2) {
8381 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8382 /* need to keep FILE objects of stdin, stdout and stderr */
8383 if (rb_cloexec_dup2(fd2, fd) < 0)
8384 rb_sys_fail_path(orig->pathv);
8385 rb_update_max_fd(fd);
8386 }
8387 else {
8388 fclose(fptr->stdio_file);
8389 fptr->stdio_file = 0;
8390 fptr->fd = -1;
8391 if (rb_cloexec_dup2(fd2, fd) < 0)
8392 rb_sys_fail_path(orig->pathv);
8393 rb_update_max_fd(fd);
8394 fptr->fd = fd;
8395 }
8396 rb_thread_fd_close(fd);
8397 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8398 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8399 rb_sys_fail_path(fptr->pathv);
8400 }
8401 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8402 rb_sys_fail_path(orig->pathv);
8403 }
8404 }
8405 }
8406
8407 if (fptr->mode & FMODE_BINMODE) {
8408 rb_io_binmode(io);
8409 }
8410
8411 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8412 return io;
8413}
8414
8415#ifdef _WIN32
8416int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8417#else
8418static int
8419rb_freopen(VALUE fname, const char *mode, FILE *fp)
8420{
8421 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8422 RB_GC_GUARD(fname);
8423 return errno;
8424 }
8425 return 0;
8426}
8427#endif
8428
8429/*
8430 * call-seq:
8431 * reopen(other_io) -> self
8432 * reopen(path, mode = 'r', **opts) -> self
8433 *
8434 * Reassociates the stream with another stream,
8435 * which may be of a different class.
8436 * This method may be used to redirect an existing stream
8437 * to a new destination.
8438 *
8439 * With argument +other_io+ given, reassociates with that stream:
8440 *
8441 * # Redirect $stdin from a file.
8442 * f = File.open('t.txt')
8443 * $stdin.reopen(f)
8444 * f.close
8445 *
8446 * # Redirect $stdout to a file.
8447 * f = File.open('t.tmp', 'w')
8448 * $stdout.reopen(f)
8449 * f.close
8450 *
8451 * With argument +path+ given, reassociates with a new stream to that file path:
8452 *
8453 * $stdin.reopen('t.txt')
8454 * $stdout.reopen('t.tmp', 'w')
8455 *
8456 * Optional keyword arguments +opts+ specify:
8457 *
8458 * - {Open Options}[rdoc-ref:IO@Open+Options].
8459 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8460 *
8461 */
8462
8463static VALUE
8464rb_io_reopen(int argc, VALUE *argv, VALUE file)
8465{
8466 VALUE fname, nmode, opt;
8467 int oflags;
8468 rb_io_t *fptr;
8469
8470 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8471 VALUE tmp = rb_io_check_io(fname);
8472 if (!NIL_P(tmp)) {
8473 return io_reopen(file, tmp);
8474 }
8475 }
8476
8477 FilePathValue(fname);
8478 rb_io_taint_check(file);
8479 fptr = RFILE(file)->fptr;
8480 if (!fptr) {
8481 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8482 }
8483
8484 if (!NIL_P(nmode) || !NIL_P(opt)) {
8485 int fmode;
8486 struct rb_io_encoding convconfig;
8487
8488 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8489 if (RUBY_IO_EXTERNAL_P(fptr) &&
8490 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8491 (fptr->mode & FMODE_READWRITE)) {
8492 rb_raise(rb_eArgError,
8493 "%s can't change access mode from \"%s\" to \"%s\"",
8494 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8495 rb_io_fmode_modestr(fmode));
8496 }
8497 fptr->mode = fmode;
8498 fptr->encs = convconfig;
8499 }
8500 else {
8501 oflags = rb_io_fmode_oflags(fptr->mode);
8502 }
8503
8504 fptr->pathv = fname;
8505 if (fptr->fd < 0) {
8506 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8507 fptr->stdio_file = 0;
8508 return file;
8509 }
8510
8511 if (fptr->mode & FMODE_WRITABLE) {
8512 if (io_fflush(fptr) < 0)
8513 rb_sys_fail_on_write(fptr);
8514 }
8515 fptr->rbuf.off = fptr->rbuf.len = 0;
8516
8517 if (fptr->stdio_file) {
8518 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8519 rb_io_oflags_modestr(oflags),
8520 fptr->stdio_file);
8521 if (e) rb_syserr_fail_path(e, fptr->pathv);
8522 fptr->fd = fileno(fptr->stdio_file);
8523 rb_fd_fix_cloexec(fptr->fd);
8524#ifdef USE_SETVBUF
8525 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8526 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8527#endif
8528 if (fptr->stdio_file == stderr) {
8529 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8530 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8531 }
8532 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8533 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8534 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8535 }
8536 }
8537 else {
8538 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8539 int err = 0;
8540 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8541 err = errno;
8542 (void)close(tmpfd);
8543 if (err) {
8544 rb_syserr_fail_path(err, fptr->pathv);
8545 }
8546 }
8547
8548 return file;
8549}
8550
8551/* :nodoc: */
8552static VALUE
8553rb_io_init_copy(VALUE dest, VALUE io)
8554{
8555 rb_io_t *fptr, *orig;
8556 int fd;
8557 VALUE write_io;
8558 rb_off_t pos;
8559
8560 io = rb_io_get_io(io);
8561 if (!OBJ_INIT_COPY(dest, io)) return dest;
8562 GetOpenFile(io, orig);
8563 MakeOpenFile(dest, fptr);
8564
8565 rb_io_flush(io);
8566
8567 /* copy rb_io_t structure */
8568 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8569 fptr->encs = orig->encs;
8570 fptr->pid = orig->pid;
8571 fptr->lineno = orig->lineno;
8572 fptr->timeout = orig->timeout;
8573 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8574 fptr_copy_finalizer(fptr, orig);
8575
8576 fd = ruby_dup(orig->fd);
8577 fptr->fd = fd;
8578 pos = io_tell(orig);
8579 if (0 <= pos)
8580 io_seek(fptr, pos, SEEK_SET);
8581 if (fptr->mode & FMODE_BINMODE) {
8582 rb_io_binmode(dest);
8583 }
8584
8585 write_io = GetWriteIO(io);
8586 if (io != write_io) {
8587 write_io = rb_obj_dup(write_io);
8588 fptr->tied_io_for_writing = write_io;
8589 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8590 }
8591
8592 return dest;
8593}
8594
8595/*
8596 * call-seq:
8597 * printf(format_string, *objects) -> nil
8598 *
8599 * Formats and writes +objects+ to the stream.
8600 *
8601 * For details on +format_string+, see
8602 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8603 *
8604 */
8605
8606 VALUE
8607rb_io_printf(int argc, const VALUE *argv, VALUE out)
8608{
8609 rb_io_write(out, rb_f_sprintf(argc, argv));
8610 return Qnil;
8611}
8612
8613/*
8614 * call-seq:
8615 * printf(format_string, *objects) -> nil
8616 * printf(io, format_string, *objects) -> nil
8617 *
8618 * Equivalent to:
8619 *
8620 * io.write(sprintf(format_string, *objects))
8621 *
8622 * For details on +format_string+, see
8623 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8624 *
8625 * With the single argument +format_string+, formats +objects+ into the string,
8626 * then writes the formatted string to $stdout:
8627 *
8628 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8629 *
8630 * Output (on $stdout):
8631 *
8632 * 0024 24 24.00#
8633 *
8634 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8635 * then writes the formatted string to +io+:
8636 *
8637 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8638 *
8639 * Output (on $stderr):
8640 *
8641 * 0024 24 24.00# => nil
8642 *
8643 * With no arguments, does nothing.
8644 *
8645 */
8646
8647static VALUE
8648rb_f_printf(int argc, VALUE *argv, VALUE _)
8649{
8650 VALUE out;
8651
8652 if (argc == 0) return Qnil;
8653 if (RB_TYPE_P(argv[0], T_STRING)) {
8654 out = rb_ractor_stdout();
8655 }
8656 else {
8657 out = argv[0];
8658 argv++;
8659 argc--;
8660 }
8661 rb_io_write(out, rb_f_sprintf(argc, argv));
8662
8663 return Qnil;
8664}
8665
8666static void
8667deprecated_str_setter(VALUE val, ID id, VALUE *var)
8668{
8669 rb_str_setter(val, id, &val);
8670 if (!NIL_P(val)) {
8671 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8672 }
8673 *var = val;
8674}
8675
8676/*
8677 * call-seq:
8678 * print(*objects) -> nil
8679 *
8680 * Writes the given objects to the stream; returns +nil+.
8681 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8682 * (<tt>$\</tt>), if it is not +nil+.
8683 * See {Line IO}[rdoc-ref:IO@Line+IO].
8684 *
8685 * With argument +objects+ given, for each object:
8686 *
8687 * - Converts via its method +to_s+ if not a string.
8688 * - Writes to the stream.
8689 * - If not the last object, writes the output field separator
8690 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8691 *
8692 * With default separators:
8693 *
8694 * f = File.open('t.tmp', 'w+')
8695 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8696 * p $OUTPUT_RECORD_SEPARATOR
8697 * p $OUTPUT_FIELD_SEPARATOR
8698 * f.print(*objects)
8699 * f.rewind
8700 * p f.read
8701 * f.close
8702 *
8703 * Output:
8704 *
8705 * nil
8706 * nil
8707 * "00.00/10+0izerozero"
8708 *
8709 * With specified separators:
8710 *
8711 * $\ = "\n"
8712 * $, = ','
8713 * f.rewind
8714 * f.print(*objects)
8715 * f.rewind
8716 * p f.read
8717 *
8718 * Output:
8719 *
8720 * "0,0.0,0/1,0+0i,zero,zero\n"
8721 *
8722 * With no argument given, writes the content of <tt>$_</tt>
8723 * (which is usually the most recent user input):
8724 *
8725 * f = File.open('t.tmp', 'w+')
8726 * gets # Sets $_ to the most recent user input.
8727 * f.print
8728 * f.close
8729 *
8730 */
8731
8732 VALUE
8733rb_io_print(int argc, const VALUE *argv, VALUE out)
8734{
8735 int i;
8736 VALUE line;
8737
8738 /* if no argument given, print `$_' */
8739 if (argc == 0) {
8740 argc = 1;
8741 line = rb_lastline_get();
8742 argv = &line;
8743 }
8744 if (argc > 1 && !NIL_P(rb_output_fs)) {
8745 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8746 }
8747 for (i=0; i<argc; i++) {
8748 if (!NIL_P(rb_output_fs) && i>0) {
8749 rb_io_write(out, rb_output_fs);
8750 }
8751 rb_io_write(out, argv[i]);
8752 }
8753 if (argc > 0 && !NIL_P(rb_output_rs)) {
8754 rb_io_write(out, rb_output_rs);
8755 }
8756
8757 return Qnil;
8758}
8759
8760/*
8761 * call-seq:
8762 * print(*objects) -> nil
8763 *
8764 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8765 * this method is the straightforward way to write to <tt>$stdout</tt>.
8766 *
8767 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8768 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8769 * <tt>$\</tt>), if it is not +nil+.
8770 *
8771 * With argument +objects+ given, for each object:
8772 *
8773 * - Converts via its method +to_s+ if not a string.
8774 * - Writes to <tt>stdout</tt>.
8775 * - If not the last object, writes the output field separator
8776 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8777 *
8778 * With default separators:
8779 *
8780 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8781 * $OUTPUT_RECORD_SEPARATOR
8782 * $OUTPUT_FIELD_SEPARATOR
8783 * print(*objects)
8784 *
8785 * Output:
8786 *
8787 * nil
8788 * nil
8789 * 00.00/10+0izerozero
8790 *
8791 * With specified separators:
8792 *
8793 * $OUTPUT_RECORD_SEPARATOR = "\n"
8794 * $OUTPUT_FIELD_SEPARATOR = ','
8795 * print(*objects)
8796 *
8797 * Output:
8798 *
8799 * 0,0.0,0/1,0+0i,zero,zero
8800 *
8801 * With no argument given, writes the content of <tt>$_</tt>
8802 * (which is usually the most recent user input):
8803 *
8804 * gets # Sets $_ to the most recent user input.
8805 * print # Prints $_.
8806 *
8807 */
8808
8809static VALUE
8810rb_f_print(int argc, const VALUE *argv, VALUE _)
8811{
8812 rb_io_print(argc, argv, rb_ractor_stdout());
8813 return Qnil;
8814}
8815
8816/*
8817 * call-seq:
8818 * putc(object) -> object
8819 *
8820 * Writes a character to the stream.
8821 * See {Character IO}[rdoc-ref:IO@Character+IO].
8822 *
8823 * If +object+ is numeric, converts to integer if necessary,
8824 * then writes the character whose code is the
8825 * least significant byte;
8826 * if +object+ is a string, writes the first character:
8827 *
8828 * $stdout.putc "A"
8829 * $stdout.putc 65
8830 *
8831 * Output:
8832 *
8833 * AA
8834 *
8835 */
8836
8837static VALUE
8838rb_io_putc(VALUE io, VALUE ch)
8839{
8840 VALUE str;
8841 if (RB_TYPE_P(ch, T_STRING)) {
8842 str = rb_str_substr(ch, 0, 1);
8843 }
8844 else {
8845 char c = NUM2CHR(ch);
8846 str = rb_str_new(&c, 1);
8847 }
8848 rb_io_write(io, str);
8849 return ch;
8850}
8851
8852#define forward(obj, id, argc, argv) \
8853 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8854#define forward_public(obj, id, argc, argv) \
8855 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8856#define forward_current(id, argc, argv) \
8857 forward_public(ARGF.current_file, id, argc, argv)
8858
8859/*
8860 * call-seq:
8861 * putc(int) -> int
8862 *
8863 * Equivalent to:
8864 *
8865 * $stdout.putc(int)
8866 *
8867 * See IO#putc for important information regarding multi-byte characters.
8868 *
8869 */
8870
8871static VALUE
8872rb_f_putc(VALUE recv, VALUE ch)
8873{
8874 VALUE r_stdout = rb_ractor_stdout();
8875 if (recv == r_stdout) {
8876 return rb_io_putc(recv, ch);
8877 }
8878 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8879}
8880
8881
8882int
8883rb_str_end_with_asciichar(VALUE str, int c)
8884{
8885 long len = RSTRING_LEN(str);
8886 const char *ptr = RSTRING_PTR(str);
8887 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8888 int n;
8889
8890 if (len == 0) return 0;
8891 if ((n = rb_enc_mbminlen(enc)) == 1) {
8892 return ptr[len - 1] == c;
8893 }
8894 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8895}
8896
8897static VALUE
8898io_puts_ary(VALUE ary, VALUE out, int recur)
8899{
8900 VALUE tmp;
8901 long i;
8902
8903 if (recur) {
8904 tmp = rb_str_new2("[...]");
8905 rb_io_puts(1, &tmp, out);
8906 return Qtrue;
8907 }
8908 ary = rb_check_array_type(ary);
8909 if (NIL_P(ary)) return Qfalse;
8910 for (i=0; i<RARRAY_LEN(ary); i++) {
8911 tmp = RARRAY_AREF(ary, i);
8912 rb_io_puts(1, &tmp, out);
8913 }
8914 return Qtrue;
8915}
8916
8917/*
8918 * call-seq:
8919 * puts(*objects) -> nil
8920 *
8921 * Writes the given +objects+ to the stream, which must be open for writing;
8922 * returns +nil+.\
8923 * Writes a newline after each that does not already end with a newline sequence.
8924 * If called without arguments, writes a newline.
8925 * See {Line IO}[rdoc-ref:IO@Line+IO].
8926 *
8927 * Note that each added newline is the character <tt>"\n"<//tt>,
8928 * not the output record separator (<tt>$\</tt>).
8929 *
8930 * Treatment for each object:
8931 *
8932 * - String: writes the string.
8933 * - Neither string nor array: writes <tt>object.to_s</tt>.
8934 * - Array: writes each element of the array; arrays may be nested.
8935 *
8936 * To keep these examples brief, we define this helper method:
8937 *
8938 * def show(*objects)
8939 * # Puts objects to file.
8940 * f = File.new('t.tmp', 'w+')
8941 * f.puts(objects)
8942 * # Return file content.
8943 * f.rewind
8944 * p f.read
8945 * f.close
8946 * end
8947 *
8948 * # Strings without newlines.
8949 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8950 * # Strings, some with newlines.
8951 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8952 *
8953 * # Neither strings nor arrays:
8954 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8955 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8956 *
8957 * # Array of strings.
8958 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8959 * # Nested arrays.
8960 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8961 *
8962 */
8963
8964 VALUE
8965rb_io_puts(int argc, const VALUE *argv, VALUE out)
8966{
8967 VALUE line, args[2];
8968
8969 /* if no argument given, print newline. */
8970 if (argc == 0) {
8971 rb_io_write(out, rb_default_rs);
8972 return Qnil;
8973 }
8974 for (int i = 0; i < argc; i++) {
8975 // Convert the argument to a string:
8976 if (RB_TYPE_P(argv[i], T_STRING)) {
8977 line = argv[i];
8978 }
8979 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8980 continue;
8981 }
8982 else {
8983 line = rb_obj_as_string(argv[i]);
8984 }
8985
8986 // Write the line:
8987 int n = 0;
8988 if (RSTRING_LEN(line) == 0) {
8989 args[n++] = rb_default_rs;
8990 }
8991 else {
8992 args[n++] = line;
8993 if (!rb_str_end_with_asciichar(line, '\n')) {
8994 args[n++] = rb_default_rs;
8995 }
8996 }
8997
8998 rb_io_writev(out, n, args);
8999 }
9000
9001 return Qnil;
9002}
9003
9004/*
9005 * call-seq:
9006 * puts(*objects) -> nil
9007 *
9008 * Equivalent to
9009 *
9010 * $stdout.puts(objects)
9011 */
9012
9013static VALUE
9014rb_f_puts(int argc, VALUE *argv, VALUE recv)
9015{
9016 VALUE r_stdout = rb_ractor_stdout();
9017 if (recv == r_stdout) {
9018 return rb_io_puts(argc, argv, recv);
9019 }
9020 return forward(r_stdout, rb_intern("puts"), argc, argv);
9021}
9022
9023static VALUE
9024rb_p_write(VALUE str)
9025{
9026 VALUE args[2];
9027 args[0] = str;
9028 args[1] = rb_default_rs;
9029 VALUE r_stdout = rb_ractor_stdout();
9030 if (RB_TYPE_P(r_stdout, T_FILE) &&
9031 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9032 io_writev(2, args, r_stdout);
9033 }
9034 else {
9035 rb_io_writev(r_stdout, 2, args);
9036 }
9037 return Qnil;
9038}
9039
9040void
9041rb_p(VALUE obj) /* for debug print within C code */
9042{
9043 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9044}
9045
9046static VALUE
9047rb_p_result(int argc, const VALUE *argv)
9048{
9049 VALUE ret = Qnil;
9050
9051 if (argc == 1) {
9052 ret = argv[0];
9053 }
9054 else if (argc > 1) {
9055 ret = rb_ary_new4(argc, argv);
9056 }
9057 VALUE r_stdout = rb_ractor_stdout();
9058 if (RB_TYPE_P(r_stdout, T_FILE)) {
9059 rb_uninterruptible(rb_io_flush, r_stdout);
9060 }
9061 return ret;
9062}
9063
9064/*
9065 * call-seq:
9066 * p(object) -> obj
9067 * p(*objects) -> array of objects
9068 * p -> nil
9069 *
9070 * For each object +obj+, executes:
9071 *
9072 * $stdout.write(obj.inspect, "\n")
9073 *
9074 * With one object given, returns the object;
9075 * with multiple objects given, returns an array containing the objects;
9076 * with no object given, returns +nil+.
9077 *
9078 * Examples:
9079 *
9080 * r = Range.new(0, 4)
9081 * p r # => 0..4
9082 * p [r, r, r] # => [0..4, 0..4, 0..4]
9083 * p # => nil
9084 *
9085 * Output:
9086 *
9087 * 0..4
9088 * [0..4, 0..4, 0..4]
9089 *
9090 * Kernel#p is designed for debugging purposes.
9091 * Ruby implementations may define Kernel#p to be uninterruptible
9092 * in whole or in part.
9093 * On CRuby, Kernel#p's writing of data is uninterruptible.
9094 */
9095
9096static VALUE
9097rb_f_p(int argc, VALUE *argv, VALUE self)
9098{
9099 int i;
9100 for (i=0; i<argc; i++) {
9101 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9102 rb_uninterruptible(rb_p_write, inspected);
9103 }
9104 return rb_p_result(argc, argv);
9105}
9106
9107/*
9108 * call-seq:
9109 * display(port = $>) -> nil
9110 *
9111 * Writes +self+ on the given port:
9112 *
9113 * 1.display
9114 * "cat".display
9115 * [ 4, 5, 6 ].display
9116 * puts
9117 *
9118 * Output:
9119 *
9120 * 1cat[4, 5, 6]
9121 *
9122 */
9123
9124static VALUE
9125rb_obj_display(int argc, VALUE *argv, VALUE self)
9126{
9127 VALUE out;
9128
9129 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9130 rb_io_write(out, self);
9131
9132 return Qnil;
9133}
9134
9135static int
9136rb_stderr_to_original_p(VALUE err)
9137{
9138 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9139}
9140
9141void
9142rb_write_error2(const char *mesg, long len)
9143{
9144 VALUE out = rb_ractor_stderr();
9145 if (rb_stderr_to_original_p(out)) {
9146#ifdef _WIN32
9147 if (isatty(fileno(stderr))) {
9148 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9149 }
9150#endif
9151 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9152 /* failed to write to stderr, what can we do? */
9153 return;
9154 }
9155 }
9156 else {
9157 rb_io_write(out, rb_str_new(mesg, len));
9158 }
9159}
9160
9161void
9162rb_write_error(const char *mesg)
9163{
9164 rb_write_error2(mesg, strlen(mesg));
9165}
9166
9167void
9168rb_write_error_str(VALUE mesg)
9169{
9170 VALUE out = rb_ractor_stderr();
9171 /* a stopgap measure for the time being */
9172 if (rb_stderr_to_original_p(out)) {
9173 size_t len = (size_t)RSTRING_LEN(mesg);
9174#ifdef _WIN32
9175 if (isatty(fileno(stderr))) {
9176 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9177 }
9178#endif
9179 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9180 RB_GC_GUARD(mesg);
9181 return;
9182 }
9183 }
9184 else {
9185 /* may unlock GVL, and */
9186 rb_io_write(out, mesg);
9187 }
9188}
9189
9190int
9191rb_stderr_tty_p(void)
9192{
9193 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9194 return isatty(fileno(stderr));
9195 return 0;
9196}
9197
9198static void
9199must_respond_to(ID mid, VALUE val, ID id)
9200{
9201 if (!rb_respond_to(val, mid)) {
9202 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9203 rb_id2str(id), rb_id2str(mid),
9204 rb_obj_class(val));
9205 }
9206}
9207
9208static void
9209stdin_setter(VALUE val, ID id, VALUE *ptr)
9210{
9211 rb_ractor_stdin_set(val);
9212}
9213
9214static VALUE
9215stdin_getter(ID id, VALUE *ptr)
9216{
9217 return rb_ractor_stdin();
9218}
9219
9220static void
9221stdout_setter(VALUE val, ID id, VALUE *ptr)
9222{
9223 must_respond_to(id_write, val, id);
9224 rb_ractor_stdout_set(val);
9225}
9226
9227static VALUE
9228stdout_getter(ID id, VALUE *ptr)
9229{
9230 return rb_ractor_stdout();
9231}
9232
9233static void
9234stderr_setter(VALUE val, ID id, VALUE *ptr)
9235{
9236 must_respond_to(id_write, val, id);
9237 rb_ractor_stderr_set(val);
9238}
9239
9240static VALUE
9241stderr_getter(ID id, VALUE *ptr)
9242{
9243 return rb_ractor_stderr();
9244}
9245
9246static VALUE
9247allocate_and_open_new_file(VALUE klass)
9248{
9249 VALUE self = io_alloc(klass);
9250 rb_io_make_open_file(self);
9251 return self;
9252}
9253
9254 VALUE
9255rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9256{
9257 int state;
9258 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9259 if (state) {
9260 /* if we raised an exception allocating an IO object, but the caller
9261 intended to transfer ownership of this FD to us, close the fd before
9262 raising the exception. Otherwise, we would leak a FD - the caller
9263 expects GC to close the file, but we never got around to assigning
9264 it to a rb_io. */
9265 if (!(mode & FMODE_EXTERNAL)) {
9266 maygvl_close(descriptor, 0);
9267 }
9268 rb_jump_tag(state);
9269 }
9270
9271
9272 rb_io_t *io = RFILE(self)->fptr;
9273 io->self = self;
9274 io->fd = descriptor;
9275 io->mode = mode;
9276
9277 /* At this point, Ruby fully owns the descriptor, and will close it when
9278 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9279 in the rest of this method. */
9280
9281 if (NIL_P(path)) {
9282 io->pathv = Qnil;
9283 }
9284 else {
9285 StringValue(path);
9286 io->pathv = rb_str_new_frozen(path);
9287 }
9288
9289 io->timeout = timeout;
9290
9291 if (encoding) {
9292 io->encs = *encoding;
9293 }
9294
9295 rb_update_max_fd(descriptor);
9296
9297 return self;
9298}
9299
9300static VALUE
9301prep_io(int fd, int fmode, VALUE klass, const char *path)
9302{
9303 VALUE path_value = Qnil;
9304 rb_encoding *e;
9305 struct rb_io_encoding convconfig;
9306
9307 if (path) {
9308 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9309 }
9310
9311 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9312 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9313 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9314 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
9315 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
9316#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9317 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9318 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9319 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9320#endif
9321 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9322 convconfig.ecopts = Qnil;
9323
9324 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9325 rb_io_t*io = RFILE(self)->fptr;
9326
9327 if (!io_check_tty(io)) {
9328#ifdef __CYGWIN__
9329 io->mode |= FMODE_BINMODE;
9330 setmode(fd, O_BINARY);
9331#endif
9332 }
9333
9334 return self;
9335}
9336
9337 VALUE
9338rb_io_fdopen(int fd, int oflags, const char *path)
9339{
9340 VALUE klass = rb_cIO;
9341
9342 if (path && strcmp(path, "-")) klass = rb_cFile;
9343 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9344}
9345
9346static VALUE
9347prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9348{
9349 rb_io_t *fptr;
9350 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9351
9352 GetOpenFile(io, fptr);
9353 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
9354#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9355 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9356 if (fmode & FMODE_READABLE) {
9357 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
9358 }
9359#endif
9360 fptr->stdio_file = f;
9361
9362 return io;
9363}
9364
9365 VALUE
9366rb_io_prep_stdin(void)
9367{
9368 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9369}
9370
9371 VALUE
9372rb_io_prep_stdout(void)
9373{
9374 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9375}
9376
9377 VALUE
9378rb_io_prep_stderr(void)
9379{
9380 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9381}
9382
9383FILE *
9384rb_io_stdio_file(rb_io_t *fptr)
9385{
9386 if (!fptr->stdio_file) {
9387 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9388 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9389 }
9390 return fptr->stdio_file;
9391}
9392
9393static inline void
9394rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9395{
9396 buf->ptr = NULL;
9397 buf->off = 0;
9398 buf->len = 0;
9399 buf->capa = 0;
9400}
9401
9402static inline rb_io_t *
9403rb_io_fptr_new(void)
9404{
9405 rb_io_t *fp = ALLOC(rb_io_t);
9406 fp->self = Qnil;
9407 fp->fd = -1;
9408 fp->stdio_file = NULL;
9409 fp->mode = 0;
9410 fp->pid = 0;
9411 fp->lineno = 0;
9412 fp->pathv = Qnil;
9413 fp->finalize = 0;
9414 rb_io_buffer_init(&fp->wbuf);
9415 rb_io_buffer_init(&fp->rbuf);
9416 rb_io_buffer_init(&fp->cbuf);
9417 fp->readconv = NULL;
9418 fp->writeconv = NULL;
9419 fp->writeconv_asciicompat = Qnil;
9420 fp->writeconv_pre_ecflags = 0;
9421 fp->writeconv_pre_ecopts = Qnil;
9422 fp->writeconv_initialized = 0;
9423 fp->tied_io_for_writing = 0;
9424 fp->encs.enc = NULL;
9425 fp->encs.enc2 = NULL;
9426 fp->encs.ecflags = 0;
9427 fp->encs.ecopts = Qnil;
9428 fp->write_lock = Qnil;
9429 fp->timeout = Qnil;
9430 return fp;
9431}
9432
9433rb_io_t *
9434rb_io_make_open_file(VALUE obj)
9435{
9436 rb_io_t *fp = 0;
9437
9438 Check_Type(obj, T_FILE);
9439 if (RFILE(obj)->fptr) {
9440 rb_io_close(obj);
9441 rb_io_fptr_finalize(RFILE(obj)->fptr);
9442 RFILE(obj)->fptr = 0;
9443 }
9444 fp = rb_io_fptr_new();
9445 fp->self = obj;
9446 RFILE(obj)->fptr = fp;
9447 return fp;
9448}
9449
9450static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9451
9452/*
9453 * call-seq:
9454 * IO.new(fd, mode = 'r', **opts) -> io
9455 *
9456 * Creates and returns a new \IO object (file stream) from a file descriptor.
9457 *
9458 * \IO.new may be useful for interaction with low-level libraries.
9459 * For higher-level interactions, it may be simpler to create
9460 * the file stream using File.open.
9461 *
9462 * Argument +fd+ must be a valid file descriptor (integer):
9463 *
9464 * path = 't.tmp'
9465 * fd = IO.sysopen(path) # => 3
9466 * IO.new(fd) # => #<IO:fd 3>
9467 *
9468 * The new \IO object does not inherit encoding
9469 * (because the integer file descriptor does not have an encoding):
9470 *
9471 * fd = IO.sysopen('t.rus', 'rb')
9472 * io = IO.new(fd)
9473 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9474 *
9475 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9476 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9477 *
9478 * IO.new(fd, 'w') # => #<IO:fd 3>
9479 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9480 *
9481 * Optional keyword arguments +opts+ specify:
9482 *
9483 * - {Open Options}[rdoc-ref:IO@Open+Options].
9484 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9485 *
9486 * Examples:
9487 *
9488 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9489 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9490 *
9491 */
9492
9493static VALUE
9494rb_io_initialize(int argc, VALUE *argv, VALUE io)
9495{
9496 VALUE fnum, vmode;
9497 VALUE opt;
9498
9499 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9500 return io_initialize(io, fnum, vmode, opt);
9501}
9502
9503static VALUE
9504io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9505{
9506 rb_io_t *fp;
9507 int fd, fmode, oflags = O_RDONLY;
9508 struct rb_io_encoding convconfig;
9509#if defined(HAVE_FCNTL) && defined(F_GETFL)
9510 int ofmode;
9511#else
9512 struct stat st;
9513#endif
9514
9515 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9516
9517 fd = NUM2INT(fnum);
9518 if (rb_reserved_fd_p(fd)) {
9519 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9520 }
9521#if defined(HAVE_FCNTL) && defined(F_GETFL)
9522 oflags = fcntl(fd, F_GETFL);
9523 if (oflags == -1) rb_sys_fail(0);
9524#else
9525 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9526#endif
9527 rb_update_max_fd(fd);
9528#if defined(HAVE_FCNTL) && defined(F_GETFL)
9529 ofmode = rb_io_oflags_fmode(oflags);
9530 if (NIL_P(vmode)) {
9531 fmode = ofmode;
9532 }
9533 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9534 VALUE error = INT2FIX(EINVAL);
9535 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
9536 }
9537#endif
9538 VALUE path = Qnil;
9539
9540 if (!NIL_P(opt)) {
9541 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9542 fmode |= FMODE_EXTERNAL;
9543 }
9544
9545 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9546 if (!NIL_P(path)) {
9547 StringValue(path);
9548 path = rb_str_new_frozen(path);
9549 }
9550 }
9551
9552 MakeOpenFile(io, fp);
9553 fp->self = io;
9554 fp->fd = fd;
9555 fp->mode = fmode;
9556 fp->encs = convconfig;
9557 fp->pathv = path;
9558 fp->timeout = Qnil;
9559 clear_codeconv(fp);
9560 io_check_tty(fp);
9561 if (fileno(stdin) == fd)
9562 fp->stdio_file = stdin;
9563 else if (fileno(stdout) == fd)
9564 fp->stdio_file = stdout;
9565 else if (fileno(stderr) == fd)
9566 fp->stdio_file = stderr;
9567
9568 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9569 return io;
9570}
9571
9572/*
9573 * call-seq:
9574 * set_encoding_by_bom -> encoding or nil
9575 *
9576 * If the stream begins with a BOM
9577 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9578 * consumes the BOM and sets the external encoding accordingly;
9579 * returns the result encoding if found, or +nil+ otherwise:
9580 *
9581 * File.write('t.tmp', "\u{FEFF}abc")
9582 * io = File.open('t.tmp', 'rb')
9583 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9584 * io.close
9585 *
9586 * File.write('t.tmp', 'abc')
9587 * io = File.open('t.tmp', 'rb')
9588 * io.set_encoding_by_bom # => nil
9589 * io.close
9590 *
9591 * Raises an exception if the stream is not binmode
9592 * or its encoding has already been set.
9593 *
9594 */
9595
9596static VALUE
9597rb_io_set_encoding_by_bom(VALUE io)
9598{
9599 rb_io_t *fptr;
9600
9601 GetOpenFile(io, fptr);
9602 if (!(fptr->mode & FMODE_BINMODE)) {
9603 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9604 }
9605 if (fptr->encs.enc2) {
9606 rb_raise(rb_eArgError, "encoding conversion is set");
9607 }
9608 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9609 rb_raise(rb_eArgError, "encoding is set to %s already",
9610 rb_enc_name(fptr->encs.enc));
9611 }
9612 if (!io_set_encoding_by_bom(io)) return Qnil;
9613 return rb_enc_from_encoding(fptr->encs.enc);
9614}
9615
9616/*
9617 * call-seq:
9618 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9619 *
9620 * Opens the file at the given +path+ according to the given +mode+;
9621 * creates and returns a new File object for that file.
9622 *
9623 * The new File object is buffered mode (or non-sync mode), unless
9624 * +filename+ is a tty.
9625 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9626 *
9627 * Argument +path+ must be a valid file path:
9628 *
9629 * f = File.new('/etc/fstab')
9630 * f.close
9631 * f = File.new('t.txt')
9632 * f.close
9633 *
9634 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9635 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9636 *
9637 * f = File.new('t.tmp', 'w')
9638 * f.close
9639 * f = File.new('t.tmp', File::RDONLY)
9640 * f.close
9641 *
9642 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9643 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9644 *
9645 * f = File.new('t.tmp', File::CREAT, 0644)
9646 * f.close
9647 * f = File.new('t.tmp', File::CREAT, 0444)
9648 * f.close
9649 *
9650 * Optional keyword arguments +opts+ specify:
9651 *
9652 * - {Open Options}[rdoc-ref:IO@Open+Options].
9653 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9654 *
9655 */
9656
9657static VALUE
9658rb_file_initialize(int argc, VALUE *argv, VALUE io)
9659{
9660 if (RFILE(io)->fptr) {
9661 rb_raise(rb_eRuntimeError, "reinitializing File");
9662 }
9663 VALUE fname, vmode, vperm, opt;
9664 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9665 if (posargc < 3) { /* perm is File only */
9666 VALUE fd = rb_check_to_int(fname);
9667
9668 if (!NIL_P(fd)) {
9669 return io_initialize(io, fd, vmode, opt);
9670 }
9671 }
9672 return rb_open_file(io, fname, vmode, vperm, opt);
9673}
9674
9675/* :nodoc: */
9676static VALUE
9677rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9678{
9679 if (rb_block_given_p()) {
9680 VALUE cname = rb_obj_as_string(klass);
9681
9682 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9683 cname, cname);
9684 }
9685 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9686}
9687
9688
9689/*
9690 * call-seq:
9691 * IO.for_fd(fd, mode = 'r', **opts) -> io
9692 *
9693 * Synonym for IO.new.
9694 *
9695 */
9696
9697static VALUE
9698rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9699{
9700 VALUE io = rb_obj_alloc(klass);
9701 rb_io_initialize(argc, argv, io);
9702 return io;
9703}
9704
9705/*
9706 * call-seq:
9707 * ios.autoclose? -> true or false
9708 *
9709 * Returns +true+ if the underlying file descriptor of _ios_ will be
9710 * closed at its finalization or at calling #close, otherwise +false+.
9711 */
9712
9713static VALUE
9714rb_io_autoclose_p(VALUE io)
9715{
9716 rb_io_t *fptr = RFILE(io)->fptr;
9717 rb_io_check_closed(fptr);
9718 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9719}
9720
9721/*
9722 * call-seq:
9723 * io.autoclose = bool -> true or false
9724 *
9725 * Sets auto-close flag.
9726 *
9727 * f = File.open(File::NULL)
9728 * IO.for_fd(f.fileno).close
9729 * f.gets # raises Errno::EBADF
9730 *
9731 * f = File.open(File::NULL)
9732 * g = IO.for_fd(f.fileno)
9733 * g.autoclose = false
9734 * g.close
9735 * f.gets # won't cause Errno::EBADF
9736 */
9737
9738static VALUE
9739rb_io_set_autoclose(VALUE io, VALUE autoclose)
9740{
9741 rb_io_t *fptr;
9742 GetOpenFile(io, fptr);
9743 if (!RTEST(autoclose))
9744 fptr->mode |= FMODE_EXTERNAL;
9745 else
9746 fptr->mode &= ~FMODE_EXTERNAL;
9747 return autoclose;
9748}
9749
9750static VALUE
9751io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9752{
9753 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9754
9755 if (!RB_TEST(result)) {
9756 return Qnil;
9757 }
9758
9759 int mask = RB_NUM2INT(result);
9760
9761 if (mask & event) {
9762 if (return_io)
9763 return io;
9764 else
9765 return result;
9766 }
9767 else {
9768 return Qfalse;
9769 }
9770}
9771
9772/*
9773 * call-seq:
9774 * io.wait_readable -> truthy or falsy
9775 * io.wait_readable(timeout) -> truthy or falsy
9776 *
9777 * Waits until IO is readable and returns a truthy value, or a falsy
9778 * value when times out. Returns a truthy value immediately when
9779 * buffered data is available.
9780 */
9781
9782static VALUE
9783io_wait_readable(int argc, VALUE *argv, VALUE io)
9784{
9785 rb_io_t *fptr;
9786
9787 RB_IO_POINTER(io, fptr);
9788 rb_io_check_readable(fptr);
9789
9790 if (rb_io_read_pending(fptr)) return Qtrue;
9791
9792 rb_check_arity(argc, 0, 1);
9793 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9794
9795 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9796}
9797
9798/*
9799 * call-seq:
9800 * io.wait_writable -> truthy or falsy
9801 * io.wait_writable(timeout) -> truthy or falsy
9802 *
9803 * Waits until IO is writable and returns a truthy value or a falsy
9804 * value when times out.
9805 */
9806static VALUE
9807io_wait_writable(int argc, VALUE *argv, VALUE io)
9808{
9809 rb_io_t *fptr;
9810
9811 RB_IO_POINTER(io, fptr);
9812 rb_io_check_writable(fptr);
9813
9814 rb_check_arity(argc, 0, 1);
9815 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9816
9817 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9818}
9819
9820/*
9821 * call-seq:
9822 * io.wait_priority -> truthy or falsy
9823 * io.wait_priority(timeout) -> truthy or falsy
9824 *
9825 * Waits until IO is priority and returns a truthy value or a falsy
9826 * value when times out. Priority data is sent and received using
9827 * the Socket::MSG_OOB flag and is typically limited to streams.
9828 */
9829static VALUE
9830io_wait_priority(int argc, VALUE *argv, VALUE io)
9831{
9832 rb_io_t *fptr = NULL;
9833
9834 RB_IO_POINTER(io, fptr);
9835 rb_io_check_readable(fptr);
9836
9837 if (rb_io_read_pending(fptr)) return Qtrue;
9838
9839 rb_check_arity(argc, 0, 1);
9840 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9841
9842 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9843}
9844
9845static int
9846wait_mode_sym(VALUE mode)
9847{
9848 if (mode == ID2SYM(rb_intern("r"))) {
9849 return RB_WAITFD_IN;
9850 }
9851 if (mode == ID2SYM(rb_intern("read"))) {
9852 return RB_WAITFD_IN;
9853 }
9854 if (mode == ID2SYM(rb_intern("readable"))) {
9855 return RB_WAITFD_IN;
9856 }
9857 if (mode == ID2SYM(rb_intern("w"))) {
9858 return RB_WAITFD_OUT;
9859 }
9860 if (mode == ID2SYM(rb_intern("write"))) {
9861 return RB_WAITFD_OUT;
9862 }
9863 if (mode == ID2SYM(rb_intern("writable"))) {
9864 return RB_WAITFD_OUT;
9865 }
9866 if (mode == ID2SYM(rb_intern("rw"))) {
9867 return RB_WAITFD_IN|RB_WAITFD_OUT;
9868 }
9869 if (mode == ID2SYM(rb_intern("read_write"))) {
9870 return RB_WAITFD_IN|RB_WAITFD_OUT;
9871 }
9872 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9873 return RB_WAITFD_IN|RB_WAITFD_OUT;
9874 }
9875
9876 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9877}
9878
9879static inline enum rb_io_event
9880io_event_from_value(VALUE value)
9881{
9882 int events = RB_NUM2INT(value);
9883
9884 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9885
9886 return events;
9887}
9888
9889/*
9890 * call-seq:
9891 * io.wait(events, timeout) -> event mask, false or nil
9892 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9893 *
9894 * Waits until the IO becomes ready for the specified events and returns the
9895 * subset of events that become ready, or a falsy value when times out.
9896 *
9897 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9898 * +IO::PRIORITY+.
9899 *
9900 * Returns an event mask (truthy value) immediately when buffered data is available.
9901 *
9902 * Optional parameter +mode+ is one of +:read+, +:write+, or
9903 * +:read_write+.
9904 */
9905
9906static VALUE
9907io_wait(int argc, VALUE *argv, VALUE io)
9908{
9909 VALUE timeout = Qundef;
9910 enum rb_io_event events = 0;
9911 int return_io = 0;
9912
9913 // The documented signature for this method is actually incorrect.
9914 // A single timeout is allowed in any position, and multiple symbols can be given.
9915 // Whether this is intentional or not, I don't know, and as such I consider this to
9916 // be a legacy/slow path.
9917 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9918 // We'd prefer to return the actual mask, but this form would return the io itself:
9919 return_io = 1;
9920
9921 // Slow/messy path:
9922 for (int i = 0; i < argc; i += 1) {
9923 if (RB_SYMBOL_P(argv[i])) {
9924 events |= wait_mode_sym(argv[i]);
9925 }
9926 else if (UNDEF_P(timeout)) {
9927 rb_time_interval(timeout = argv[i]);
9928 }
9929 else {
9930 rb_raise(rb_eArgError, "timeout given more than once");
9931 }
9932 }
9933
9934 if (UNDEF_P(timeout)) timeout = Qnil;
9935
9936 if (events == 0) {
9937 events = RUBY_IO_READABLE;
9938 }
9939 }
9940 else /* argc == 2 and neither are symbols */ {
9941 // This is the fast path:
9942 events = io_event_from_value(argv[0]);
9943 timeout = argv[1];
9944 }
9945
9946 if (events & RUBY_IO_READABLE) {
9947 rb_io_t *fptr = NULL;
9948 RB_IO_POINTER(io, fptr);
9949
9950 if (rb_io_read_pending(fptr)) {
9951 // This was the original behaviour:
9952 if (return_io) return Qtrue;
9953 // New behaviour always returns an event mask:
9954 else return RB_INT2NUM(RUBY_IO_READABLE);
9955 }
9956 }
9957
9958 return io_wait_event(io, events, timeout, return_io);
9959}
9960
9961static void
9962argf_mark(void *ptr)
9963{
9964 struct argf *p = ptr;
9965 rb_gc_mark(p->filename);
9966 rb_gc_mark(p->current_file);
9967 rb_gc_mark(p->argv);
9968 rb_gc_mark(p->inplace);
9969 rb_gc_mark(p->encs.ecopts);
9970}
9971
9972static size_t
9973argf_memsize(const void *ptr)
9974{
9975 const struct argf *p = ptr;
9976 size_t size = sizeof(*p);
9977 return size;
9978}
9979
9980static const rb_data_type_t argf_type = {
9981 "ARGF",
9982 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9983 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9984};
9985
9986static inline void
9987argf_init(struct argf *p, VALUE v)
9988{
9989 p->filename = Qnil;
9990 p->current_file = Qnil;
9991 p->lineno = 0;
9992 p->argv = v;
9993}
9994
9995static VALUE
9996argf_alloc(VALUE klass)
9997{
9998 struct argf *p;
9999 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10000
10001 argf_init(p, Qnil);
10002 return argf;
10003}
10004
10005#undef rb_argv
10006
10007/* :nodoc: */
10008static VALUE
10009argf_initialize(VALUE argf, VALUE argv)
10010{
10011 memset(&ARGF, 0, sizeof(ARGF));
10012 argf_init(&ARGF, argv);
10013
10014 return argf;
10015}
10016
10017/* :nodoc: */
10018static VALUE
10019argf_initialize_copy(VALUE argf, VALUE orig)
10020{
10021 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10022 ARGF = argf_of(orig);
10023 ARGF.argv = rb_obj_dup(ARGF.argv);
10024 return argf;
10025}
10026
10027/*
10028 * call-seq:
10029 * ARGF.lineno = integer -> integer
10030 *
10031 * Sets the line number of ARGF as a whole to the given Integer.
10032 *
10033 * ARGF sets the line number automatically as you read data, so normally
10034 * you will not need to set it explicitly. To access the current line number
10035 * use ARGF.lineno.
10036 *
10037 * For example:
10038 *
10039 * ARGF.lineno #=> 0
10040 * ARGF.readline #=> "This is line 1\n"
10041 * ARGF.lineno #=> 1
10042 * ARGF.lineno = 0 #=> 0
10043 * ARGF.lineno #=> 0
10044 */
10045static VALUE
10046argf_set_lineno(VALUE argf, VALUE val)
10047{
10048 ARGF.lineno = NUM2INT(val);
10049 ARGF.last_lineno = ARGF.lineno;
10050 return val;
10051}
10052
10053/*
10054 * call-seq:
10055 * ARGF.lineno -> integer
10056 *
10057 * Returns the current line number of ARGF as a whole. This value
10058 * can be set manually with ARGF.lineno=.
10059 *
10060 * For example:
10061 *
10062 * ARGF.lineno #=> 0
10063 * ARGF.readline #=> "This is line 1\n"
10064 * ARGF.lineno #=> 1
10065 */
10066static VALUE
10067argf_lineno(VALUE argf)
10068{
10069 return INT2FIX(ARGF.lineno);
10070}
10071
10072static VALUE
10073argf_forward(int argc, VALUE *argv, VALUE argf)
10074{
10075 return forward_current(rb_frame_this_func(), argc, argv);
10076}
10077
10078#define next_argv() argf_next_argv(argf)
10079#define ARGF_GENERIC_INPUT_P() \
10080 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10081#define ARGF_FORWARD(argc, argv) do {\
10082 if (ARGF_GENERIC_INPUT_P())\
10083 return argf_forward((argc), (argv), argf);\
10084} while (0)
10085#define NEXT_ARGF_FORWARD(argc, argv) do {\
10086 if (!next_argv()) return Qnil;\
10087 ARGF_FORWARD((argc), (argv));\
10088} while (0)
10089
10090static void
10091argf_close(VALUE argf)
10092{
10093 VALUE file = ARGF.current_file;
10094 if (file == rb_stdin) return;
10095 if (RB_TYPE_P(file, T_FILE)) {
10096 rb_io_set_write_io(file, Qnil);
10097 }
10098 io_close(file);
10099 ARGF.init_p = -1;
10100}
10101
10102static int
10103argf_next_argv(VALUE argf)
10104{
10105 char *fn;
10106 rb_io_t *fptr;
10107 int stdout_binmode = 0;
10108 int fmode;
10109
10110 VALUE r_stdout = rb_ractor_stdout();
10111
10112 if (RB_TYPE_P(r_stdout, T_FILE)) {
10113 GetOpenFile(r_stdout, fptr);
10114 if (fptr->mode & FMODE_BINMODE)
10115 stdout_binmode = 1;
10116 }
10117
10118 if (ARGF.init_p == 0) {
10119 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10120 ARGF.next_p = 1;
10121 }
10122 else {
10123 ARGF.next_p = -1;
10124 }
10125 ARGF.init_p = 1;
10126 }
10127 else {
10128 if (NIL_P(ARGF.argv)) {
10129 ARGF.next_p = -1;
10130 }
10131 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10132 ARGF.next_p = 1;
10133 }
10134 }
10135
10136 if (ARGF.next_p == 1) {
10137 if (ARGF.init_p == 1) argf_close(argf);
10138 retry:
10139 if (RARRAY_LEN(ARGF.argv) > 0) {
10140 VALUE filename = rb_ary_shift(ARGF.argv);
10141 FilePathValue(filename);
10142 ARGF.filename = filename;
10143 filename = rb_str_encode_ospath(filename);
10144 fn = StringValueCStr(filename);
10145 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10146 ARGF.current_file = rb_stdin;
10147 if (ARGF.inplace) {
10148 rb_warn("Can't do inplace edit for stdio; skipping");
10149 goto retry;
10150 }
10151 }
10152 else {
10153 VALUE write_io = Qnil;
10154 int fr = rb_sysopen(filename, O_RDONLY, 0);
10155
10156 if (ARGF.inplace) {
10157 struct stat st;
10158#ifndef NO_SAFE_RENAME
10159 struct stat st2;
10160#endif
10161 VALUE str;
10162 int fw;
10163
10164 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10165 rb_io_close(r_stdout);
10166 }
10167 fstat(fr, &st);
10168 str = filename;
10169 if (!NIL_P(ARGF.inplace)) {
10170 VALUE suffix = ARGF.inplace;
10171 str = rb_str_dup(str);
10172 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10173 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10174 rb_enc_get(suffix), 0, Qnil))) {
10175 rb_str_append(str, suffix);
10176 }
10177#ifdef NO_SAFE_RENAME
10178 (void)close(fr);
10179 (void)unlink(RSTRING_PTR(str));
10180 if (rename(fn, RSTRING_PTR(str)) < 0) {
10181 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10182 filename, str, strerror(errno));
10183 goto retry;
10184 }
10185 fr = rb_sysopen(str, O_RDONLY, 0);
10186#else
10187 if (rename(fn, RSTRING_PTR(str)) < 0) {
10188 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10189 filename, str, strerror(errno));
10190 close(fr);
10191 goto retry;
10192 }
10193#endif
10194 }
10195 else {
10196#ifdef NO_SAFE_RENAME
10197 rb_fatal("Can't do inplace edit without backup");
10198#else
10199 if (unlink(fn) < 0) {
10200 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10201 filename, strerror(errno));
10202 close(fr);
10203 goto retry;
10204 }
10205#endif
10206 }
10207 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10208#ifndef NO_SAFE_RENAME
10209 fstat(fw, &st2);
10210#ifdef HAVE_FCHMOD
10211 fchmod(fw, st.st_mode);
10212#else
10213 chmod(fn, st.st_mode);
10214#endif
10215 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10216 int err;
10217#ifdef HAVE_FCHOWN
10218 err = fchown(fw, st.st_uid, st.st_gid);
10219#else
10220 err = chown(fn, st.st_uid, st.st_gid);
10221#endif
10222 if (err && getuid() == 0 && st2.st_uid == 0) {
10223 const char *wkfn = RSTRING_PTR(filename);
10224 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10225 filename, str, strerror(errno));
10226 (void)close(fr);
10227 (void)close(fw);
10228 (void)unlink(wkfn);
10229 goto retry;
10230 }
10231 }
10232#endif
10233 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10234 rb_ractor_stdout_set(write_io);
10235 if (stdout_binmode) rb_io_binmode(rb_stdout);
10236 }
10237 fmode = FMODE_READABLE;
10238 if (!ARGF.binmode) {
10239 fmode |= DEFAULT_TEXTMODE;
10240 }
10241 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10242 if (!NIL_P(write_io)) {
10243 rb_io_set_write_io(ARGF.current_file, write_io);
10244 }
10245 RB_GC_GUARD(filename);
10246 }
10247 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10248 GetOpenFile(ARGF.current_file, fptr);
10249 if (ARGF.encs.enc) {
10250 fptr->encs = ARGF.encs;
10251 clear_codeconv(fptr);
10252 }
10253 else {
10254 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10255 if (!ARGF.binmode) {
10256 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
10257#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10258 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10259#endif
10260 }
10261 }
10262 ARGF.next_p = 0;
10263 }
10264 else {
10265 ARGF.next_p = 1;
10266 return FALSE;
10267 }
10268 }
10269 else if (ARGF.next_p == -1) {
10270 ARGF.current_file = rb_stdin;
10271 ARGF.filename = rb_str_new2("-");
10272 if (ARGF.inplace) {
10273 rb_warn("Can't do inplace edit for stdio");
10274 rb_ractor_stdout_set(orig_stdout);
10275 }
10276 }
10277 if (ARGF.init_p == -1) ARGF.init_p = 1;
10278 return TRUE;
10279}
10280
10281static VALUE
10282argf_getline(int argc, VALUE *argv, VALUE argf)
10283{
10284 VALUE line;
10285 long lineno = ARGF.lineno;
10286
10287 retry:
10288 if (!next_argv()) return Qnil;
10289 if (ARGF_GENERIC_INPUT_P()) {
10290 line = forward_current(idGets, argc, argv);
10291 }
10292 else {
10293 if (argc == 0 && rb_rs == rb_default_rs) {
10294 line = rb_io_gets(ARGF.current_file);
10295 }
10296 else {
10297 line = rb_io_getline(argc, argv, ARGF.current_file);
10298 }
10299 if (NIL_P(line) && ARGF.next_p != -1) {
10300 argf_close(argf);
10301 ARGF.next_p = 1;
10302 goto retry;
10303 }
10304 }
10305 if (!NIL_P(line)) {
10306 ARGF.lineno = ++lineno;
10307 ARGF.last_lineno = ARGF.lineno;
10308 }
10309 return line;
10310}
10311
10312static VALUE
10313argf_lineno_getter(ID id, VALUE *var)
10314{
10315 VALUE argf = *var;
10316 return INT2FIX(ARGF.last_lineno);
10317}
10318
10319static void
10320argf_lineno_setter(VALUE val, ID id, VALUE *var)
10321{
10322 VALUE argf = *var;
10323 int n = NUM2INT(val);
10324 ARGF.last_lineno = ARGF.lineno = n;
10325}
10326
10327void
10328rb_reset_argf_lineno(long n)
10329{
10330 ARGF.last_lineno = ARGF.lineno = n;
10331}
10332
10333static VALUE argf_gets(int, VALUE *, VALUE);
10334
10335/*
10336 * call-seq:
10337 * gets(sep=$/ [, getline_args]) -> string or nil
10338 * gets(limit [, getline_args]) -> string or nil
10339 * gets(sep, limit [, getline_args]) -> string or nil
10340 *
10341 * Returns (and assigns to <code>$_</code>) the next line from the list
10342 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10343 * no files are present on the command line. Returns +nil+ at end of
10344 * file. The optional argument specifies the record separator. The
10345 * separator is included with the contents of each record. A separator
10346 * of +nil+ reads the entire contents, and a zero-length separator
10347 * reads the input one paragraph at a time, where paragraphs are
10348 * divided by two consecutive newlines. If the first argument is an
10349 * integer, or optional second argument is given, the returning string
10350 * would not be longer than the given value in bytes. If multiple
10351 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10352 * the contents one file at a time.
10353 *
10354 * ARGV << "testfile"
10355 * print while gets
10356 *
10357 * <em>produces:</em>
10358 *
10359 * This is line one
10360 * This is line two
10361 * This is line three
10362 * And so on...
10363 *
10364 * The style of programming using <code>$_</code> as an implicit
10365 * parameter is gradually losing favor in the Ruby community.
10366 */
10367
10368static VALUE
10369rb_f_gets(int argc, VALUE *argv, VALUE recv)
10370{
10371 if (recv == argf) {
10372 return argf_gets(argc, argv, argf);
10373 }
10374 return forward(argf, idGets, argc, argv);
10375}
10376
10377/*
10378 * call-seq:
10379 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10380 * ARGF.gets(limit [, getline_args]) -> string or nil
10381 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10382 *
10383 * Returns the next line from the current file in ARGF.
10384 *
10385 * By default lines are assumed to be separated by <code>$/</code>;
10386 * to use a different character as a separator, supply it as a String
10387 * for the _sep_ argument.
10388 *
10389 * The optional _limit_ argument specifies how many characters of each line
10390 * to return. By default all characters are returned.
10391 *
10392 * See IO.readlines for details about getline_args.
10393 *
10394 */
10395static VALUE
10396argf_gets(int argc, VALUE *argv, VALUE argf)
10397{
10398 VALUE line;
10399
10400 line = argf_getline(argc, argv, argf);
10401 rb_lastline_set(line);
10402
10403 return line;
10404}
10405
10406 VALUE
10407rb_gets(void)
10408{
10409 VALUE line;
10410
10411 if (rb_rs != rb_default_rs) {
10412 return rb_f_gets(0, 0, argf);
10413 }
10414
10415 retry:
10416 if (!next_argv()) return Qnil;
10417 line = rb_io_gets(ARGF.current_file);
10418 if (NIL_P(line) && ARGF.next_p != -1) {
10419 rb_io_close(ARGF.current_file);
10420 ARGF.next_p = 1;
10421 goto retry;
10422 }
10423 rb_lastline_set(line);
10424 if (!NIL_P(line)) {
10425 ARGF.lineno++;
10426 ARGF.last_lineno = ARGF.lineno;
10427 }
10428
10429 return line;
10430}
10431
10432static VALUE argf_readline(int, VALUE *, VALUE);
10433
10434/*
10435 * call-seq:
10436 * readline(sep = $/, chomp: false) -> string
10437 * readline(limit, chomp: false) -> string
10438 * readline(sep, limit, chomp: false) -> string
10439 *
10440 * Equivalent to method Kernel#gets, except that it raises an exception
10441 * if called at end-of-stream:
10442 *
10443 * $ cat t.txt | ruby -e "p readlines; readline"
10444 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10445 * in `readline': end of file reached (EOFError)
10446 *
10447 * Optional keyword argument +chomp+ specifies whether line separators
10448 * are to be omitted.
10449 */
10450
10451static VALUE
10452rb_f_readline(int argc, VALUE *argv, VALUE recv)
10453{
10454 if (recv == argf) {
10455 return argf_readline(argc, argv, argf);
10456 }
10457 return forward(argf, rb_intern("readline"), argc, argv);
10458}
10459
10460
10461/*
10462 * call-seq:
10463 * ARGF.readline(sep=$/) -> string
10464 * ARGF.readline(limit) -> string
10465 * ARGF.readline(sep, limit) -> string
10466 *
10467 * Returns the next line from the current file in ARGF.
10468 *
10469 * By default lines are assumed to be separated by <code>$/</code>;
10470 * to use a different character as a separator, supply it as a String
10471 * for the _sep_ argument.
10472 *
10473 * The optional _limit_ argument specifies how many characters of each line
10474 * to return. By default all characters are returned.
10475 *
10476 * An EOFError is raised at the end of the file.
10477 */
10478static VALUE
10479argf_readline(int argc, VALUE *argv, VALUE argf)
10480{
10481 VALUE line;
10482
10483 if (!next_argv()) rb_eof_error();
10484 ARGF_FORWARD(argc, argv);
10485 line = argf_gets(argc, argv, argf);
10486 if (NIL_P(line)) {
10487 rb_eof_error();
10488 }
10489
10490 return line;
10491}
10492
10493static VALUE argf_readlines(int, VALUE *, VALUE);
10494
10495/*
10496 * call-seq:
10497 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10498 * readlines(limit, chomp: false, **enc_opts) -> array
10499 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10500 *
10501 * Returns an array containing the lines returned by calling
10502 * Kernel#gets until the end-of-stream is reached;
10503 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10504 *
10505 * With only string argument +sep+ given,
10506 * returns the remaining lines as determined by line separator +sep+,
10507 * or +nil+ if none;
10508 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10509 *
10510 * # Default separator.
10511 * $ cat t.txt | ruby -e "p readlines"
10512 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10513 *
10514 * # Specified separator.
10515 * $ cat t.txt | ruby -e "p readlines 'li'"
10516 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10517 *
10518 * # Get-all separator.
10519 * $ cat t.txt | ruby -e "p readlines nil"
10520 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10521 *
10522 * # Get-paragraph separator.
10523 * $ cat t.txt | ruby -e "p readlines ''"
10524 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10525 *
10526 * With only integer argument +limit+ given,
10527 * limits the number of bytes in the line;
10528 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10529 *
10530 * $cat t.txt | ruby -e "p readlines 10"
10531 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10532 *
10533 * $cat t.txt | ruby -e "p readlines 11"
10534 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10535 *
10536 * $cat t.txt | ruby -e "p readlines 12"
10537 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10538 *
10539 * With arguments +sep+ and +limit+ given,
10540 * combines the two behaviors
10541 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10542 *
10543 * Optional keyword argument +chomp+ specifies whether line separators
10544 * are to be omitted:
10545 *
10546 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10547 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10548 *
10549 * Optional keyword arguments +enc_opts+ specify encoding options;
10550 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10551 *
10552 */
10553
10554static VALUE
10555rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10556{
10557 if (recv == argf) {
10558 return argf_readlines(argc, argv, argf);
10559 }
10560 return forward(argf, rb_intern("readlines"), argc, argv);
10561}
10562
10563/*
10564 * call-seq:
10565 * ARGF.readlines(sep = $/, chomp: false) -> array
10566 * ARGF.readlines(limit, chomp: false) -> array
10567 * ARGF.readlines(sep, limit, chomp: false) -> array
10568 *
10569 * ARGF.to_a(sep = $/, chomp: false) -> array
10570 * ARGF.to_a(limit, chomp: false) -> array
10571 * ARGF.to_a(sep, limit, chomp: false) -> array
10572 *
10573 * Reads each file in ARGF in its entirety, returning an Array containing
10574 * lines from the files. Lines are assumed to be separated by _sep_.
10575 *
10576 * lines = ARGF.readlines
10577 * lines[0] #=> "This is line one\n"
10578 *
10579 * See +IO.readlines+ for a full description of all options.
10580 */
10581static VALUE
10582argf_readlines(int argc, VALUE *argv, VALUE argf)
10583{
10584 long lineno = ARGF.lineno;
10585 VALUE lines, ary;
10586
10587 ary = rb_ary_new();
10588 while (next_argv()) {
10589 if (ARGF_GENERIC_INPUT_P()) {
10590 lines = forward_current(rb_intern("readlines"), argc, argv);
10591 }
10592 else {
10593 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10594 argf_close(argf);
10595 }
10596 ARGF.next_p = 1;
10597 rb_ary_concat(ary, lines);
10598 ARGF.lineno = lineno + RARRAY_LEN(ary);
10599 ARGF.last_lineno = ARGF.lineno;
10600 }
10601 ARGF.init_p = 0;
10602 return ary;
10603}
10604
10605/*
10606 * call-seq:
10607 * `command` -> string
10608 *
10609 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10610 * sets global variable <tt>$?</tt> to the process status.
10611 *
10612 * This method has potential security vulnerabilities if called with untrusted input;
10613 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10614 *
10615 * Examples:
10616 *
10617 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10618 * $ `echo oops && exit 99` # => "oops\n"
10619 * $ $? # => #<Process::Status: pid 17088 exit 99>
10620 * $ $?.status # => 99>
10621 *
10622 * The built-in syntax <tt>%x{...}</tt> uses this method.
10623 *
10624 */
10625
10626static VALUE
10627rb_f_backquote(VALUE obj, VALUE str)
10628{
10629 VALUE port;
10630 VALUE result;
10631 rb_io_t *fptr;
10632
10633 StringValue(str);
10634 rb_last_status_clear();
10635 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10636 if (NIL_P(port)) return rb_str_new(0,0);
10637
10638 GetOpenFile(port, fptr);
10639 result = read_all(fptr, remain_size(fptr), Qnil);
10640 rb_io_close(port);
10641 rb_io_fptr_cleanup_all(fptr);
10642 RB_GC_GUARD(port);
10643
10644 return result;
10645}
10646
10647#ifdef HAVE_SYS_SELECT_H
10648#include <sys/select.h>
10649#endif
10650
10651static VALUE
10652select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10653{
10654 VALUE res, list;
10655 rb_fdset_t *rp, *wp, *ep;
10656 rb_io_t *fptr;
10657 long i;
10658 int max = 0, n;
10659 int pending = 0;
10660 struct timeval timerec;
10661
10662 if (!NIL_P(read)) {
10663 Check_Type(read, T_ARRAY);
10664 for (i=0; i<RARRAY_LEN(read); i++) {
10665 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10666 rb_fd_set(fptr->fd, &fds[0]);
10667 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10668 pending++;
10669 rb_fd_set(fptr->fd, &fds[3]);
10670 }
10671 if (max < fptr->fd) max = fptr->fd;
10672 }
10673 if (pending) { /* no blocking if there's buffered data */
10674 timerec.tv_sec = timerec.tv_usec = 0;
10675 tp = &timerec;
10676 }
10677 rp = &fds[0];
10678 }
10679 else
10680 rp = 0;
10681
10682 if (!NIL_P(write)) {
10683 Check_Type(write, T_ARRAY);
10684 for (i=0; i<RARRAY_LEN(write); i++) {
10685 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10686 GetOpenFile(write_io, fptr);
10687 rb_fd_set(fptr->fd, &fds[1]);
10688 if (max < fptr->fd) max = fptr->fd;
10689 }
10690 wp = &fds[1];
10691 }
10692 else
10693 wp = 0;
10694
10695 if (!NIL_P(except)) {
10696 Check_Type(except, T_ARRAY);
10697 for (i=0; i<RARRAY_LEN(except); i++) {
10698 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10699 VALUE write_io = GetWriteIO(io);
10700 GetOpenFile(io, fptr);
10701 rb_fd_set(fptr->fd, &fds[2]);
10702 if (max < fptr->fd) max = fptr->fd;
10703 if (io != write_io) {
10704 GetOpenFile(write_io, fptr);
10705 rb_fd_set(fptr->fd, &fds[2]);
10706 if (max < fptr->fd) max = fptr->fd;
10707 }
10708 }
10709 ep = &fds[2];
10710 }
10711 else {
10712 ep = 0;
10713 }
10714
10715 max++;
10716
10717 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10718 if (n < 0) {
10719 rb_sys_fail(0);
10720 }
10721 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10722
10723 res = rb_ary_new2(3);
10724 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10725 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10726 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10727
10728 if (rp) {
10729 list = RARRAY_AREF(res, 0);
10730 for (i=0; i< RARRAY_LEN(read); i++) {
10731 VALUE obj = rb_ary_entry(read, i);
10732 VALUE io = rb_io_get_io(obj);
10733 GetOpenFile(io, fptr);
10734 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10735 rb_fd_isset(fptr->fd, &fds[3])) {
10736 rb_ary_push(list, obj);
10737 }
10738 }
10739 }
10740
10741 if (wp) {
10742 list = RARRAY_AREF(res, 1);
10743 for (i=0; i< RARRAY_LEN(write); i++) {
10744 VALUE obj = rb_ary_entry(write, i);
10745 VALUE io = rb_io_get_io(obj);
10746 VALUE write_io = GetWriteIO(io);
10747 GetOpenFile(write_io, fptr);
10748 if (rb_fd_isset(fptr->fd, &fds[1])) {
10749 rb_ary_push(list, obj);
10750 }
10751 }
10752 }
10753
10754 if (ep) {
10755 list = RARRAY_AREF(res, 2);
10756 for (i=0; i< RARRAY_LEN(except); i++) {
10757 VALUE obj = rb_ary_entry(except, i);
10758 VALUE io = rb_io_get_io(obj);
10759 VALUE write_io = GetWriteIO(io);
10760 GetOpenFile(io, fptr);
10761 if (rb_fd_isset(fptr->fd, &fds[2])) {
10762 rb_ary_push(list, obj);
10763 }
10764 else if (io != write_io) {
10765 GetOpenFile(write_io, fptr);
10766 if (rb_fd_isset(fptr->fd, &fds[2])) {
10767 rb_ary_push(list, obj);
10768 }
10769 }
10770 }
10771 }
10772
10773 return res; /* returns an empty array on interrupt */
10774}
10775
10776 struct select_args {
10777 VALUE read, write, except;
10778 struct timeval *timeout;
10779 rb_fdset_t fdsets[4];
10780};
10781
10782static VALUE
10783select_call(VALUE arg)
10784{
10785 struct select_args *p = (struct select_args *)arg;
10786
10787 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10788}
10789
10790static VALUE
10791select_end(VALUE arg)
10792{
10793 struct select_args *p = (struct select_args *)arg;
10794 int i;
10795
10796 for (i = 0; i < numberof(p->fdsets); ++i)
10797 rb_fd_term(&p->fdsets[i]);
10798 return Qnil;
10799}
10800
10801static VALUE sym_normal, sym_sequential, sym_random,
10802 sym_willneed, sym_dontneed, sym_noreuse;
10803
10804#ifdef HAVE_POSIX_FADVISE
10805struct io_advise_struct {
10806 int fd;
10807 int advice;
10808 rb_off_t offset;
10809 rb_off_t len;
10810};
10811
10812static VALUE
10813io_advise_internal(void *arg)
10814{
10815 struct io_advise_struct *ptr = arg;
10816 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10817}
10818
10819static VALUE
10820io_advise_sym_to_const(VALUE sym)
10821{
10822#ifdef POSIX_FADV_NORMAL
10823 if (sym == sym_normal)
10824 return INT2NUM(POSIX_FADV_NORMAL);
10825#endif
10826
10827#ifdef POSIX_FADV_RANDOM
10828 if (sym == sym_random)
10829 return INT2NUM(POSIX_FADV_RANDOM);
10830#endif
10831
10832#ifdef POSIX_FADV_SEQUENTIAL
10833 if (sym == sym_sequential)
10834 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10835#endif
10836
10837#ifdef POSIX_FADV_WILLNEED
10838 if (sym == sym_willneed)
10839 return INT2NUM(POSIX_FADV_WILLNEED);
10840#endif
10841
10842#ifdef POSIX_FADV_DONTNEED
10843 if (sym == sym_dontneed)
10844 return INT2NUM(POSIX_FADV_DONTNEED);
10845#endif
10846
10847#ifdef POSIX_FADV_NOREUSE
10848 if (sym == sym_noreuse)
10849 return INT2NUM(POSIX_FADV_NOREUSE);
10850#endif
10851
10852 return Qnil;
10853}
10854
10855static VALUE
10856do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10857{
10858 int rv;
10859 struct io_advise_struct ias;
10860 VALUE num_adv;
10861
10862 num_adv = io_advise_sym_to_const(advice);
10863
10864 /*
10865 * The platform doesn't support this hint. We don't raise exception, instead
10866 * silently ignore it. Because IO::advise is only hint.
10867 */
10868 if (NIL_P(num_adv))
10869 return Qnil;
10870
10871 ias.fd = fptr->fd;
10872 ias.advice = NUM2INT(num_adv);
10873 ias.offset = offset;
10874 ias.len = len;
10875
10876 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10877 if (rv && rv != ENOSYS) {
10878 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10879 it returns the error code. */
10880 VALUE message = rb_sprintf("%"PRIsVALUE" "
10881 "(%"PRI_OFFT_PREFIX"d, "
10882 "%"PRI_OFFT_PREFIX"d, "
10883 "%"PRIsVALUE")",
10884 fptr->pathv, offset, len, advice);
10885 rb_syserr_fail_str(rv, message);
10886 }
10887
10888 return Qnil;
10889}
10890
10891#endif /* HAVE_POSIX_FADVISE */
10892
10893static void
10894advice_arg_check(VALUE advice)
10895{
10896 if (!SYMBOL_P(advice))
10897 rb_raise(rb_eTypeError, "advice must be a Symbol");
10898
10899 if (advice != sym_normal &&
10900 advice != sym_sequential &&
10901 advice != sym_random &&
10902 advice != sym_willneed &&
10903 advice != sym_dontneed &&
10904 advice != sym_noreuse) {
10905 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10906 }
10907}
10908
10909/*
10910 * call-seq:
10911 * advise(advice, offset = 0, len = 0) -> nil
10912 *
10913 * Invokes Posix system call
10914 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10915 * which announces an intention to access data from the current file
10916 * in a particular manner.
10917 *
10918 * The arguments and results are platform-dependent.
10919 *
10920 * The relevant data is specified by:
10921 *
10922 * - +offset+: The offset of the first byte of data.
10923 * - +len+: The number of bytes to be accessed;
10924 * if +len+ is zero, or is larger than the number of bytes remaining,
10925 * all remaining bytes will be accessed.
10926 *
10927 * Argument +advice+ is one of the following symbols:
10928 *
10929 * - +:normal+: The application has no advice to give
10930 * about its access pattern for the specified data.
10931 * If no advice is given for an open file, this is the default assumption.
10932 * - +:sequential+: The application expects to access the specified data sequentially
10933 * (with lower offsets read before higher ones).
10934 * - +:random+: The specified data will be accessed in random order.
10935 * - +:noreuse+: The specified data will be accessed only once.
10936 * - +:willneed+: The specified data will be accessed in the near future.
10937 * - +:dontneed+: The specified data will not be accessed in the near future.
10938 *
10939 * Not implemented on all platforms.
10940 *
10941 */
10942static VALUE
10943rb_io_advise(int argc, VALUE *argv, VALUE io)
10944{
10945 VALUE advice, offset, len;
10946 rb_off_t off, l;
10947 rb_io_t *fptr;
10948
10949 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10950 advice_arg_check(advice);
10951
10952 io = GetWriteIO(io);
10953 GetOpenFile(io, fptr);
10954
10955 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10956 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10957
10958#ifdef HAVE_POSIX_FADVISE
10959 return do_io_advise(fptr, advice, off, l);
10960#else
10961 ((void)off, (void)l); /* Ignore all hint */
10962 return Qnil;
10963#endif
10964}
10965
10966/*
10967 * call-seq:
10968 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10969 *
10970 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10971 * which monitors multiple file descriptors,
10972 * waiting until one or more of the file descriptors
10973 * becomes ready for some class of I/O operation.
10974 *
10975 * Not implemented on all platforms.
10976 *
10977 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10978 * is an array of IO objects.
10979 *
10980 * Argument +timeout+ is a numeric value (such as integer or float) timeout
10981 * interval in seconds.
10982 *
10983 * The method monitors the \IO objects given in all three arrays,
10984 * waiting for some to be ready;
10985 * returns a 3-element array whose elements are:
10986 *
10987 * - An array of the objects in +read_ios+ that are ready for reading.
10988 * - An array of the objects in +write_ios+ that are ready for writing.
10989 * - An array of the objects in +error_ios+ have pending exceptions.
10990 *
10991 * If no object becomes ready within the given +timeout+, +nil+ is returned.
10992 *
10993 * \IO.select peeks the buffer of \IO objects for testing readability.
10994 * If the \IO buffer is not empty, \IO.select immediately notifies
10995 * readability. This "peek" only happens for \IO objects. It does not
10996 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10997 *
10998 * The best way to use \IO.select is invoking it after non-blocking
10999 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11000 * raise an exception which is extended by IO::WaitReadable or
11001 * IO::WaitWritable. The modules notify how the caller should wait
11002 * with \IO.select. If IO::WaitReadable is raised, the caller should
11003 * wait for reading. If IO::WaitWritable is raised, the caller should
11004 * wait for writing.
11005 *
11006 * So, blocking read (#readpartial) can be emulated using
11007 * #read_nonblock and \IO.select as follows:
11008 *
11009 * begin
11010 * result = io_like.read_nonblock(maxlen)
11011 * rescue IO::WaitReadable
11012 * IO.select([io_like])
11013 * retry
11014 * rescue IO::WaitWritable
11015 * IO.select(nil, [io_like])
11016 * retry
11017 * end
11018 *
11019 * Especially, the combination of non-blocking methods and \IO.select is
11020 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11021 * has #to_io method to return underlying IO object. IO.select calls
11022 * #to_io to obtain the file descriptor to wait.
11023 *
11024 * This means that readability notified by \IO.select doesn't mean
11025 * readability from OpenSSL::SSL::SSLSocket object.
11026 *
11027 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11028 * some data. \IO.select doesn't see the buffer. So \IO.select can
11029 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11030 *
11031 * However, several more complicated situations exist.
11032 *
11033 * SSL is a protocol which is sequence of records.
11034 * The record consists of multiple bytes.
11035 * So, the remote side of SSL sends a partial record, IO.select
11036 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11037 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11038 *
11039 * Also, the remote side can request SSL renegotiation which forces
11040 * the local SSL engine to write some data.
11041 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11042 * system call and it can block.
11043 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11044 * IO::WaitWritable instead of blocking.
11045 * So, the caller should wait for ready for writability as above
11046 * example.
11047 *
11048 * The combination of non-blocking methods and \IO.select is also useful
11049 * for streams such as tty, pipe socket socket when multiple processes
11050 * read from a stream.
11051 *
11052 * Finally, Linux kernel developers don't guarantee that
11053 * readability of select(2) means readability of following read(2) even
11054 * for a single process;
11055 * see {select(2)}[https://linux.die.net/man/2/select]
11056 *
11057 * Invoking \IO.select before IO#readpartial works well as usual.
11058 * However it is not the best way to use \IO.select.
11059 *
11060 * The writability notified by select(2) doesn't show
11061 * how many bytes are writable.
11062 * IO#write method blocks until given whole string is written.
11063 * So, <tt>IO#write(two or more bytes)</tt> can block after
11064 * writability is notified by \IO.select. IO#write_nonblock is required
11065 * to avoid the blocking.
11066 *
11067 * Blocking write (#write) can be emulated using #write_nonblock and
11068 * IO.select as follows: IO::WaitReadable should also be rescued for
11069 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11070 *
11071 * while 0 < string.bytesize
11072 * begin
11073 * written = io_like.write_nonblock(string)
11074 * rescue IO::WaitReadable
11075 * IO.select([io_like])
11076 * retry
11077 * rescue IO::WaitWritable
11078 * IO.select(nil, [io_like])
11079 * retry
11080 * end
11081 * string = string.byteslice(written..-1)
11082 * end
11083 *
11084 * Example:
11085 *
11086 * rp, wp = IO.pipe
11087 * mesg = "ping "
11088 * 100.times {
11089 * # IO.select follows IO#read. Not the best way to use IO.select.
11090 * rs, ws, = IO.select([rp], [wp])
11091 * if r = rs[0]
11092 * ret = r.read(5)
11093 * print ret
11094 * case ret
11095 * when /ping/
11096 * mesg = "pong\n"
11097 * when /pong/
11098 * mesg = "ping "
11099 * end
11100 * end
11101 * if w = ws[0]
11102 * w.write(mesg)
11103 * end
11104 * }
11105 *
11106 * Output:
11107 *
11108 * ping pong
11109 * ping pong
11110 * ping pong
11111 * (snipped)
11112 * ping
11113 *
11114 */
11115
11116static VALUE
11117rb_f_select(int argc, VALUE *argv, VALUE obj)
11118{
11119 VALUE scheduler = rb_fiber_scheduler_current();
11120 if (scheduler != Qnil) {
11121 // It's optionally supported.
11122 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11123 if (!UNDEF_P(result)) return result;
11124 }
11125
11126 VALUE timeout;
11127 struct select_args args;
11128 struct timeval timerec;
11129 int i;
11130
11131 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11132 if (NIL_P(timeout)) {
11133 args.timeout = 0;
11134 }
11135 else {
11136 timerec = rb_time_interval(timeout);
11137 args.timeout = &timerec;
11138 }
11139
11140 for (i = 0; i < numberof(args.fdsets); ++i)
11141 rb_fd_init(&args.fdsets[i]);
11142
11143 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11144}
11145
11146#ifdef IOCTL_REQ_TYPE
11147 typedef IOCTL_REQ_TYPE ioctl_req_t;
11148#else
11149 typedef int ioctl_req_t;
11150# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11151#endif
11152
11153#ifdef HAVE_IOCTL
11154struct ioctl_arg {
11155 int fd;
11156 ioctl_req_t cmd;
11157 long narg;
11158};
11159
11160static VALUE
11161nogvl_ioctl(void *ptr)
11162{
11163 struct ioctl_arg *arg = ptr;
11164
11165 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11166}
11167
11168static int
11169do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11170{
11171 int retval;
11172 struct ioctl_arg arg;
11173
11174 arg.fd = io->fd;
11175 arg.cmd = cmd;
11176 arg.narg = narg;
11177
11178 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11179
11180 return retval;
11181}
11182#endif
11183
11184#define DEFAULT_IOCTL_NARG_LEN (256)
11185
11186#if defined(__linux__) && defined(_IOC_SIZE)
11187static long
11188linux_iocparm_len(ioctl_req_t cmd)
11189{
11190 long len;
11191
11192 if ((cmd & 0xFFFF0000) == 0) {
11193 /* legacy and unstructured ioctl number. */
11194 return DEFAULT_IOCTL_NARG_LEN;
11195 }
11196
11197 len = _IOC_SIZE(cmd);
11198
11199 /* paranoia check for silly drivers which don't keep ioctl convention */
11200 if (len < DEFAULT_IOCTL_NARG_LEN)
11201 len = DEFAULT_IOCTL_NARG_LEN;
11202
11203 return len;
11204}
11205#endif
11206
11207#ifdef HAVE_IOCTL
11208static long
11209ioctl_narg_len(ioctl_req_t cmd)
11210{
11211 long len;
11212
11213#ifdef IOCPARM_MASK
11214#ifndef IOCPARM_LEN
11215#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11216#endif
11217#endif
11218#ifdef IOCPARM_LEN
11219 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11220#elif defined(__linux__) && defined(_IOC_SIZE)
11221 len = linux_iocparm_len(cmd);
11222#else
11223 /* otherwise guess at what's safe */
11224 len = DEFAULT_IOCTL_NARG_LEN;
11225#endif
11226
11227 return len;
11228}
11229#endif
11230
11231#ifdef HAVE_FCNTL
11232#ifdef __linux__
11233typedef long fcntl_arg_t;
11234#else
11235/* posix */
11236typedef int fcntl_arg_t;
11237#endif
11238
11239static long
11240fcntl_narg_len(ioctl_req_t cmd)
11241{
11242 long len;
11243
11244 switch (cmd) {
11245#ifdef F_DUPFD
11246 case F_DUPFD:
11247 len = sizeof(fcntl_arg_t);
11248 break;
11249#endif
11250#ifdef F_DUP2FD /* bsd specific */
11251 case F_DUP2FD:
11252 len = sizeof(int);
11253 break;
11254#endif
11255#ifdef F_DUPFD_CLOEXEC /* linux specific */
11256 case F_DUPFD_CLOEXEC:
11257 len = sizeof(fcntl_arg_t);
11258 break;
11259#endif
11260#ifdef F_GETFD
11261 case F_GETFD:
11262 len = 1;
11263 break;
11264#endif
11265#ifdef F_SETFD
11266 case F_SETFD:
11267 len = sizeof(fcntl_arg_t);
11268 break;
11269#endif
11270#ifdef F_GETFL
11271 case F_GETFL:
11272 len = 1;
11273 break;
11274#endif
11275#ifdef F_SETFL
11276 case F_SETFL:
11277 len = sizeof(fcntl_arg_t);
11278 break;
11279#endif
11280#ifdef F_GETOWN
11281 case F_GETOWN:
11282 len = 1;
11283 break;
11284#endif
11285#ifdef F_SETOWN
11286 case F_SETOWN:
11287 len = sizeof(fcntl_arg_t);
11288 break;
11289#endif
11290#ifdef F_GETOWN_EX /* linux specific */
11291 case F_GETOWN_EX:
11292 len = sizeof(struct f_owner_ex);
11293 break;
11294#endif
11295#ifdef F_SETOWN_EX /* linux specific */
11296 case F_SETOWN_EX:
11297 len = sizeof(struct f_owner_ex);
11298 break;
11299#endif
11300#ifdef F_GETLK
11301 case F_GETLK:
11302 len = sizeof(struct flock);
11303 break;
11304#endif
11305#ifdef F_SETLK
11306 case F_SETLK:
11307 len = sizeof(struct flock);
11308 break;
11309#endif
11310#ifdef F_SETLKW
11311 case F_SETLKW:
11312 len = sizeof(struct flock);
11313 break;
11314#endif
11315#ifdef F_READAHEAD /* bsd specific */
11316 case F_READAHEAD:
11317 len = sizeof(int);
11318 break;
11319#endif
11320#ifdef F_RDAHEAD /* Darwin specific */
11321 case F_RDAHEAD:
11322 len = sizeof(int);
11323 break;
11324#endif
11325#ifdef F_GETSIG /* linux specific */
11326 case F_GETSIG:
11327 len = 1;
11328 break;
11329#endif
11330#ifdef F_SETSIG /* linux specific */
11331 case F_SETSIG:
11332 len = sizeof(fcntl_arg_t);
11333 break;
11334#endif
11335#ifdef F_GETLEASE /* linux specific */
11336 case F_GETLEASE:
11337 len = 1;
11338 break;
11339#endif
11340#ifdef F_SETLEASE /* linux specific */
11341 case F_SETLEASE:
11342 len = sizeof(fcntl_arg_t);
11343 break;
11344#endif
11345#ifdef F_NOTIFY /* linux specific */
11346 case F_NOTIFY:
11347 len = sizeof(fcntl_arg_t);
11348 break;
11349#endif
11350
11351 default:
11352 len = 256;
11353 break;
11354 }
11355
11356 return len;
11357}
11358#else /* HAVE_FCNTL */
11359static long
11360fcntl_narg_len(ioctl_req_t cmd)
11361{
11362 return 0;
11363}
11364#endif /* HAVE_FCNTL */
11365
11366#define NARG_SENTINEL 17
11367
11368static long
11369setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11370{
11371 long narg = 0;
11372 VALUE arg = *argp;
11373
11374 if (!RTEST(arg)) {
11375 narg = 0;
11376 }
11377 else if (FIXNUM_P(arg)) {
11378 narg = FIX2LONG(arg);
11379 }
11380 else if (arg == Qtrue) {
11381 narg = 1;
11382 }
11383 else {
11384 VALUE tmp = rb_check_string_type(arg);
11385
11386 if (NIL_P(tmp)) {
11387 narg = NUM2LONG(arg);
11388 }
11389 else {
11390 char *ptr;
11391 long len, slen;
11392
11393 *argp = arg = tmp;
11394 len = narg_len(cmd);
11395 rb_str_modify(arg);
11396
11397 slen = RSTRING_LEN(arg);
11398 /* expand for data + sentinel. */
11399 if (slen < len+1) {
11400 rb_str_resize(arg, len+1);
11401 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11402 slen = len+1;
11403 }
11404 /* a little sanity check here */
11405 ptr = RSTRING_PTR(arg);
11406 ptr[slen - 1] = NARG_SENTINEL;
11407 narg = (long)(SIGNED_VALUE)ptr;
11408 }
11409 }
11410
11411 return narg;
11412}
11413
11414static VALUE
11415finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11416{
11417 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11418 if (RB_TYPE_P(arg, T_STRING)) {
11419 char *ptr;
11420 long slen;
11421 RSTRING_GETMEM(arg, ptr, slen);
11422 if (ptr[slen-1] != NARG_SENTINEL)
11423 rb_raise(rb_eArgError, "return value overflowed string");
11424 ptr[slen-1] = '\0';
11425 }
11426
11427 return INT2NUM(retval);
11428}
11429
11430#ifdef HAVE_IOCTL
11431static VALUE
11432rb_ioctl(VALUE io, VALUE req, VALUE arg)
11433{
11434 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11435 rb_io_t *fptr;
11436 long narg;
11437 int retval;
11438
11439 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11440 GetOpenFile(io, fptr);
11441 retval = do_ioctl(fptr, cmd, narg);
11442 return finish_narg(retval, arg, fptr);
11443}
11444
11445/*
11446 * call-seq:
11447 * ioctl(integer_cmd, argument) -> integer
11448 *
11449 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11450 * which issues a low-level command to an I/O device.
11451 *
11452 * Issues a low-level command to an I/O device.
11453 * The arguments and returned value are platform-dependent.
11454 * The effect of the call is platform-dependent.
11455 *
11456 * If argument +argument+ is an integer, it is passed directly;
11457 * if it is a string, it is interpreted as a binary sequence of bytes.
11458 *
11459 * Not implemented on all platforms.
11460 *
11461 */
11462
11463static VALUE
11464rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11465{
11466 VALUE req, arg;
11467
11468 rb_scan_args(argc, argv, "11", &req, &arg);
11469 return rb_ioctl(io, req, arg);
11470}
11471#else
11472#define rb_io_ioctl rb_f_notimplement
11473#endif
11474
11475#ifdef HAVE_FCNTL
11476struct fcntl_arg {
11477 int fd;
11478 int cmd;
11479 long narg;
11480};
11481
11482static VALUE
11483nogvl_fcntl(void *ptr)
11484{
11485 struct fcntl_arg *arg = ptr;
11486
11487#if defined(F_DUPFD)
11488 if (arg->cmd == F_DUPFD)
11489 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11490#endif
11491 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11492}
11493
11494static int
11495do_fcntl(struct rb_io *io, int cmd, long narg)
11496{
11497 int retval;
11498 struct fcntl_arg arg;
11499
11500 arg.fd = io->fd;
11501 arg.cmd = cmd;
11502 arg.narg = narg;
11503
11504 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11505 if (retval != -1) {
11506 switch (cmd) {
11507#if defined(F_DUPFD)
11508 case F_DUPFD:
11509#endif
11510#if defined(F_DUPFD_CLOEXEC)
11511 case F_DUPFD_CLOEXEC:
11512#endif
11513 rb_update_max_fd(retval);
11514 }
11515 }
11516
11517 return retval;
11518}
11519
11520static VALUE
11521rb_fcntl(VALUE io, VALUE req, VALUE arg)
11522{
11523 int cmd = NUM2INT(req);
11524 rb_io_t *fptr;
11525 long narg;
11526 int retval;
11527
11528 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11529 GetOpenFile(io, fptr);
11530 retval = do_fcntl(fptr, cmd, narg);
11531 return finish_narg(retval, arg, fptr);
11532}
11533
11534/*
11535 * call-seq:
11536 * fcntl(integer_cmd, argument) -> integer
11537 *
11538 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11539 * which provides a mechanism for issuing low-level commands to control or query
11540 * a file-oriented I/O stream. Arguments and results are platform
11541 * dependent.
11542 *
11543 * If +argument+ is a number, its value is passed directly;
11544 * if it is a string, it is interpreted as a binary sequence of bytes.
11545 * (Array#pack might be a useful way to build this string.)
11546 *
11547 * Not implemented on all platforms.
11548 *
11549 */
11550
11551static VALUE
11552rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11553{
11554 VALUE req, arg;
11555
11556 rb_scan_args(argc, argv, "11", &req, &arg);
11557 return rb_fcntl(io, req, arg);
11558}
11559#else
11560#define rb_io_fcntl rb_f_notimplement
11561#endif
11562
11563#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11564/*
11565 * call-seq:
11566 * syscall(integer_callno, *arguments) -> integer
11567 *
11568 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11569 * which calls a specified function.
11570 *
11571 * Calls the operating system function identified by +integer_callno+;
11572 * returns the result of the function or raises SystemCallError if it failed.
11573 * The effect of the call is platform-dependent.
11574 * The arguments and returned value are platform-dependent.
11575 *
11576 * For each of +arguments+: if it is an integer, it is passed directly;
11577 * if it is a string, it is interpreted as a binary sequence of bytes.
11578 * There may be as many as nine such arguments.
11579 *
11580 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11581 * are platform-dependent.
11582 *
11583 * Note: Method +syscall+ is essentially unsafe and unportable.
11584 * The DL (Fiddle) library is preferred for safer and a bit
11585 * more portable programming.
11586 *
11587 * Not implemented on all platforms.
11588 *
11589 */
11590
11591static VALUE
11592rb_f_syscall(int argc, VALUE *argv, VALUE _)
11593{
11594 VALUE arg[8];
11595#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11596# define SYSCALL __syscall
11597# define NUM2SYSCALLID(x) NUM2LONG(x)
11598# define RETVAL2NUM(x) LONG2NUM(x)
11599# if SIZEOF_LONG == 8
11600 long num, retval = -1;
11601# elif SIZEOF_LONG_LONG == 8
11602 long long num, retval = -1;
11603# else
11604# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11605# endif
11606#elif defined(__linux__)
11607# define SYSCALL syscall
11608# define NUM2SYSCALLID(x) NUM2LONG(x)
11609# define RETVAL2NUM(x) LONG2NUM(x)
11610 /*
11611 * Linux man page says, syscall(2) function prototype is below.
11612 *
11613 * int syscall(int number, ...);
11614 *
11615 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11616 */
11617 long num, retval = -1;
11618#else
11619# define SYSCALL syscall
11620# define NUM2SYSCALLID(x) NUM2INT(x)
11621# define RETVAL2NUM(x) INT2NUM(x)
11622 int num, retval = -1;
11623#endif
11624 int i;
11625
11626 if (RTEST(ruby_verbose)) {
11627 rb_category_warning(RB_WARN_CATEGORY_DEPRECATED,
11628 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11629 }
11630
11631 if (argc == 0)
11632 rb_raise(rb_eArgError, "too few arguments for syscall");
11633 if (argc > numberof(arg))
11634 rb_raise(rb_eArgError, "too many arguments for syscall");
11635 num = NUM2SYSCALLID(argv[0]); ++argv;
11636 for (i = argc - 1; i--; ) {
11637 VALUE v = rb_check_string_type(argv[i]);
11638
11639 if (!NIL_P(v)) {
11640 StringValue(v);
11641 rb_str_modify(v);
11642 arg[i] = (VALUE)StringValueCStr(v);
11643 }
11644 else {
11645 arg[i] = (VALUE)NUM2LONG(argv[i]);
11646 }
11647 }
11648
11649 switch (argc) {
11650 case 1:
11651 retval = SYSCALL(num);
11652 break;
11653 case 2:
11654 retval = SYSCALL(num, arg[0]);
11655 break;
11656 case 3:
11657 retval = SYSCALL(num, arg[0],arg[1]);
11658 break;
11659 case 4:
11660 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11661 break;
11662 case 5:
11663 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11664 break;
11665 case 6:
11666 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11667 break;
11668 case 7:
11669 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11670 break;
11671 case 8:
11672 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11673 break;
11674 }
11675
11676 if (retval == -1)
11677 rb_sys_fail(0);
11678 return RETVAL2NUM(retval);
11679#undef SYSCALL
11680#undef NUM2SYSCALLID
11681#undef RETVAL2NUM
11682}
11683#else
11684#define rb_f_syscall rb_f_notimplement
11685#endif
11686
11687static VALUE
11688io_new_instance(VALUE args)
11689{
11690 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11691}
11692
11693static rb_encoding *
11694find_encoding(VALUE v)
11695{
11696 rb_encoding *enc = rb_find_encoding(v);
11697 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11698 return enc;
11699}
11700
11701static void
11702io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11703{
11704 rb_encoding *enc, *enc2;
11705 int ecflags = fptr->encs.ecflags;
11706 VALUE ecopts, tmp;
11707
11708 if (!NIL_P(v2)) {
11709 enc2 = find_encoding(v1);
11710 tmp = rb_check_string_type(v2);
11711 if (!NIL_P(tmp)) {
11712 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11713 /* Special case - "-" => no transcoding */
11714 enc = enc2;
11715 enc2 = NULL;
11716 }
11717 else
11718 enc = find_encoding(v2);
11719 if (enc == enc2) {
11720 /* Special case - "-" => no transcoding */
11721 enc2 = NULL;
11722 }
11723 }
11724 else {
11725 enc = find_encoding(v2);
11726 if (enc == enc2) {
11727 /* Special case - "-" => no transcoding */
11728 enc2 = NULL;
11729 }
11730 }
11731 if (enc2 == rb_ascii8bit_encoding()) {
11732 /* If external is ASCII-8BIT, no transcoding */
11733 enc = enc2;
11734 enc2 = NULL;
11735 }
11736 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11737 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11738 }
11739 else {
11740 if (NIL_P(v1)) {
11741 /* Set to default encodings */
11742 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11743 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11744 ecopts = Qnil;
11745 }
11746 else {
11747 tmp = rb_check_string_type(v1);
11748 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11749 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11750 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11751 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11752 }
11753 else {
11754 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11755 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11756 ecopts = Qnil;
11757 }
11758 }
11759 }
11760 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11761 fptr->encs.enc = enc;
11762 fptr->encs.enc2 = enc2;
11763 fptr->encs.ecflags = ecflags;
11764 fptr->encs.ecopts = ecopts;
11765 clear_codeconv(fptr);
11766
11767}
11768
11769 struct io_encoding_set_args {
11770 rb_io_t *fptr;
11771 VALUE v1;
11772 VALUE v2;
11773 VALUE opt;
11774};
11775
11776static VALUE
11777io_encoding_set_v(VALUE v)
11778{
11779 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11780 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11781 return Qnil;
11782}
11783
11784static VALUE
11785pipe_pair_close(VALUE rw)
11786{
11787 VALUE *rwp = (VALUE *)rw;
11788 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11789}
11790
11791/*
11792 * call-seq:
11793 * IO.pipe(**opts) -> [read_io, write_io]
11794 * IO.pipe(enc, **opts) -> [read_io, write_io]
11795 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11796 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11797 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11798 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11799 *
11800 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11801 * connected to each other.
11802 *
11803 * If argument +enc_string+ is given, it must be a string containing one of:
11804 *
11805 * - The name of the encoding to be used as the external encoding.
11806 * - The colon-separated names of two encodings to be used as the external
11807 * and internal encodings.
11808 *
11809 * If argument +int_enc+ is given, it must be an Encoding object
11810 * or encoding name string that specifies the internal encoding to be used;
11811 * if argument +ext_enc+ is also given, it must be an Encoding object
11812 * or encoding name string that specifies the external encoding to be used.
11813 *
11814 * The string read from +read_io+ is tagged with the external encoding;
11815 * if an internal encoding is also specified, the string is converted
11816 * to, and tagged with, that encoding.
11817 *
11818 * If any encoding is specified,
11819 * optional hash arguments specify the conversion option.
11820 *
11821 * Optional keyword arguments +opts+ specify:
11822 *
11823 * - {Open Options}[rdoc-ref:IO@Open+Options].
11824 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11825 *
11826 * With no block given, returns the two endpoints in an array:
11827 *
11828 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11829 *
11830 * With a block given, calls the block with the two endpoints;
11831 * closes both endpoints and returns the value of the block:
11832 *
11833 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11834 *
11835 * Output:
11836 *
11837 * #<IO:fd 6>
11838 * #<IO:fd 7>
11839 *
11840 * Not available on all platforms.
11841 *
11842 * In the example below, the two processes close the ends of the pipe
11843 * that they are not using. This is not just a cosmetic nicety. The
11844 * read end of a pipe will not generate an end of file condition if
11845 * there are any writers with the pipe still open. In the case of the
11846 * parent process, the <tt>rd.read</tt> will never return if it
11847 * does not first issue a <tt>wr.close</tt>:
11848 *
11849 * rd, wr = IO.pipe
11850 *
11851 * if fork
11852 * wr.close
11853 * puts "Parent got: <#{rd.read}>"
11854 * rd.close
11855 * Process.wait
11856 * else
11857 * rd.close
11858 * puts 'Sending message to parent'
11859 * wr.write "Hi Dad"
11860 * wr.close
11861 * end
11862 *
11863 * <em>produces:</em>
11864 *
11865 * Sending message to parent
11866 * Parent got: <Hi Dad>
11867 *
11868 */
11869
11870static VALUE
11871rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11872{
11873 int pipes[2], state;
11874 VALUE r, w, args[3], v1, v2;
11875 VALUE opt;
11876 rb_io_t *fptr, *fptr2;
11877 struct io_encoding_set_args ies_args;
11878 int fmode = 0;
11879 VALUE ret;
11880
11881 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11882 if (rb_pipe(pipes) < 0)
11883 rb_sys_fail(0);
11884
11885 args[0] = klass;
11886 args[1] = INT2NUM(pipes[0]);
11887 args[2] = INT2FIX(O_RDONLY);
11888 r = rb_protect(io_new_instance, (VALUE)args, &state);
11889 if (state) {
11890 close(pipes[0]);
11891 close(pipes[1]);
11892 rb_jump_tag(state);
11893 }
11894 GetOpenFile(r, fptr);
11895
11896 ies_args.fptr = fptr;
11897 ies_args.v1 = v1;
11898 ies_args.v2 = v2;
11899 ies_args.opt = opt;
11900 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11901 if (state) {
11902 close(pipes[1]);
11903 io_close(r);
11904 rb_jump_tag(state);
11905 }
11906
11907 args[1] = INT2NUM(pipes[1]);
11908 args[2] = INT2FIX(O_WRONLY);
11909 w = rb_protect(io_new_instance, (VALUE)args, &state);
11910 if (state) {
11911 close(pipes[1]);
11912 if (!NIL_P(r)) rb_io_close(r);
11913 rb_jump_tag(state);
11914 }
11915 GetOpenFile(w, fptr2);
11916 rb_io_synchronized(fptr2);
11917
11918 extract_binmode(opt, &fmode);
11919
11920 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11921 rb_io_ascii8bit_binmode(r);
11922 rb_io_ascii8bit_binmode(w);
11923 }
11924
11925#if DEFAULT_TEXTMODE
11926 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11927 fptr->mode &= ~FMODE_TEXTMODE;
11928 setmode(fptr->fd, O_BINARY);
11929 }
11930#if RUBY_CRLF_ENVIRONMENT
11931 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
11932 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
11933 }
11934#endif
11935#endif
11936 fptr->mode |= fmode;
11937#if DEFAULT_TEXTMODE
11938 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11939 fptr2->mode &= ~FMODE_TEXTMODE;
11940 setmode(fptr2->fd, O_BINARY);
11941 }
11942#endif
11943 fptr2->mode |= fmode;
11944
11945 ret = rb_assoc_new(r, w);
11946 if (rb_block_given_p()) {
11947 VALUE rw[2];
11948 rw[0] = r;
11949 rw[1] = w;
11950 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11951 }
11952 return ret;
11953}
11954
11955 struct foreach_arg {
11956 int argc;
11957 VALUE *argv;
11958 VALUE io;
11959};
11960
11961static void
11962open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11963{
11964 VALUE path, v;
11965 VALUE vmode = Qnil, vperm = Qnil;
11966
11967 path = *argv++;
11968 argc--;
11969 FilePathValue(path);
11970 arg->io = 0;
11971 arg->argc = argc;
11972 arg->argv = argv;
11973 if (NIL_P(opt)) {
11974 vmode = INT2NUM(O_RDONLY);
11975 vperm = INT2FIX(0666);
11976 }
11977 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11978 int n;
11979
11980 v = rb_to_array_type(v);
11981 n = RARRAY_LENINT(v);
11982 rb_check_arity(n, 0, 3); /* rb_io_open */
11983 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11984 }
11985 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11986}
11987
11988static VALUE
11989io_s_foreach(VALUE v)
11990{
11991 struct getline_arg *arg = (void *)v;
11992 VALUE str;
11993
11994 if (arg->limit == 0)
11995 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
11996 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11997 rb_lastline_set(str);
11998 rb_yield(str);
11999 }
12000 rb_lastline_set(Qnil);
12001 return Qnil;
12002}
12003
12004/*
12005 * call-seq:
12006 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12007 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12008 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12009 * IO.foreach(...) -> an_enumerator
12010 *
12011 * Calls the block with each successive line read from the stream.
12012 *
12013 * When called from class \IO (but not subclasses of \IO),
12014 * this method has potential security vulnerabilities if called with untrusted input;
12015 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12016 *
12017 * The first argument must be a string that is the path to a file.
12018 *
12019 * With only argument +path+ given, parses lines from the file at the given +path+,
12020 * as determined by the default line separator,
12021 * and calls the block with each successive line:
12022 *
12023 * File.foreach('t.txt') {|line| p line }
12024 *
12025 * Output: the same as above.
12026 *
12027 * For both forms, command and path, the remaining arguments are the same.
12028 *
12029 * With argument +sep+ given, parses lines as determined by that line separator
12030 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12031 *
12032 * File.foreach('t.txt', 'li') {|line| p line }
12033 *
12034 * Output:
12035 *
12036 * "First li"
12037 * "ne\nSecond li"
12038 * "ne\n\nThird li"
12039 * "ne\nFourth li"
12040 * "ne\n"
12041 *
12042 * Each paragraph:
12043 *
12044 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12045 *
12046 * Output:
12047 *
12048 * "First line\nSecond line\n\n"
12049 * "Third line\nFourth line\n"
12050 *
12051 * With argument +limit+ given, parses lines as determined by the default
12052 * line separator and the given line-length limit
12053 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12054 *
12055 * File.foreach('t.txt', 7) {|line| p line }
12056 *
12057 * Output:
12058 *
12059 * "First l"
12060 * "ine\n"
12061 * "Second "
12062 * "line\n"
12063 * "\n"
12064 * "Third l"
12065 * "ine\n"
12066 * "Fourth l"
12067 * "line\n"
12068 *
12069 * With arguments +sep+ and +limit+ given,
12070 * combines the two behaviors
12071 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12072 *
12073 * Optional keyword arguments +opts+ specify:
12074 *
12075 * - {Open Options}[rdoc-ref:IO@Open+Options].
12076 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12077 * - {Line Options}[rdoc-ref:IO@Line+IO].
12078 *
12079 * Returns an Enumerator if no block is given.
12080 *
12081 */
12082
12083static VALUE
12084rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12085{
12086 VALUE opt;
12087 int orig_argc = argc;
12088 struct foreach_arg arg;
12089 struct getline_arg garg;
12090
12091 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12092 RETURN_ENUMERATOR(self, orig_argc, argv);
12093 extract_getline_args(argc-1, argv+1, &garg);
12094 open_key_args(self, argc, argv, opt, &arg);
12095 if (NIL_P(arg.io)) return Qnil;
12096 extract_getline_opts(opt, &garg);
12097 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12098 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12099}
12100
12101static VALUE
12102io_s_readlines(VALUE v)
12103{
12104 struct getline_arg *arg = (void *)v;
12105 return io_readlines(arg, arg->io);
12106}
12107
12108/*
12109 * call-seq:
12110 * IO.readlines(path, sep = $/, **opts) -> array
12111 * IO.readlines(path, limit, **opts) -> array
12112 * IO.readlines(path, sep, limit, **opts) -> array
12113 *
12114 * Returns an array of all lines read from the stream.
12115 *
12116 * When called from class \IO (but not subclasses of \IO),
12117 * this method has potential security vulnerabilities if called with untrusted input;
12118 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12119 *
12120 * The first argument must be a string that is the path to a file.
12121 *
12122 * With only argument +path+ given, parses lines from the file at the given +path+,
12123 * as determined by the default line separator,
12124 * and returns those lines in an array:
12125 *
12126 * IO.readlines('t.txt')
12127 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12128 *
12129 * With argument +sep+ given, parses lines as determined by that line separator
12130 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12131 *
12132 * # Ordinary separator.
12133 * IO.readlines('t.txt', 'li')
12134 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12135 * # Get-paragraphs separator.
12136 * IO.readlines('t.txt', '')
12137 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12138 * # Get-all separator.
12139 * IO.readlines('t.txt', nil)
12140 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12141 *
12142 * With argument +limit+ given, parses lines as determined by the default
12143 * line separator and the given line-length limit
12144 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12145 *
12146 * IO.readlines('t.txt', 7)
12147 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12148 *
12149 * With arguments +sep+ and +limit+ given,
12150 * combines the two behaviors
12151 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12152 *
12153 * Optional keyword arguments +opts+ specify:
12154 *
12155 * - {Open Options}[rdoc-ref:IO@Open+Options].
12156 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12157 * - {Line Options}[rdoc-ref:IO@Line+IO].
12158 *
12159 */
12160
12161static VALUE
12162rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12163{
12164 VALUE opt;
12165 struct foreach_arg arg;
12166 struct getline_arg garg;
12167
12168 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12169 extract_getline_args(argc-1, argv+1, &garg);
12170 open_key_args(io, argc, argv, opt, &arg);
12171 if (NIL_P(arg.io)) return Qnil;
12172 extract_getline_opts(opt, &garg);
12173 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12174 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12175}
12176
12177static VALUE
12178io_s_read(VALUE v)
12179{
12180 struct foreach_arg *arg = (void *)v;
12181 return io_read(arg->argc, arg->argv, arg->io);
12182}
12183
12184 struct seek_arg {
12185 VALUE io;
12186 VALUE offset;
12187 int mode;
12188};
12189
12190static VALUE
12191seek_before_access(VALUE argp)
12192{
12193 struct seek_arg *arg = (struct seek_arg *)argp;
12194 rb_io_binmode(arg->io);
12195 return rb_io_seek(arg->io, arg->offset, arg->mode);
12196}
12197
12198/*
12199 * call-seq:
12200 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12201 *
12202 * Opens the stream, reads and returns some or all of its content,
12203 * and closes the stream; returns +nil+ if no bytes were read.
12204 *
12205 * When called from class \IO (but not subclasses of \IO),
12206 * this method has potential security vulnerabilities if called with untrusted input;
12207 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12208 *
12209 * The first argument must be a string that is the path to a file.
12210 *
12211 * With only argument +path+ given, reads in text mode and returns the entire content
12212 * of the file at the given path:
12213 *
12214 * IO.read('t.txt')
12215 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12216 *
12217 * On Windows, text mode can terminate reading and leave bytes in the file
12218 * unread when encountering certain special bytes. Consider using
12219 * IO.binread if all bytes in the file should be read.
12220 *
12221 * With argument +length+, returns +length+ bytes if available:
12222 *
12223 * IO.read('t.txt', 7) # => "First l"
12224 * IO.read('t.txt', 700)
12225 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12226 *
12227 * With arguments +length+ and +offset+, returns +length+ bytes
12228 * if available, beginning at the given +offset+:
12229 *
12230 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12231 * IO.read('t.txt', 10, 200) # => nil
12232 *
12233 * Optional keyword arguments +opts+ specify:
12234 *
12235 * - {Open Options}[rdoc-ref:IO@Open+Options].
12236 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12237 *
12238 */
12239
12240static VALUE
12241rb_io_s_read(int argc, VALUE *argv, VALUE io)
12242{
12243 VALUE opt, offset;
12244 long off;
12245 struct foreach_arg arg;
12246
12247 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12248 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12249 rb_raise(rb_eArgError, "negative offset %ld given", off);
12250 }
12251 open_key_args(io, argc, argv, opt, &arg);
12252 if (NIL_P(arg.io)) return Qnil;
12253 if (!NIL_P(offset)) {
12254 struct seek_arg sarg;
12255 int state = 0;
12256 sarg.io = arg.io;
12257 sarg.offset = offset;
12258 sarg.mode = SEEK_SET;
12259 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12260 if (state) {
12261 rb_io_close(arg.io);
12262 rb_jump_tag(state);
12263 }
12264 if (arg.argc == 2) arg.argc = 1;
12265 }
12266 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12267}
12268
12269/*
12270 * call-seq:
12271 * IO.binread(path, length = nil, offset = 0) -> string or nil
12272 *
12273 * Behaves like IO.read, except that the stream is opened in binary mode
12274 * with ASCII-8BIT encoding.
12275 *
12276 * When called from class \IO (but not subclasses of \IO),
12277 * this method has potential security vulnerabilities if called with untrusted input;
12278 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12279 *
12280 */
12281
12282static VALUE
12283rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12284{
12285 VALUE offset;
12286 struct foreach_arg arg;
12287 enum {
12288 fmode = FMODE_READABLE|FMODE_BINMODE,
12289 oflags = O_RDONLY
12290#ifdef O_BINARY
12291 |O_BINARY
12292#endif
12293 };
12294 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12295
12296 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12297 FilePathValue(argv[0]);
12298 convconfig.enc = rb_ascii8bit_encoding();
12299 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12300 if (NIL_P(arg.io)) return Qnil;
12301 arg.argv = argv+1;
12302 arg.argc = (argc > 1) ? 1 : 0;
12303 if (!NIL_P(offset)) {
12304 struct seek_arg sarg;
12305 int state = 0;
12306 sarg.io = arg.io;
12307 sarg.offset = offset;
12308 sarg.mode = SEEK_SET;
12309 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12310 if (state) {
12311 rb_io_close(arg.io);
12312 rb_jump_tag(state);
12313 }
12314 }
12315 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12316}
12317
12318static VALUE
12319io_s_write0(VALUE v)
12320{
12321 struct write_arg *arg = (void *)v;
12322 return io_write(arg->io,arg->str,arg->nosync);
12323}
12324
12325static VALUE
12326io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12327{
12328 VALUE string, offset, opt;
12329 struct foreach_arg arg;
12330 struct write_arg warg;
12331
12332 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12333
12334 if (NIL_P(opt)) opt = rb_hash_new();
12335 else opt = rb_hash_dup(opt);
12336
12337
12338 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12339 int mode = O_WRONLY|O_CREAT;
12340#ifdef O_BINARY
12341 if (binary) mode |= O_BINARY;
12342#endif
12343 if (NIL_P(offset)) mode |= O_TRUNC;
12344 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12345 }
12346 open_key_args(klass, argc, argv, opt, &arg);
12347
12348#ifndef O_BINARY
12349 if (binary) rb_io_binmode_m(arg.io);
12350#endif
12351
12352 if (NIL_P(arg.io)) return Qnil;
12353 if (!NIL_P(offset)) {
12354 struct seek_arg sarg;
12355 int state = 0;
12356 sarg.io = arg.io;
12357 sarg.offset = offset;
12358 sarg.mode = SEEK_SET;
12359 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12360 if (state) {
12361 rb_io_close(arg.io);
12362 rb_jump_tag(state);
12363 }
12364 }
12365
12366 warg.io = arg.io;
12367 warg.str = string;
12368 warg.nosync = 0;
12369
12370 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12371}
12372
12373/*
12374 * call-seq:
12375 * IO.write(path, data, offset = 0, **opts) -> integer
12376 *
12377 * Opens the stream, writes the given +data+ to it,
12378 * and closes the stream; returns the number of bytes written.
12379 *
12380 * When called from class \IO (but not subclasses of \IO),
12381 * this method has potential security vulnerabilities if called with untrusted input;
12382 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12383 *
12384 * The first argument must be a string that is the path to a file.
12385 *
12386 * With only argument +path+ given, writes the given +data+ to the file at that path:
12387 *
12388 * IO.write('t.tmp', 'abc') # => 3
12389 * File.read('t.tmp') # => "abc"
12390 *
12391 * If +offset+ is zero (the default), the file is overwritten:
12392 *
12393 * IO.write('t.tmp', 'A') # => 1
12394 * File.read('t.tmp') # => "A"
12395 *
12396 * If +offset+ in within the file content, the file is partly overwritten:
12397 *
12398 * IO.write('t.tmp', 'abcdef') # => 3
12399 * File.read('t.tmp') # => "abcdef"
12400 * # Offset within content.
12401 * IO.write('t.tmp', '012', 2) # => 3
12402 * File.read('t.tmp') # => "ab012f"
12403 *
12404 * If +offset+ is outside the file content,
12405 * the file is padded with null characters <tt>"\u0000"</tt>:
12406 *
12407 * IO.write('t.tmp', 'xyz', 10) # => 3
12408 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12409 *
12410 * Optional keyword arguments +opts+ specify:
12411 *
12412 * - {Open Options}[rdoc-ref:IO@Open+Options].
12413 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12414 *
12415 */
12416
12417static VALUE
12418rb_io_s_write(int argc, VALUE *argv, VALUE io)
12419{
12420 return io_s_write(argc, argv, io, 0);
12421}
12422
12423/*
12424 * call-seq:
12425 * IO.binwrite(path, string, offset = 0) -> integer
12426 *
12427 * Behaves like IO.write, except that the stream is opened in binary mode
12428 * with ASCII-8BIT encoding.
12429 *
12430 * When called from class \IO (but not subclasses of \IO),
12431 * this method has potential security vulnerabilities if called with untrusted input;
12432 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12433 *
12434 */
12435
12436static VALUE
12437rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12438{
12439 return io_s_write(argc, argv, io, 1);
12440}
12441
12442 struct copy_stream_struct {
12443 VALUE src;
12444 VALUE dst;
12445 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12446 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12447
12448 rb_io_t *src_fptr;
12449 rb_io_t *dst_fptr;
12450 unsigned close_src : 1;
12451 unsigned close_dst : 1;
12452 int error_no;
12453 rb_off_t total;
12454 const char *syserr;
12455 const char *notimp;
12456 VALUE th;
12457 struct stat src_stat;
12458 struct stat dst_stat;
12459#ifdef HAVE_FCOPYFILE
12460 copyfile_state_t copyfile_state;
12461#endif
12462};
12463
12464static void *
12465exec_interrupts(void *arg)
12466{
12467 VALUE th = (VALUE)arg;
12468 rb_thread_execute_interrupts(th);
12469 return NULL;
12470}
12471
12472/*
12473 * returns TRUE if the preceding system call was interrupted
12474 * so we can continue. If the thread was interrupted, we
12475 * reacquire the GVL to execute interrupts before continuing.
12476 */
12477static int
12478maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12479{
12480 switch (errno) {
12481 case EINTR:
12482#if defined(ERESTART)
12483 case ERESTART:
12484#endif
12485 if (rb_thread_interrupted(stp->th)) {
12486 if (has_gvl)
12487 rb_thread_execute_interrupts(stp->th);
12488 else
12489 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12490 }
12491 return TRUE;
12492 }
12493 return FALSE;
12494}
12495
12496 struct fiber_scheduler_wait_for_arguments {
12497 VALUE scheduler;
12498
12499 rb_io_t *fptr;
12500 short events;
12501
12502 VALUE result;
12503};
12504
12505static void *
12506fiber_scheduler_wait_for(void * _arguments)
12507{
12508 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12509
12510 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12511
12512 return NULL;
12513}
12514
12515#if USE_POLL
12516# define IOWAIT_SYSCALL "poll"
12517STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12518STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12519static int
12520nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12521{
12522 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
12523 if (scheduler != Qnil) {
12524 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12525 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12526 return RTEST(args.result);
12527 }
12528
12529 int fd = fptr->fd;
12530 if (fd == -1) return 0;
12531
12532 struct pollfd fds;
12533
12534 fds.fd = fd;
12535 fds.events = events;
12536
12537 int timeout_milliseconds = -1;
12538
12539 if (timeout) {
12540 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12541 }
12542
12543 return poll(&fds, 1, timeout_milliseconds);
12544}
12545#else /* !USE_POLL */
12546# define IOWAIT_SYSCALL "select"
12547static int
12548nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12549{
12550 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
12551 if (scheduler != Qnil) {
12552 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12553 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12554 return RTEST(args.result);
12555 }
12556
12557 int fd = fptr->fd;
12558
12559 if (fd == -1) {
12560 errno = EBADF;
12561 return -1;
12562 }
12563
12564 rb_fdset_t fds;
12565 int ret;
12566
12567 rb_fd_init(&fds);
12568 rb_fd_set(fd, &fds);
12569
12570 switch (events) {
12571 case RB_WAITFD_IN:
12572 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12573 break;
12574 case RB_WAITFD_OUT:
12575 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12576 break;
12577 default:
12578 VM_UNREACHABLE(nogvl_wait_for);
12579 }
12580
12581 rb_fd_term(&fds);
12582
12583 // On timeout, this returns 0.
12584 return ret;
12585}
12586#endif /* !USE_POLL */
12587
12588static int
12589maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12590{
12591 int ret;
12592
12593 do {
12594 if (has_gvl) {
12595 ret = RB_NUM2INT(rb_io_wait(stp->src, RB_INT2NUM(RUBY_IO_READABLE), Qnil));
12596 }
12597 else {
12598 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12599 }
12600 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12601
12602 if (ret < 0) {
12603 stp->syserr = IOWAIT_SYSCALL;
12604 stp->error_no = errno;
12605 return ret;
12606 }
12607 return 0;
12608}
12609
12610static int
12611nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12612{
12613 int ret;
12614
12615 do {
12616 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12617 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12618
12619 if (ret < 0) {
12620 stp->syserr = IOWAIT_SYSCALL;
12621 stp->error_no = errno;
12622 return ret;
12623 }
12624 return 0;
12625}
12626
12627#ifdef USE_COPY_FILE_RANGE
12628
12629static ssize_t
12630simple_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)
12631{
12632#ifdef HAVE_COPY_FILE_RANGE
12633 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12634#else
12635 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12636#endif
12637}
12638
12639static int
12640nogvl_copy_file_range(struct copy_stream_struct *stp)
12641{
12642 ssize_t ss;
12643 rb_off_t src_size;
12644 rb_off_t copy_length, src_offset, *src_offset_ptr;
12645
12646 if (!S_ISREG(stp->src_stat.st_mode))
12647 return 0;
12648
12649 src_size = stp->src_stat.st_size;
12650 src_offset = stp->src_offset;
12651 if (src_offset >= (rb_off_t)0) {
12652 src_offset_ptr = &src_offset;
12653 }
12654 else {
12655 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12656 }
12657
12658 copy_length = stp->copy_length;
12659 if (copy_length < (rb_off_t)0) {
12660 if (src_offset < (rb_off_t)0) {
12661 rb_off_t current_offset;
12662 errno = 0;
12663 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12664 if (current_offset < (rb_off_t)0 && errno) {
12665 stp->syserr = "lseek";
12666 stp->error_no = errno;
12667 return (int)current_offset;
12668 }
12669 copy_length = src_size - current_offset;
12670 }
12671 else {
12672 copy_length = src_size - src_offset;
12673 }
12674 }
12675
12676 retry_copy_file_range:
12677# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12678 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12679 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12680# else
12681 ss = (ssize_t)copy_length;
12682# endif
12683 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12684 if (0 < ss) {
12685 stp->total += ss;
12686 copy_length -= ss;
12687 if (0 < copy_length) {
12688 goto retry_copy_file_range;
12689 }
12690 }
12691 if (ss < 0) {
12692 if (maygvl_copy_stream_continue_p(0, stp)) {
12693 goto retry_copy_file_range;
12694 }
12695 switch (errno) {
12696 case EINVAL:
12697 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12698 docker container) */
12699#ifdef ENOSYS
12700 case ENOSYS:
12701#endif
12702#ifdef EXDEV
12703 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12704#endif
12705 return 0;
12706 case EAGAIN:
12707#if EWOULDBLOCK != EAGAIN
12708 case EWOULDBLOCK:
12709#endif
12710 {
12711 int ret = nogvl_copy_stream_wait_write(stp);
12712 if (ret < 0) return ret;
12713 }
12714 goto retry_copy_file_range;
12715 case EBADF:
12716 {
12717 int e = errno;
12718 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12719
12720 if (flags != -1 && flags & O_APPEND) {
12721 return 0;
12722 }
12723 errno = e;
12724 }
12725 }
12726 stp->syserr = "copy_file_range";
12727 stp->error_no = errno;
12728 return (int)ss;
12729 }
12730 return 1;
12731}
12732#endif
12733
12734#ifdef HAVE_FCOPYFILE
12735static int
12736nogvl_fcopyfile(struct copy_stream_struct *stp)
12737{
12738 rb_off_t cur, ss = 0;
12739 const rb_off_t src_offset = stp->src_offset;
12740 int ret;
12741
12742 if (stp->copy_length >= (rb_off_t)0) {
12743 /* copy_length can't be specified in fcopyfile(3) */
12744 return 0;
12745 }
12746
12747 if (!S_ISREG(stp->src_stat.st_mode))
12748 return 0;
12749
12750 if (!S_ISREG(stp->dst_stat.st_mode))
12751 return 0;
12752 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12753 return 0;
12754 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12755 /* fcopyfile(3) appends src IO to dst IO and then truncates
12756 * dst IO to src IO's original size. */
12757 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12758 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12759 if (end > (rb_off_t)0) return 0;
12760 }
12761
12762 if (src_offset > (rb_off_t)0) {
12763 rb_off_t r;
12764
12765 /* get current offset */
12766 errno = 0;
12767 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12768 if (cur < (rb_off_t)0 && errno) {
12769 stp->error_no = errno;
12770 return 1;
12771 }
12772
12773 errno = 0;
12774 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12775 if (r < (rb_off_t)0 && errno) {
12776 stp->error_no = errno;
12777 return 1;
12778 }
12779 }
12780
12781 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12782 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12783 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12784
12785 if (ret == 0) { /* success */
12786 stp->total = ss;
12787 if (src_offset > (rb_off_t)0) {
12788 rb_off_t r;
12789 errno = 0;
12790 /* reset offset */
12791 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12792 if (r < (rb_off_t)0 && errno) {
12793 stp->error_no = errno;
12794 return 1;
12795 }
12796 }
12797 }
12798 else {
12799 switch (errno) {
12800 case ENOTSUP:
12801 case EPERM:
12802 case EINVAL:
12803 return 0;
12804 }
12805 stp->syserr = "fcopyfile";
12806 stp->error_no = errno;
12807 return (int)ret;
12808 }
12809 return 1;
12810}
12811#endif
12812
12813#ifdef HAVE_SENDFILE
12814
12815# ifdef __linux__
12816# define USE_SENDFILE
12817
12818# ifdef HAVE_SYS_SENDFILE_H
12819# include <sys/sendfile.h>
12820# endif
12821
12822static ssize_t
12823simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12824{
12825 return sendfile(out_fd, in_fd, offset, (size_t)count);
12826}
12827
12828# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12829/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12830 * without cpuset -l 0.
12831 */
12832# define USE_SENDFILE
12833
12834static ssize_t
12835simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12836{
12837 int r;
12838 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12839 rb_off_t sbytes;
12840# ifdef __APPLE__
12841 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12842 sbytes = count;
12843# else
12844 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12845# endif
12846 if (r != 0 && sbytes == 0) return r;
12847 if (offset) {
12848 *offset += sbytes;
12849 }
12850 else {
12851 lseek(in_fd, sbytes, SEEK_CUR);
12852 }
12853 return (ssize_t)sbytes;
12854}
12855
12856# endif
12857
12858#endif
12859
12860#ifdef USE_SENDFILE
12861static int
12862nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12863{
12864 ssize_t ss;
12865 rb_off_t src_size;
12866 rb_off_t copy_length;
12867 rb_off_t src_offset;
12868 int use_pread;
12869
12870 if (!S_ISREG(stp->src_stat.st_mode))
12871 return 0;
12872
12873 src_size = stp->src_stat.st_size;
12874#ifndef __linux__
12875 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12876 return 0;
12877#endif
12878
12879 src_offset = stp->src_offset;
12880 use_pread = src_offset >= (rb_off_t)0;
12881
12882 copy_length = stp->copy_length;
12883 if (copy_length < (rb_off_t)0) {
12884 if (use_pread)
12885 copy_length = src_size - src_offset;
12886 else {
12887 rb_off_t cur;
12888 errno = 0;
12889 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12890 if (cur < (rb_off_t)0 && errno) {
12891 stp->syserr = "lseek";
12892 stp->error_no = errno;
12893 return (int)cur;
12894 }
12895 copy_length = src_size - cur;
12896 }
12897 }
12898
12899 retry_sendfile:
12900# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12901 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12902 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12903# else
12904 ss = (ssize_t)copy_length;
12905# endif
12906 if (use_pread) {
12907 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12908 }
12909 else {
12910 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12911 }
12912 if (0 < ss) {
12913 stp->total += ss;
12914 copy_length -= ss;
12915 if (0 < copy_length) {
12916 goto retry_sendfile;
12917 }
12918 }
12919 if (ss < 0) {
12920 if (maygvl_copy_stream_continue_p(0, stp))
12921 goto retry_sendfile;
12922 switch (errno) {
12923 case EINVAL:
12924#ifdef ENOSYS
12925 case ENOSYS:
12926#endif
12927#ifdef EOPNOTSUP
12928 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12929 see also: [Feature #16965] */
12930 case EOPNOTSUP:
12931#endif
12932 return 0;
12933 case EAGAIN:
12934#if EWOULDBLOCK != EAGAIN
12935 case EWOULDBLOCK:
12936#endif
12937 {
12938 int ret;
12939#ifndef __linux__
12940 /*
12941 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12942 * select() reports regular files to always be "ready", so
12943 * there is no need to select() on it.
12944 * Other OSes may have the same limitation for sendfile() which
12945 * allow us to bypass maygvl_copy_stream_wait_read()...
12946 */
12947 ret = maygvl_copy_stream_wait_read(0, stp);
12948 if (ret < 0) return ret;
12949#endif
12950 ret = nogvl_copy_stream_wait_write(stp);
12951 if (ret < 0) return ret;
12952 }
12953 goto retry_sendfile;
12954 }
12955 stp->syserr = "sendfile";
12956 stp->error_no = errno;
12957 return (int)ss;
12958 }
12959 return 1;
12960}
12961#endif
12962
12963static ssize_t
12964maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12965{
12966 if (has_gvl)
12967 return rb_io_read_memory(fptr, buf, count);
12968 else
12969 return read(fptr->fd, buf, count);
12970}
12971
12972static ssize_t
12973maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12974{
12975 ssize_t ss;
12976 retry_read:
12977 if (offset < (rb_off_t)0) {
12978 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12979 }
12980 else {
12981 ss = pread(stp->src_fptr->fd, buf, len, offset);
12982 }
12983 if (ss == 0) {
12984 return 0;
12985 }
12986 if (ss < 0) {
12987 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12988 goto retry_read;
12989 switch (errno) {
12990 case EAGAIN:
12991#if EWOULDBLOCK != EAGAIN
12992 case EWOULDBLOCK:
12993#endif
12994 {
12995 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12996 if (ret < 0) return ret;
12997 }
12998 goto retry_read;
12999#ifdef ENOSYS
13000 case ENOSYS:
13001 stp->notimp = "pread";
13002 return ss;
13003#endif
13004 }
13005 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13006 stp->error_no = errno;
13007 }
13008 return ss;
13009}
13010
13011static int
13012nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13013{
13014 ssize_t ss;
13015 int off = 0;
13016 while (len) {
13017 ss = write(stp->dst_fptr->fd, buf+off, len);
13018 if (ss < 0) {
13019 if (maygvl_copy_stream_continue_p(0, stp))
13020 continue;
13021 if (io_again_p(errno)) {
13022 int ret = nogvl_copy_stream_wait_write(stp);
13023 if (ret < 0) return ret;
13024 continue;
13025 }
13026 stp->syserr = "write";
13027 stp->error_no = errno;
13028 return (int)ss;
13029 }
13030 off += (int)ss;
13031 len -= (int)ss;
13032 stp->total += ss;
13033 }
13034 return 0;
13035}
13036
13037static void
13038nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13039{
13040 char buf[1024*16];
13041 size_t len;
13042 ssize_t ss;
13043 int ret;
13044 rb_off_t copy_length;
13045 rb_off_t src_offset;
13046 int use_eof;
13047 int use_pread;
13048
13049 copy_length = stp->copy_length;
13050 use_eof = copy_length < (rb_off_t)0;
13051 src_offset = stp->src_offset;
13052 use_pread = src_offset >= (rb_off_t)0;
13053
13054 if (use_pread && stp->close_src) {
13055 rb_off_t r;
13056 errno = 0;
13057 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13058 if (r < (rb_off_t)0 && errno) {
13059 stp->syserr = "lseek";
13060 stp->error_no = errno;
13061 return;
13062 }
13063 src_offset = (rb_off_t)-1;
13064 use_pread = 0;
13065 }
13066
13067 while (use_eof || 0 < copy_length) {
13068 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13069 len = (size_t)copy_length;
13070 }
13071 else {
13072 len = sizeof(buf);
13073 }
13074 if (use_pread) {
13075 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13076 if (0 < ss)
13077 src_offset += ss;
13078 }
13079 else {
13080 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13081 }
13082 if (ss <= 0) /* EOF or error */
13083 return;
13084
13085 ret = nogvl_copy_stream_write(stp, buf, ss);
13086 if (ret < 0)
13087 return;
13088
13089 if (!use_eof)
13090 copy_length -= ss;
13091 }
13092}
13093
13094static void *
13095nogvl_copy_stream_func(void *arg)
13096{
13097 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13098#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13099 int ret;
13100#endif
13101
13102#ifdef USE_COPY_FILE_RANGE
13103 ret = nogvl_copy_file_range(stp);
13104 if (ret != 0)
13105 goto finish; /* error or success */
13106#endif
13107
13108#ifdef HAVE_FCOPYFILE
13109 ret = nogvl_fcopyfile(stp);
13110 if (ret != 0)
13111 goto finish; /* error or success */
13112#endif
13113
13114#ifdef USE_SENDFILE
13115 ret = nogvl_copy_stream_sendfile(stp);
13116 if (ret != 0)
13117 goto finish; /* error or success */
13118#endif
13119
13120 nogvl_copy_stream_read_write(stp);
13121
13122#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13123 finish:
13124#endif
13125 return 0;
13126}
13127
13128static VALUE
13129copy_stream_fallback_body(VALUE arg)
13130{
13131 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13132 const int buflen = 16*1024;
13133 VALUE n;
13134 VALUE buf = rb_str_buf_new(buflen);
13135 rb_off_t rest = stp->copy_length;
13136 rb_off_t off = stp->src_offset;
13137 ID read_method = id_readpartial;
13138
13139 if (!stp->src_fptr) {
13140 if (!rb_respond_to(stp->src, read_method)) {
13141 read_method = id_read;
13142 }
13143 }
13144
13145 while (1) {
13146 long numwrote;
13147 long l;
13148 rb_str_make_independent(buf);
13149 if (stp->copy_length < (rb_off_t)0) {
13150 l = buflen;
13151 }
13152 else {
13153 if (rest == 0) {
13154 rb_str_resize(buf, 0);
13155 break;
13156 }
13157 l = buflen < rest ? buflen : (long)rest;
13158 }
13159 if (!stp->src_fptr) {
13160 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13161
13162 if (read_method == id_read && NIL_P(rc))
13163 break;
13164 }
13165 else {
13166 ssize_t ss;
13167 rb_str_resize(buf, buflen);
13168 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13169 rb_str_resize(buf, ss > 0 ? ss : 0);
13170 if (ss < 0)
13171 return Qnil;
13172 if (ss == 0)
13173 rb_eof_error();
13174 if (off >= (rb_off_t)0)
13175 off += ss;
13176 }
13177 n = rb_io_write(stp->dst, buf);
13178 numwrote = NUM2LONG(n);
13179 stp->total += numwrote;
13180 rest -= numwrote;
13181 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13182 break;
13183 }
13184 }
13185
13186 return Qnil;
13187}
13188
13189static VALUE
13190copy_stream_fallback(struct copy_stream_struct *stp)
13191{
13192 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13193 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13194 }
13195 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13196 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13197 rb_eEOFError, (VALUE)0);
13198 return Qnil;
13199}
13200
13201static VALUE
13202copy_stream_body(VALUE arg)
13203{
13204 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13205 VALUE src_io = stp->src, dst_io = stp->dst;
13206 const int common_oflags = 0
13207#ifdef O_NOCTTY
13208 | O_NOCTTY
13209#endif
13210 ;
13211
13212 stp->th = rb_thread_current();
13213
13214 stp->total = 0;
13215
13216 if (src_io == argf ||
13217 !(RB_TYPE_P(src_io, T_FILE) ||
13218 RB_TYPE_P(src_io, T_STRING) ||
13219 rb_respond_to(src_io, rb_intern("to_path")))) {
13220 stp->src_fptr = NULL;
13221 }
13222 else {
13223 int stat_ret;
13224 VALUE tmp_io = rb_io_check_io(src_io);
13225 if (!NIL_P(tmp_io)) {
13226 src_io = tmp_io;
13227 }
13228 else if (!RB_TYPE_P(src_io, T_FILE)) {
13229 VALUE args[2];
13230 FilePathValue(src_io);
13231 args[0] = src_io;
13232 args[1] = INT2NUM(O_RDONLY|common_oflags);
13233 src_io = rb_class_new_instance(2, args, rb_cFile);
13234 stp->src = src_io;
13235 stp->close_src = 1;
13236 }
13237 RB_IO_POINTER(src_io, stp->src_fptr);
13238 rb_io_check_byte_readable(stp->src_fptr);
13239
13240 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13241 if (stat_ret < 0) {
13242 stp->syserr = "fstat";
13243 stp->error_no = errno;
13244 return Qnil;
13245 }
13246 }
13247
13248 if (dst_io == argf ||
13249 !(RB_TYPE_P(dst_io, T_FILE) ||
13250 RB_TYPE_P(dst_io, T_STRING) ||
13251 rb_respond_to(dst_io, rb_intern("to_path")))) {
13252 stp->dst_fptr = NULL;
13253 }
13254 else {
13255 int stat_ret;
13256 VALUE tmp_io = rb_io_check_io(dst_io);
13257 if (!NIL_P(tmp_io)) {
13258 dst_io = GetWriteIO(tmp_io);
13259 }
13260 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13261 VALUE args[3];
13262 FilePathValue(dst_io);
13263 args[0] = dst_io;
13264 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13265 args[2] = INT2FIX(0666);
13266 dst_io = rb_class_new_instance(3, args, rb_cFile);
13267 stp->dst = dst_io;
13268 stp->close_dst = 1;
13269 }
13270 else {
13271 dst_io = GetWriteIO(dst_io);
13272 stp->dst = dst_io;
13273 }
13274 RB_IO_POINTER(dst_io, stp->dst_fptr);
13275 rb_io_check_writable(stp->dst_fptr);
13276
13277 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13278 if (stat_ret < 0) {
13279 stp->syserr = "fstat";
13280 stp->error_no = errno;
13281 return Qnil;
13282 }
13283 }
13284
13285#ifdef O_BINARY
13286 if (stp->src_fptr)
13287 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13288#endif
13289 if (stp->dst_fptr)
13290 io_ascii8bit_binmode(stp->dst_fptr);
13291
13292 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13293 size_t len = stp->src_fptr->rbuf.len;
13294 VALUE str;
13295 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13296 len = (size_t)stp->copy_length;
13297 }
13298 str = rb_str_buf_new(len);
13299 rb_str_resize(str,len);
13300 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13301 if (stp->dst_fptr) { /* IO or filename */
13302 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13303 rb_sys_fail_on_write(stp->dst_fptr);
13304 }
13305 else /* others such as StringIO */
13306 rb_io_write(dst_io, str);
13307 rb_str_resize(str, 0);
13308 stp->total += len;
13309 if (stp->copy_length >= (rb_off_t)0)
13310 stp->copy_length -= len;
13311 }
13312
13313 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13314 rb_raise(rb_eIOError, "flush failed");
13315 }
13316
13317 if (stp->copy_length == 0)
13318 return Qnil;
13319
13320 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13321 return copy_stream_fallback(stp);
13322 }
13323
13324 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13325 return Qnil;
13326}
13327
13328static VALUE
13329copy_stream_finalize(VALUE arg)
13330{
13331 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13332
13333#ifdef HAVE_FCOPYFILE
13334 if (stp->copyfile_state) {
13335 copyfile_state_free(stp->copyfile_state);
13336 }
13337#endif
13338
13339 if (stp->close_src) {
13340 rb_io_close_m(stp->src);
13341 }
13342 if (stp->close_dst) {
13343 rb_io_close_m(stp->dst);
13344 }
13345 if (stp->syserr) {
13346 rb_syserr_fail(stp->error_no, stp->syserr);
13347 }
13348 if (stp->notimp) {
13349 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13350 }
13351 return Qnil;
13352}
13353
13354/*
13355 * call-seq:
13356 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13357 *
13358 * Copies from the given +src+ to the given +dst+,
13359 * returning the number of bytes copied.
13360 *
13361 * - The given +src+ must be one of the following:
13362 *
13363 * - The path to a readable file, from which source data is to be read.
13364 * - An \IO-like object, opened for reading and capable of responding
13365 * to method +:readpartial+ or method +:read+.
13366 *
13367 * - The given +dst+ must be one of the following:
13368 *
13369 * - The path to a writable file, to which data is to be written.
13370 * - An \IO-like object, opened for writing and capable of responding
13371 * to method +:write+.
13372 *
13373 * The examples here use file <tt>t.txt</tt> as source:
13374 *
13375 * File.read('t.txt')
13376 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13377 * File.read('t.txt').size # => 47
13378 *
13379 * If only arguments +src+ and +dst+ are given,
13380 * the entire source stream is copied:
13381 *
13382 * # Paths.
13383 * IO.copy_stream('t.txt', 't.tmp') # => 47
13384 *
13385 * # IOs (recall that a File is also an IO).
13386 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13387 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13388 * IO.copy_stream(src_io, dst_io) # => 47
13389 * src_io.close
13390 * dst_io.close
13391 *
13392 * With argument +src_length+ a non-negative integer,
13393 * no more than that many bytes are copied:
13394 *
13395 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13396 * File.read('t.tmp') # => "First line"
13397 *
13398 * With argument +src_offset+ also given,
13399 * the source stream is read beginning at that offset:
13400 *
13401 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13402 * IO.read('t.tmp') # => "Second line"
13403 *
13404 */
13405static VALUE
13406rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13407{
13408 VALUE src, dst, length, src_offset;
13409 struct copy_stream_struct st;
13410
13411 MEMZERO(&st, struct copy_stream_struct, 1);
13412
13413 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13414
13415 st.src = src;
13416 st.dst = dst;
13417
13418 st.src_fptr = NULL;
13419 st.dst_fptr = NULL;
13420
13421 if (NIL_P(length))
13422 st.copy_length = (rb_off_t)-1;
13423 else
13424 st.copy_length = NUM2OFFT(length);
13425
13426 if (NIL_P(src_offset))
13427 st.src_offset = (rb_off_t)-1;
13428 else
13429 st.src_offset = NUM2OFFT(src_offset);
13430
13431 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13432
13433 return OFFT2NUM(st.total);
13434}
13435
13436/*
13437 * call-seq:
13438 * external_encoding -> encoding or nil
13439 *
13440 * Returns the Encoding object that represents the encoding of the stream,
13441 * or +nil+ if the stream is in write mode and no encoding is specified.
13442 *
13443 * See {Encodings}[rdoc-ref:File@Encodings].
13444 *
13445 */
13446
13447static VALUE
13448rb_io_external_encoding(VALUE io)
13449{
13450 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13451
13452 if (fptr->encs.enc2) {
13453 return rb_enc_from_encoding(fptr->encs.enc2);
13454 }
13455 if (fptr->mode & FMODE_WRITABLE) {
13456 if (fptr->encs.enc)
13457 return rb_enc_from_encoding(fptr->encs.enc);
13458 return Qnil;
13459 }
13460 return rb_enc_from_encoding(io_read_encoding(fptr));
13461}
13462
13463/*
13464 * call-seq:
13465 * internal_encoding -> encoding or nil
13466 *
13467 * Returns the Encoding object that represents the encoding of the internal string,
13468 * if conversion is specified,
13469 * or +nil+ otherwise.
13470 *
13471 * See {Encodings}[rdoc-ref:File@Encodings].
13472 *
13473 */
13474
13475static VALUE
13476rb_io_internal_encoding(VALUE io)
13477{
13478 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13479
13480 if (!fptr->encs.enc2) return Qnil;
13481 return rb_enc_from_encoding(io_read_encoding(fptr));
13482}
13483
13484/*
13485 * call-seq:
13486 * set_encoding(ext_enc) -> self
13487 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13488 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13489 *
13490 * See {Encodings}[rdoc-ref:File@Encodings].
13491 *
13492 * Argument +ext_enc+, if given, must be an Encoding object
13493 * or a String with the encoding name;
13494 * it is assigned as the encoding for the stream.
13495 *
13496 * Argument +int_enc+, if given, must be an Encoding object
13497 * or a String with the encoding name;
13498 * it is assigned as the encoding for the internal string.
13499 *
13500 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13501 * containing two colon-separated encoding names;
13502 * corresponding Encoding objects are assigned as the external
13503 * and internal encodings for the stream.
13504 *
13505 * If the external encoding of a string is binary/ASCII-8BIT,
13506 * the internal encoding of the string is set to nil, since no
13507 * transcoding is needed.
13508 *
13509 * Optional keyword arguments +enc_opts+ specify
13510 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13511 *
13512 */
13513
13514static VALUE
13515rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13516{
13517 rb_io_t *fptr;
13518 VALUE v1, v2, opt;
13519
13520 if (!RB_TYPE_P(io, T_FILE)) {
13521 return forward(io, id_set_encoding, argc, argv);
13522 }
13523
13524 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13525 GetOpenFile(io, fptr);
13526 io_encoding_set(fptr, v1, v2, opt);
13527 return io;
13528}
13529
13530void
13531rb_stdio_set_default_encoding(void)
13532{
13533 VALUE val = Qnil;
13534
13535#ifdef _WIN32
13536 if (isatty(fileno(stdin))) {
13537 rb_encoding *external = rb_locale_encoding();
13538 rb_encoding *internal = rb_default_internal_encoding();
13539 if (!internal) internal = rb_default_external_encoding();
13540 io_encoding_set(RFILE(rb_stdin)->fptr,
13541 rb_enc_from_encoding(external),
13542 rb_enc_from_encoding(internal),
13543 Qnil);
13544 }
13545 else
13546#endif
13547 rb_io_set_encoding(1, &val, rb_stdin);
13548 rb_io_set_encoding(1, &val, rb_stdout);
13549 rb_io_set_encoding(1, &val, rb_stderr);
13550}
13551
13552static inline int
13553global_argf_p(VALUE arg)
13554{
13555 return arg == argf;
13556}
13557
13558typedef VALUE (*argf_encoding_func)(VALUE io);
13559
13560static VALUE
13561argf_encoding(VALUE argf, argf_encoding_func func)
13562{
13563 if (!RTEST(ARGF.current_file)) {
13564 return rb_enc_default_external();
13565 }
13566 return func(rb_io_check_io(ARGF.current_file));
13567}
13568
13569/*
13570 * call-seq:
13571 * ARGF.external_encoding -> encoding
13572 *
13573 * Returns the external encoding for files read from ARGF as an Encoding
13574 * object. The external encoding is the encoding of the text as stored in a
13575 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13576 * represent this text within Ruby.
13577 *
13578 * To set the external encoding use ARGF.set_encoding.
13579 *
13580 * For example:
13581 *
13582 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13583 *
13584 */
13585static VALUE
13586argf_external_encoding(VALUE argf)
13587{
13588 return argf_encoding(argf, rb_io_external_encoding);
13589}
13590
13591/*
13592 * call-seq:
13593 * ARGF.internal_encoding -> encoding
13594 *
13595 * Returns the internal encoding for strings read from ARGF as an
13596 * Encoding object.
13597 *
13598 * If ARGF.set_encoding has been called with two encoding names, the second
13599 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13600 * value is returned. Failing that, if a default external encoding was
13601 * specified on the command-line, that value is used. If the encoding is
13602 * unknown, +nil+ is returned.
13603 */
13604static VALUE
13605argf_internal_encoding(VALUE argf)
13606{
13607 return argf_encoding(argf, rb_io_internal_encoding);
13608}
13609
13610/*
13611 * call-seq:
13612 * ARGF.set_encoding(ext_enc) -> ARGF
13613 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13614 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13615 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13616 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13617 *
13618 * If single argument is specified, strings read from ARGF are tagged with
13619 * the encoding specified.
13620 *
13621 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13622 * the read string is converted from the first encoding (external encoding)
13623 * to the second encoding (internal encoding), then tagged with the second
13624 * encoding.
13625 *
13626 * If two arguments are specified, they must be encoding objects or encoding
13627 * names. Again, the first specifies the external encoding; the second
13628 * specifies the internal encoding.
13629 *
13630 * If the external encoding and the internal encoding are specified, the
13631 * optional Hash argument can be used to adjust the conversion process. The
13632 * structure of this hash is explained in the String#encode documentation.
13633 *
13634 * For example:
13635 *
13636 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13637 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13638 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13639 * # to UTF-8.
13640 */
13641static VALUE
13642argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13643{
13644 rb_io_t *fptr;
13645
13646 if (!next_argv()) {
13647 rb_raise(rb_eArgError, "no stream to set encoding");
13648 }
13649 rb_io_set_encoding(argc, argv, ARGF.current_file);
13650 GetOpenFile(ARGF.current_file, fptr);
13651 ARGF.encs = fptr->encs;
13652 return argf;
13653}
13654
13655/*
13656 * call-seq:
13657 * ARGF.tell -> Integer
13658 * ARGF.pos -> Integer
13659 *
13660 * Returns the current offset (in bytes) of the current file in ARGF.
13661 *
13662 * ARGF.pos #=> 0
13663 * ARGF.gets #=> "This is line one\n"
13664 * ARGF.pos #=> 17
13665 *
13666 */
13667static VALUE
13668argf_tell(VALUE argf)
13669{
13670 if (!next_argv()) {
13671 rb_raise(rb_eArgError, "no stream to tell");
13672 }
13673 ARGF_FORWARD(0, 0);
13674 return rb_io_tell(ARGF.current_file);
13675}
13676
13677/*
13678 * call-seq:
13679 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13680 *
13681 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13682 * the value of _whence_. See IO#seek for further details.
13683 */
13684static VALUE
13685argf_seek_m(int argc, VALUE *argv, VALUE argf)
13686{
13687 if (!next_argv()) {
13688 rb_raise(rb_eArgError, "no stream to seek");
13689 }
13690 ARGF_FORWARD(argc, argv);
13691 return rb_io_seek_m(argc, argv, ARGF.current_file);
13692}
13693
13694/*
13695 * call-seq:
13696 * ARGF.pos = position -> Integer
13697 *
13698 * Seeks to the position given by _position_ (in bytes) in ARGF.
13699 *
13700 * For example:
13701 *
13702 * ARGF.pos = 17
13703 * ARGF.gets #=> "This is line two\n"
13704 */
13705static VALUE
13706argf_set_pos(VALUE argf, VALUE offset)
13707{
13708 if (!next_argv()) {
13709 rb_raise(rb_eArgError, "no stream to set position");
13710 }
13711 ARGF_FORWARD(1, &offset);
13712 return rb_io_set_pos(ARGF.current_file, offset);
13713}
13714
13715/*
13716 * call-seq:
13717 * ARGF.rewind -> 0
13718 *
13719 * Positions the current file to the beginning of input, resetting
13720 * ARGF.lineno to zero.
13721 *
13722 * ARGF.readline #=> "This is line one\n"
13723 * ARGF.rewind #=> 0
13724 * ARGF.lineno #=> 0
13725 * ARGF.readline #=> "This is line one\n"
13726 */
13727static VALUE
13728argf_rewind(VALUE argf)
13729{
13730 VALUE ret;
13731 int old_lineno;
13732
13733 if (!next_argv()) {
13734 rb_raise(rb_eArgError, "no stream to rewind");
13735 }
13736 ARGF_FORWARD(0, 0);
13737 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13738 ret = rb_io_rewind(ARGF.current_file);
13739 if (!global_argf_p(argf)) {
13740 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13741 }
13742 return ret;
13743}
13744
13745/*
13746 * call-seq:
13747 * ARGF.fileno -> integer
13748 * ARGF.to_i -> integer
13749 *
13750 * Returns an integer representing the numeric file descriptor for
13751 * the current file. Raises an ArgumentError if there isn't a current file.
13752 *
13753 * ARGF.fileno #=> 3
13754 */
13755static VALUE
13756argf_fileno(VALUE argf)
13757{
13758 if (!next_argv()) {
13759 rb_raise(rb_eArgError, "no stream");
13760 }
13761 ARGF_FORWARD(0, 0);
13762 return rb_io_fileno(ARGF.current_file);
13763}
13764
13765/*
13766 * call-seq:
13767 * ARGF.to_io -> IO
13768 *
13769 * Returns an IO object representing the current file. This will be a
13770 * File object unless the current file is a stream such as STDIN.
13771 *
13772 * For example:
13773 *
13774 * ARGF.to_io #=> #<File:glark.txt>
13775 * ARGF.to_io #=> #<IO:<STDIN>>
13776 */
13777static VALUE
13778argf_to_io(VALUE argf)
13779{
13780 next_argv();
13781 ARGF_FORWARD(0, 0);
13782 return ARGF.current_file;
13783}
13784
13785/*
13786 * call-seq:
13787 * ARGF.eof? -> true or false
13788 * ARGF.eof -> true or false
13789 *
13790 * Returns true if the current file in ARGF is at end of file, i.e. it has
13791 * no data to read. The stream must be opened for reading or an IOError
13792 * will be raised.
13793 *
13794 * $ echo "eof" | ruby argf.rb
13795 *
13796 * ARGF.eof? #=> false
13797 * 3.times { ARGF.readchar }
13798 * ARGF.eof? #=> false
13799 * ARGF.readchar #=> "\n"
13800 * ARGF.eof? #=> true
13801 */
13802
13803static VALUE
13804argf_eof(VALUE argf)
13805{
13806 next_argv();
13807 if (RTEST(ARGF.current_file)) {
13808 if (ARGF.init_p == 0) return Qtrue;
13809 next_argv();
13810 ARGF_FORWARD(0, 0);
13811 if (rb_io_eof(ARGF.current_file)) {
13812 return Qtrue;
13813 }
13814 }
13815 return Qfalse;
13816}
13817
13818/*
13819 * call-seq:
13820 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13821 *
13822 * Reads _length_ bytes from ARGF. The files named on the command line
13823 * are concatenated and treated as a single file by this method, so when
13824 * called without arguments the contents of this pseudo file are returned in
13825 * their entirety.
13826 *
13827 * _length_ must be a non-negative integer or +nil+.
13828 *
13829 * If _length_ is a positive integer, +read+ tries to read
13830 * _length_ bytes without any conversion (binary mode).
13831 * It returns +nil+ if an EOF is encountered before anything can be read.
13832 * Fewer than _length_ bytes are returned if an EOF is encountered during
13833 * the read.
13834 * In the case of an integer _length_, the resulting string is always
13835 * in ASCII-8BIT encoding.
13836 *
13837 * If _length_ is omitted or is +nil+, it reads until EOF
13838 * and the encoding conversion is applied, if applicable.
13839 * A string is returned even if EOF is encountered before any data is read.
13840 *
13841 * If _length_ is zero, it returns an empty string (<code>""</code>).
13842 *
13843 * If the optional _outbuf_ argument is present,
13844 * it must reference a String, which will receive the data.
13845 * The _outbuf_ will contain only the received data after the method call
13846 * even if it is not empty at the beginning.
13847 *
13848 * For example:
13849 *
13850 * $ echo "small" > small.txt
13851 * $ echo "large" > large.txt
13852 * $ ./glark.rb small.txt large.txt
13853 *
13854 * ARGF.read #=> "small\nlarge"
13855 * ARGF.read(200) #=> "small\nlarge"
13856 * ARGF.read(2) #=> "sm"
13857 * ARGF.read(0) #=> ""
13858 *
13859 * Note that this method behaves like the fread() function in C.
13860 * This means it retries to invoke read(2) system calls to read data
13861 * with the specified length.
13862 * If you need the behavior like a single read(2) system call,
13863 * consider ARGF#readpartial or ARGF#read_nonblock.
13864 */
13865
13866static VALUE
13867argf_read(int argc, VALUE *argv, VALUE argf)
13868{
13869 VALUE tmp, str, length;
13870 long len = 0;
13871
13872 rb_scan_args(argc, argv, "02", &length, &str);
13873 if (!NIL_P(length)) {
13874 len = NUM2LONG(argv[0]);
13875 }
13876 if (!NIL_P(str)) {
13877 StringValue(str);
13878 rb_str_resize(str,0);
13879 argv[1] = Qnil;
13880 }
13881
13882 retry:
13883 if (!next_argv()) {
13884 return str;
13885 }
13886 if (ARGF_GENERIC_INPUT_P()) {
13887 tmp = argf_forward(argc, argv, argf);
13888 }
13889 else {
13890 tmp = io_read(argc, argv, ARGF.current_file);
13891 }
13892 if (NIL_P(str)) str = tmp;
13893 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13894 if (NIL_P(tmp) || NIL_P(length)) {
13895 if (ARGF.next_p != -1) {
13896 argf_close(argf);
13897 ARGF.next_p = 1;
13898 goto retry;
13899 }
13900 }
13901 else if (argc >= 1) {
13902 long slen = RSTRING_LEN(str);
13903 if (slen < len) {
13904 argv[0] = LONG2NUM(len - slen);
13905 goto retry;
13906 }
13907 }
13908 return str;
13909}
13910
13911 struct argf_call_arg {
13912 int argc;
13913 VALUE *argv;
13914 VALUE argf;
13915};
13916
13917static VALUE
13918argf_forward_call(VALUE arg)
13919{
13920 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13921 argf_forward(p->argc, p->argv, p->argf);
13922 return Qnil;
13923}
13924
13925static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13926 int nonblock);
13927
13928/*
13929 * call-seq:
13930 * ARGF.readpartial(maxlen) -> string
13931 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13932 *
13933 * Reads at most _maxlen_ bytes from the ARGF stream.
13934 *
13935 * If the optional _outbuf_ argument is present,
13936 * it must reference a String, which will receive the data.
13937 * The _outbuf_ will contain only the received data after the method call
13938 * even if it is not empty at the beginning.
13939 *
13940 * It raises EOFError on end of ARGF stream.
13941 * Since ARGF stream is a concatenation of multiple files,
13942 * internally EOF is occur for each file.
13943 * ARGF.readpartial returns empty strings for EOFs except the last one and
13944 * raises EOFError for the last one.
13945 *
13946 */
13947
13948static VALUE
13949argf_readpartial(int argc, VALUE *argv, VALUE argf)
13950{
13951 return argf_getpartial(argc, argv, argf, Qnil, 0);
13952}
13953
13954/*
13955 * call-seq:
13956 * ARGF.read_nonblock(maxlen[, options]) -> string
13957 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13958 *
13959 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13960 */
13961
13962static VALUE
13963argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13964{
13965 VALUE opts;
13966
13967 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13968
13969 if (!NIL_P(opts))
13970 argc--;
13971
13972 return argf_getpartial(argc, argv, argf, opts, 1);
13973}
13974
13975static VALUE
13976argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13977{
13978 VALUE tmp, str, length;
13979 int no_exception;
13980
13981 rb_scan_args(argc, argv, "11", &length, &str);
13982 if (!NIL_P(str)) {
13983 StringValue(str);
13984 argv[1] = str;
13985 }
13986 no_exception = no_exception_p(opts);
13987
13988 if (!next_argv()) {
13989 if (!NIL_P(str)) {
13990 rb_str_resize(str, 0);
13991 }
13992 rb_eof_error();
13993 }
13994 if (ARGF_GENERIC_INPUT_P()) {
13995 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13996 struct argf_call_arg arg;
13997 arg.argc = argc;
13998 arg.argv = argv;
13999 arg.argf = argf;
14000 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14001 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14002 }
14003 else {
14004 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14005 }
14006 if (NIL_P(tmp)) {
14007 if (ARGF.next_p == -1) {
14008 return io_nonblock_eof(no_exception);
14009 }
14010 argf_close(argf);
14011 ARGF.next_p = 1;
14012 if (RARRAY_LEN(ARGF.argv) == 0) {
14013 return io_nonblock_eof(no_exception);
14014 }
14015 if (NIL_P(str))
14016 str = rb_str_new(NULL, 0);
14017 return str;
14018 }
14019 return tmp;
14020}
14021
14022/*
14023 * call-seq:
14024 * ARGF.getc -> String or nil
14025 *
14026 * Reads the next character from ARGF and returns it as a String. Returns
14027 * +nil+ at the end of the stream.
14028 *
14029 * ARGF treats the files named on the command line as a single file created
14030 * by concatenating their contents. After returning the last character of the
14031 * first file, it returns the first character of the second file, and so on.
14032 *
14033 * For example:
14034 *
14035 * $ echo "foo" > file
14036 * $ ruby argf.rb file
14037 *
14038 * ARGF.getc #=> "f"
14039 * ARGF.getc #=> "o"
14040 * ARGF.getc #=> "o"
14041 * ARGF.getc #=> "\n"
14042 * ARGF.getc #=> nil
14043 * ARGF.getc #=> nil
14044 */
14045static VALUE
14046argf_getc(VALUE argf)
14047{
14048 VALUE ch;
14049
14050 retry:
14051 if (!next_argv()) return Qnil;
14052 if (ARGF_GENERIC_INPUT_P()) {
14053 ch = forward_current(rb_intern("getc"), 0, 0);
14054 }
14055 else {
14056 ch = rb_io_getc(ARGF.current_file);
14057 }
14058 if (NIL_P(ch) && ARGF.next_p != -1) {
14059 argf_close(argf);
14060 ARGF.next_p = 1;
14061 goto retry;
14062 }
14063
14064 return ch;
14065}
14066
14067/*
14068 * call-seq:
14069 * ARGF.getbyte -> Integer or nil
14070 *
14071 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14072 * the end of the stream.
14073 *
14074 * For example:
14075 *
14076 * $ echo "foo" > file
14077 * $ ruby argf.rb file
14078 *
14079 * ARGF.getbyte #=> 102
14080 * ARGF.getbyte #=> 111
14081 * ARGF.getbyte #=> 111
14082 * ARGF.getbyte #=> 10
14083 * ARGF.getbyte #=> nil
14084 */
14085static VALUE
14086argf_getbyte(VALUE argf)
14087{
14088 VALUE ch;
14089
14090 retry:
14091 if (!next_argv()) return Qnil;
14092 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14093 ch = forward_current(rb_intern("getbyte"), 0, 0);
14094 }
14095 else {
14096 ch = rb_io_getbyte(ARGF.current_file);
14097 }
14098 if (NIL_P(ch) && ARGF.next_p != -1) {
14099 argf_close(argf);
14100 ARGF.next_p = 1;
14101 goto retry;
14102 }
14103
14104 return ch;
14105}
14106
14107/*
14108 * call-seq:
14109 * ARGF.readchar -> String or nil
14110 *
14111 * Reads the next character from ARGF and returns it as a String. Raises
14112 * an EOFError after the last character of the last file has been read.
14113 *
14114 * For example:
14115 *
14116 * $ echo "foo" > file
14117 * $ ruby argf.rb file
14118 *
14119 * ARGF.readchar #=> "f"
14120 * ARGF.readchar #=> "o"
14121 * ARGF.readchar #=> "o"
14122 * ARGF.readchar #=> "\n"
14123 * ARGF.readchar #=> end of file reached (EOFError)
14124 */
14125static VALUE
14126argf_readchar(VALUE argf)
14127{
14128 VALUE ch;
14129
14130 retry:
14131 if (!next_argv()) rb_eof_error();
14132 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14133 ch = forward_current(rb_intern("getc"), 0, 0);
14134 }
14135 else {
14136 ch = rb_io_getc(ARGF.current_file);
14137 }
14138 if (NIL_P(ch) && ARGF.next_p != -1) {
14139 argf_close(argf);
14140 ARGF.next_p = 1;
14141 goto retry;
14142 }
14143
14144 return ch;
14145}
14146
14147/*
14148 * call-seq:
14149 * ARGF.readbyte -> Integer
14150 *
14151 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14152 * an EOFError after the last byte of the last file has been read.
14153 *
14154 * For example:
14155 *
14156 * $ echo "foo" > file
14157 * $ ruby argf.rb file
14158 *
14159 * ARGF.readbyte #=> 102
14160 * ARGF.readbyte #=> 111
14161 * ARGF.readbyte #=> 111
14162 * ARGF.readbyte #=> 10
14163 * ARGF.readbyte #=> end of file reached (EOFError)
14164 */
14165static VALUE
14166argf_readbyte(VALUE argf)
14167{
14168 VALUE c;
14169
14170 NEXT_ARGF_FORWARD(0, 0);
14171 c = argf_getbyte(argf);
14172 if (NIL_P(c)) {
14173 rb_eof_error();
14174 }
14175 return c;
14176}
14177
14178#define FOREACH_ARGF() while (next_argv())
14179
14180static VALUE
14181argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14182{
14183 const VALUE current = ARGF.current_file;
14184 rb_yield_values2(argc, argv);
14185 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14186 rb_iter_break_value(Qundef);
14187 }
14188 return Qnil;
14189}
14190
14191#define ARGF_block_call(mid, argc, argv, func, argf) \
14192 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14193 func, argf, rb_keyword_given_p())
14194
14195static void
14196argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14197{
14198 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14199 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14200}
14201
14202static VALUE
14203argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14204{
14205 if (!global_argf_p(argf)) {
14206 ARGF.last_lineno = ++ARGF.lineno;
14207 }
14208 return argf_block_call_i(i, argf, argc, argv, blockarg);
14209}
14210
14211static void
14212argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14213{
14214 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14215 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14216}
14217
14218/*
14219 * call-seq:
14220 * ARGF.each(sep=$/) {|line| block } -> ARGF
14221 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14222 * ARGF.each(...) -> an_enumerator
14223 *
14224 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14225 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14226 * ARGF.each_line(...) -> an_enumerator
14227 *
14228 * Returns an enumerator which iterates over each line (separated by _sep_,
14229 * which defaults to your platform's newline character) of each file in
14230 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14231 * block, otherwise an enumerator is returned.
14232 * The optional _limit_ argument is an Integer specifying the maximum
14233 * length of each line; longer lines will be split according to this limit.
14234 *
14235 * This method allows you to treat the files supplied on the command line as
14236 * a single file consisting of the concatenation of each named file. After
14237 * the last line of the first file has been returned, the first line of the
14238 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14239 * used to determine the filename of the current line and line number of the
14240 * whole input, respectively.
14241 *
14242 * For example, the following code prints out each line of each named file
14243 * prefixed with its line number, displaying the filename once per file:
14244 *
14245 * ARGF.each_line do |line|
14246 * puts ARGF.filename if ARGF.file.lineno == 1
14247 * puts "#{ARGF.file.lineno}: #{line}"
14248 * end
14249 *
14250 * While the following code prints only the first file's name at first, and
14251 * the contents with line number counted through all named files.
14252 *
14253 * ARGF.each_line do |line|
14254 * puts ARGF.filename if ARGF.lineno == 1
14255 * puts "#{ARGF.lineno}: #{line}"
14256 * end
14257 */
14258static VALUE
14259argf_each_line(int argc, VALUE *argv, VALUE argf)
14260{
14261 RETURN_ENUMERATOR(argf, argc, argv);
14262 FOREACH_ARGF() {
14263 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14264 }
14265 return argf;
14266}
14267
14268/*
14269 * call-seq:
14270 * ARGF.each_byte {|byte| block } -> ARGF
14271 * ARGF.each_byte -> an_enumerator
14272 *
14273 * Iterates over each byte of each file in +ARGV+.
14274 * A byte is returned as an Integer in the range 0..255.
14275 *
14276 * This method allows you to treat the files supplied on the command line as
14277 * a single file consisting of the concatenation of each named file. After
14278 * the last byte of the first file has been returned, the first byte of the
14279 * second file is returned. The ARGF.filename method can be used to
14280 * determine the filename of the current byte.
14281 *
14282 * If no block is given, an enumerator is returned instead.
14283 *
14284 * For example:
14285 *
14286 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14287 *
14288 */
14289static VALUE
14290argf_each_byte(VALUE argf)
14291{
14292 RETURN_ENUMERATOR(argf, 0, 0);
14293 FOREACH_ARGF() {
14294 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14295 }
14296 return argf;
14297}
14298
14299/*
14300 * call-seq:
14301 * ARGF.each_char {|char| block } -> ARGF
14302 * ARGF.each_char -> an_enumerator
14303 *
14304 * Iterates over each character of each file in ARGF.
14305 *
14306 * This method allows you to treat the files supplied on the command line as
14307 * a single file consisting of the concatenation of each named file. After
14308 * the last character of the first file has been returned, the first
14309 * character of the second file is returned. The ARGF.filename method can
14310 * be used to determine the name of the file in which the current character
14311 * appears.
14312 *
14313 * If no block is given, an enumerator is returned instead.
14314 */
14315static VALUE
14316argf_each_char(VALUE argf)
14317{
14318 RETURN_ENUMERATOR(argf, 0, 0);
14319 FOREACH_ARGF() {
14320 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14321 }
14322 return argf;
14323}
14324
14325/*
14326 * call-seq:
14327 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14328 * ARGF.each_codepoint -> an_enumerator
14329 *
14330 * Iterates over each codepoint of each file in ARGF.
14331 *
14332 * This method allows you to treat the files supplied on the command line as
14333 * a single file consisting of the concatenation of each named file. After
14334 * the last codepoint of the first file has been returned, the first
14335 * codepoint of the second file is returned. The ARGF.filename method can
14336 * be used to determine the name of the file in which the current codepoint
14337 * appears.
14338 *
14339 * If no block is given, an enumerator is returned instead.
14340 */
14341static VALUE
14342argf_each_codepoint(VALUE argf)
14343{
14344 RETURN_ENUMERATOR(argf, 0, 0);
14345 FOREACH_ARGF() {
14346 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14347 }
14348 return argf;
14349}
14350
14351/*
14352 * call-seq:
14353 * ARGF.filename -> String
14354 * ARGF.path -> String
14355 *
14356 * Returns the current filename. "-" is returned when the current file is
14357 * STDIN.
14358 *
14359 * For example:
14360 *
14361 * $ echo "foo" > foo
14362 * $ echo "bar" > bar
14363 * $ echo "glark" > glark
14364 *
14365 * $ ruby argf.rb foo bar glark
14366 *
14367 * ARGF.filename #=> "foo"
14368 * ARGF.read(5) #=> "foo\nb"
14369 * ARGF.filename #=> "bar"
14370 * ARGF.skip
14371 * ARGF.filename #=> "glark"
14372 */
14373static VALUE
14374argf_filename(VALUE argf)
14375{
14376 next_argv();
14377 return ARGF.filename;
14378}
14379
14380static VALUE
14381argf_filename_getter(ID id, VALUE *var)
14382{
14383 return argf_filename(*var);
14384}
14385
14386/*
14387 * call-seq:
14388 * ARGF.file -> IO or File object
14389 *
14390 * Returns the current file as an IO or File object.
14391 * <code>$stdin</code> is returned when the current file is STDIN.
14392 *
14393 * For example:
14394 *
14395 * $ echo "foo" > foo
14396 * $ echo "bar" > bar
14397 *
14398 * $ ruby argf.rb foo bar
14399 *
14400 * ARGF.file #=> #<File:foo>
14401 * ARGF.read(5) #=> "foo\nb"
14402 * ARGF.file #=> #<File:bar>
14403 */
14404static VALUE
14405argf_file(VALUE argf)
14406{
14407 next_argv();
14408 return ARGF.current_file;
14409}
14410
14411/*
14412 * call-seq:
14413 * ARGF.binmode -> ARGF
14414 *
14415 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14416 * be reset to non-binary mode. This option has the following effects:
14417 *
14418 * * Newline conversion is disabled.
14419 * * Encoding conversion is disabled.
14420 * * Content is treated as ASCII-8BIT.
14421 */
14422static VALUE
14423argf_binmode_m(VALUE argf)
14424{
14425 ARGF.binmode = 1;
14426 next_argv();
14427 ARGF_FORWARD(0, 0);
14428 rb_io_ascii8bit_binmode(ARGF.current_file);
14429 return argf;
14430}
14431
14432/*
14433 * call-seq:
14434 * ARGF.binmode? -> true or false
14435 *
14436 * Returns true if ARGF is being read in binary mode; false otherwise.
14437 * To enable binary mode use ARGF.binmode.
14438 *
14439 * For example:
14440 *
14441 * ARGF.binmode? #=> false
14442 * ARGF.binmode
14443 * ARGF.binmode? #=> true
14444 */
14445static VALUE
14446argf_binmode_p(VALUE argf)
14447{
14448 return RBOOL(ARGF.binmode);
14449}
14450
14451/*
14452 * call-seq:
14453 * ARGF.skip -> ARGF
14454 *
14455 * Sets the current file to the next file in ARGV. If there aren't any more
14456 * files it has no effect.
14457 *
14458 * For example:
14459 *
14460 * $ ruby argf.rb foo bar
14461 * ARGF.filename #=> "foo"
14462 * ARGF.skip
14463 * ARGF.filename #=> "bar"
14464 */
14465static VALUE
14466argf_skip(VALUE argf)
14467{
14468 if (ARGF.init_p && ARGF.next_p == 0) {
14469 argf_close(argf);
14470 ARGF.next_p = 1;
14471 }
14472 return argf;
14473}
14474
14475/*
14476 * call-seq:
14477 * ARGF.close -> ARGF
14478 *
14479 * Closes the current file and skips to the next file in ARGV. If there are
14480 * no more files to open, just closes the current file. STDIN will not be
14481 * closed.
14482 *
14483 * For example:
14484 *
14485 * $ ruby argf.rb foo bar
14486 *
14487 * ARGF.filename #=> "foo"
14488 * ARGF.close
14489 * ARGF.filename #=> "bar"
14490 * ARGF.close
14491 */
14492static VALUE
14493argf_close_m(VALUE argf)
14494{
14495 next_argv();
14496 argf_close(argf);
14497 if (ARGF.next_p != -1) {
14498 ARGF.next_p = 1;
14499 }
14500 ARGF.lineno = 0;
14501 return argf;
14502}
14503
14504/*
14505 * call-seq:
14506 * ARGF.closed? -> true or false
14507 *
14508 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14509 * ARGF.close to actually close the current file.
14510 */
14511static VALUE
14512argf_closed(VALUE argf)
14513{
14514 next_argv();
14515 ARGF_FORWARD(0, 0);
14516 return rb_io_closed_p(ARGF.current_file);
14517}
14518
14519/*
14520 * call-seq:
14521 * ARGF.to_s -> String
14522 *
14523 * Returns "ARGF".
14524 */
14525static VALUE
14526argf_to_s(VALUE argf)
14527{
14528 return rb_str_new2("ARGF");
14529}
14530
14531/*
14532 * call-seq:
14533 * ARGF.inplace_mode -> String
14534 *
14535 * Returns the file extension appended to the names of backup copies of
14536 * modified files under in-place edit mode. This value can be set using
14537 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14538 */
14539static VALUE
14540argf_inplace_mode_get(VALUE argf)
14541{
14542 if (!ARGF.inplace) return Qnil;
14543 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14544 return rb_str_dup(ARGF.inplace);
14545}
14546
14547static VALUE
14548opt_i_get(ID id, VALUE *var)
14549{
14550 return argf_inplace_mode_get(*var);
14551}
14552
14553/*
14554 * call-seq:
14555 * ARGF.inplace_mode = ext -> ARGF
14556 *
14557 * Sets the filename extension for in-place editing mode to the given String.
14558 * The backup copy of each file being edited has this value appended to its
14559 * filename.
14560 *
14561 * For example:
14562 *
14563 * $ ruby argf.rb file.txt
14564 *
14565 * ARGF.inplace_mode = '.bak'
14566 * ARGF.each_line do |line|
14567 * print line.sub("foo","bar")
14568 * end
14569 *
14570 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14571 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14572 * "bar".
14573 */
14574static VALUE
14575argf_inplace_mode_set(VALUE argf, VALUE val)
14576{
14577 if (!RTEST(val)) {
14578 ARGF.inplace = Qfalse;
14579 }
14580 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14581 ARGF.inplace = Qnil;
14582 }
14583 else {
14584 ARGF.inplace = rb_str_new_frozen(val);
14585 }
14586 return argf;
14587}
14588
14589static void
14590opt_i_set(VALUE val, ID id, VALUE *var)
14591{
14592 argf_inplace_mode_set(*var, val);
14593}
14594
14595void
14596ruby_set_inplace_mode(const char *suffix)
14597{
14598 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14599}
14600
14601/*
14602 * call-seq:
14603 * ARGF.argv -> ARGV
14604 *
14605 * Returns the +ARGV+ array, which contains the arguments passed to your
14606 * script, one per element.
14607 *
14608 * For example:
14609 *
14610 * $ ruby argf.rb -v glark.txt
14611 *
14612 * ARGF.argv #=> ["-v", "glark.txt"]
14613 *
14614 */
14615static VALUE
14616argf_argv(VALUE argf)
14617{
14618 return ARGF.argv;
14619}
14620
14621static VALUE
14622argf_argv_getter(ID id, VALUE *var)
14623{
14624 return argf_argv(*var);
14625}
14626
14627 VALUE
14628rb_get_argv(void)
14629{
14630 return ARGF.argv;
14631}
14632
14633/*
14634 * call-seq:
14635 * ARGF.to_write_io -> io
14636 *
14637 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14638 * enabled.
14639 */
14640static VALUE
14641argf_write_io(VALUE argf)
14642{
14643 if (!RTEST(ARGF.current_file)) {
14644 rb_raise(rb_eIOError, "not opened for writing");
14645 }
14646 return GetWriteIO(ARGF.current_file);
14647}
14648
14649/*
14650 * call-seq:
14651 * ARGF.write(*objects) -> integer
14652 *
14653 * Writes each of the given +objects+ if inplace mode.
14654 */
14655static VALUE
14656argf_write(int argc, VALUE *argv, VALUE argf)
14657{
14658 return rb_io_writev(argf_write_io(argf), argc, argv);
14659}
14660
14661void
14662rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14663{
14664 rb_readwrite_syserr_fail(waiting, errno, mesg);
14665}
14666
14667void
14668rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14669{
14670 VALUE arg, c = Qnil;
14671 arg = mesg ? rb_str_new2(mesg) : Qnil;
14672 switch (waiting) {
14673 case RB_IO_WAIT_WRITABLE:
14674 switch (n) {
14675 case EAGAIN:
14676 c = rb_eEAGAINWaitWritable;
14677 break;
14678#if EAGAIN != EWOULDBLOCK
14679 case EWOULDBLOCK:
14680 c = rb_eEWOULDBLOCKWaitWritable;
14681 break;
14682#endif
14683 case EINPROGRESS:
14684 c = rb_eEINPROGRESSWaitWritable;
14685 break;
14686 default:
14687 rb_mod_syserr_fail_str(rb_mWaitWritable, n, arg);
14688 }
14689 break;
14690 case RB_IO_WAIT_READABLE:
14691 switch (n) {
14692 case EAGAIN:
14693 c = rb_eEAGAINWaitReadable;
14694 break;
14695#if EAGAIN != EWOULDBLOCK
14696 case EWOULDBLOCK:
14697 c = rb_eEWOULDBLOCKWaitReadable;
14698 break;
14699#endif
14700 case EINPROGRESS:
14701 c = rb_eEINPROGRESSWaitReadable;
14702 break;
14703 default:
14704 rb_mod_syserr_fail_str(rb_mWaitReadable, n, arg);
14705 }
14706 break;
14707 default:
14708 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14709 }
14710 rb_exc_raise(rb_class_new_instance(1, &arg, c));
14711}
14712
14713static VALUE
14714get_LAST_READ_LINE(ID _x, VALUE *_y)
14715{
14716 return rb_lastline_get();
14717}
14718
14719static void
14720set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14721{
14722 rb_lastline_set(val);
14723}
14724
14725/*
14726 * Document-class: IOError
14727 *
14728 * Raised when an IO operation fails.
14729 *
14730 * File.open("/etc/hosts") {|f| f << "example"}
14731 * #=> IOError: not opened for writing
14732 *
14733 * File.open("/etc/hosts") {|f| f.close; f.read }
14734 * #=> IOError: closed stream
14735 *
14736 * Note that some IO failures raise <code>SystemCallError</code>s
14737 * and these are not subclasses of IOError:
14738 *
14739 * File.open("does/not/exist")
14740 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14741 */
14742
14743/*
14744 * Document-class: EOFError
14745 *
14746 * Raised by some IO operations when reaching the end of file. Many IO
14747 * methods exist in two forms,
14748 *
14749 * one that returns +nil+ when the end of file is reached, the other
14750 * raises EOFError.
14751 *
14752 * EOFError is a subclass of IOError.
14753 *
14754 * file = File.open("/etc/hosts")
14755 * file.read
14756 * file.gets #=> nil
14757 * file.readline #=> EOFError: end of file reached
14758 * file.close
14759 */
14760
14761/*
14762 * Document-class: ARGF
14763 *
14764 * == \ARGF and +ARGV+
14765 *
14766 * The \ARGF object works with the array at global variable +ARGV+
14767 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14768 *
14769 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14770 *
14771 * Initially, it contains the command-line arguments and options
14772 * that are passed to the Ruby program;
14773 * the program can modify that array as it likes.
14774 *
14775 * - **ARGF** may be thought of as the <b>argument files</b> object.
14776 *
14777 * It can access file streams and/or the <tt>$stdin</tt> stream,
14778 * based on what it finds in +ARGV+.
14779 * This provides a convenient way for the command line
14780 * to specify streams for a Ruby program to read.
14781 *
14782 * == Reading
14783 *
14784 * \ARGF may read from _source_ streams,
14785 * which at any particular time are determined by the content of +ARGV+.
14786 *
14787 * === Simplest Case
14788 *
14789 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14790 * the source is <tt>$stdin</tt>:
14791 *
14792 * - \File +t.rb+:
14793 *
14794 * p ['ARGV', ARGV]
14795 * p ['ARGF.read', ARGF.read]
14796 *
14797 * - Commands and outputs
14798 * (see below for the content of files +foo.txt+ and +bar.txt+):
14799 *
14800 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14801 * ["ARGV", []]
14802 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14803 *
14804 * $ cat foo.txt bar.txt | ruby t.rb
14805 * ["ARGV", []]
14806 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14807 *
14808 * === About the Examples
14809 *
14810 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14811 *
14812 * $ cat foo.txt
14813 * Foo 0
14814 * Foo 1
14815 * $ cat bar.txt
14816 * Bar 0
14817 * Bar 1
14818 * Bar 2
14819 * Bar 3
14820 *
14821 * === Sources in +ARGV+
14822 *
14823 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14824 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14825 * the sources are found in +ARGV+.
14826 *
14827 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14828 * and is one of:
14829 *
14830 * - The string path to a file that may be opened as a stream.
14831 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14832 *
14833 * Each element that is _not_ one of these
14834 * should be removed from +ARGV+ before \ARGF accesses that source.
14835 *
14836 * In the following example:
14837 *
14838 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14839 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14840 *
14841 * Example:
14842 *
14843 * - \File +t.rb+:
14844 *
14845 * # Print arguments (and options, if any) found on command line.
14846 * p ['ARGV', ARGV]
14847 *
14848 * - Command and output:
14849 *
14850 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14851 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14852 *
14853 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14854 *
14855 * - \File +t.rb+:
14856 *
14857 * p "ARGV: #{ARGV}"
14858 * p "Line: #{ARGF.read}" # Read everything from all specified streams.
14859 *
14860 * - Command and output:
14861 *
14862 * $ ruby t.rb foo.txt bar.txt
14863 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14864 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14865 *
14866 * Because the value at +ARGV+ is an ordinary array,
14867 * you can manipulate it to control which sources \ARGF considers:
14868 *
14869 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14870 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14871 *
14872 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14873 * when all sources have been accessed, the array is empty:
14874 *
14875 * - \File +t.rb+:
14876 *
14877 * until ARGV.empty? && ARGF.eof?
14878 * p "ARGV: #{ARGV}"
14879 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14880 * end
14881 *
14882 * - Command and output:
14883 *
14884 * $ ruby t.rb foo.txt bar.txt
14885 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14886 * "Line: Foo 0\n"
14887 * "ARGV: [\"bar.txt\"]"
14888 * "Line: Foo 1\n"
14889 * "ARGV: [\"bar.txt\"]"
14890 * "Line: Bar 0\n"
14891 * "ARGV: []"
14892 * "Line: Bar 1\n"
14893 * "ARGV: []"
14894 * "Line: Bar 2\n"
14895 * "ARGV: []"
14896 * "Line: Bar 3\n"
14897 *
14898 * ==== Filepaths in +ARGV+
14899 *
14900 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14901 *
14902 * This program prints what it reads from files at the paths specified
14903 * on the command line:
14904 *
14905 * - \File +t.rb+:
14906 *
14907 * p ['ARGV', ARGV]
14908 * # Read and print all content from the specified sources.
14909 * p ['ARGF.read', ARGF.read]
14910 *
14911 * - Command and output:
14912 *
14913 * $ ruby t.rb foo.txt bar.txt
14914 * ["ARGV", [foo.txt, bar.txt]
14915 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14916 *
14917 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14918 *
14919 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14920 *
14921 * - \File +t.rb+:
14922 *
14923 * p ['ARGV', ARGV]
14924 * p ['ARGF.read', ARGF.read]
14925 *
14926 * - Command and output:
14927 *
14928 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14929 * ["ARGV", ["-"]]
14930 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14931 *
14932 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14933 * (exception:
14934 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14935 *
14936 * - Command and output:
14937 *
14938 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14939 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14940 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14941 *
14942 * ==== Mixtures and Repetitions in +ARGV+
14943 *
14944 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14945 * and character <tt>'-'</tt>, including repetitions.
14946 *
14947 * ==== Modifications to +ARGV+
14948 *
14949 * The running Ruby program may make any modifications to the +ARGV+ array;
14950 * the current value of +ARGV+ affects \ARGF reading.
14951 *
14952 * ==== Empty +ARGV+
14953 *
14954 * For an empty +ARGV+, an \ARGF read method either returns +nil+
14955 * or raises an exception, depending on the specific method.
14956 *
14957 * === More Read Methods
14958 *
14959 * As seen above, method ARGF#read reads the content of all sources
14960 * into a single string.
14961 * Other \ARGF methods provide other ways to access that content;
14962 * these include:
14963 *
14964 * - Byte access: #each_byte, #getbyte, #readbyte.
14965 * - Character access: #each_char, #getc, #readchar.
14966 * - Codepoint access: #each_codepoint.
14967 * - Line access: #each_line, #gets, #readline, #readlines.
14968 * - Source access: #read, #read_nonblock, #readpartial.
14969 *
14970 * === About \Enumerable
14971 *
14972 * \ARGF includes module Enumerable.
14973 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
14974 *
14975 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
14976 * _not_ from +ARGV+;
14977 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
14978 * not an array of the strings from +ARGV+:
14979 *
14980 * - \File +t.rb+:
14981 *
14982 * p ['ARGV', ARGV]
14983 * p ['ARGF.entries', ARGF.entries]
14984 *
14985 * - Command and output:
14986 *
14987 * $ ruby t.rb foo.txt bar.txt
14988 * ["ARGV", ["foo.txt", "bar.txt"]]
14989 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
14990 *
14991 * == Writing
14992 *
14993 * If <i>inplace mode</i> is in effect,
14994 * \ARGF may write to target streams,
14995 * which at any particular time are determined by the content of ARGV.
14996 *
14997 * Methods about inplace mode:
14998 *
14999 * - #inplace_mode
15000 * - #inplace_mode=
15001 * - #to_write_io
15002 *
15003 * Methods for writing:
15004 *
15005 * - #print
15006 * - #printf
15007 * - #putc
15008 * - #puts
15009 * - #write
15010 *
15011 */
15012
15013/*
15014 * An instance of class \IO (commonly called a _stream_)
15015 * represents an input/output stream in the underlying operating system.
15016 * \Class \IO is the basis for input and output in Ruby.
15017 *
15018 * \Class File is the only class in the Ruby core that is a subclass of \IO.
15019 * Some classes in the Ruby standard library are also subclasses of \IO;
15020 * these include TCPSocket and UDPSocket.
15021 *
15022 * The global constant ARGF (also accessible as <tt>$<</tt>)
15023 * provides an IO-like stream that allows access to all file paths
15024 * found in ARGV (or found in STDIN if ARGV is empty).
15025 * ARGF is not itself a subclass of \IO.
15026 *
15027 * \Class StringIO provides an IO-like stream that handles a String.
15028 * StringIO is not itself a subclass of \IO.
15029 *
15030 * Important objects based on \IO include:
15031 *
15032 * - $stdin.
15033 * - $stdout.
15034 * - $stderr.
15035 * - Instances of class File.
15036 *
15037 * An instance of \IO may be created using:
15038 *
15039 * - IO.new: returns a new \IO object for the given integer file descriptor.
15040 * - IO.open: passes a new \IO object to the given block.
15041 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15042 * of a newly-launched subprocess.
15043 * - Kernel#open: Returns a new \IO object connected to a given source:
15044 * stream, file, or subprocess.
15045 *
15046 * Like a File stream, an \IO stream has:
15047 *
15048 * - A read/write mode, which may be read-only, write-only, or read/write;
15049 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15050 * - A data mode, which may be text-only or binary;
15051 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15052 * - Internal and external encodings;
15053 * see {Encodings}[rdoc-ref:File@Encodings].
15054 *
15055 * And like other \IO streams, it has:
15056 *
15057 * - A position, which determines where in the stream the next
15058 * read or write is to occur;
15059 * see {Position}[rdoc-ref:IO@Position].
15060 * - A line number, which is a special, line-oriented, "position"
15061 * (different from the position mentioned above);
15062 * see {Line Number}[rdoc-ref:IO@Line+Number].
15063 *
15064 * == Extension <tt>io/console</tt>
15065 *
15066 * Extension <tt>io/console</tt> provides numerous methods
15067 * for interacting with the console;
15068 * requiring it adds numerous methods to class \IO.
15069 *
15070 * == Example Files
15071 *
15072 * Many examples here use these variables:
15073 *
15074 * :include: doc/examples/files.rdoc
15075 *
15076 * == Open Options
15077 *
15078 * A number of \IO methods accept optional keyword arguments
15079 * that determine how a new stream is to be opened:
15080 *
15081 * - +:mode+: Stream mode.
15082 * - +:flags+: Integer file open flags;
15083 * If +mode+ is also given, the two are bitwise-ORed.
15084 * - +:external_encoding+: External encoding for the stream.
15085 * - +:internal_encoding+: Internal encoding for the stream.
15086 * <tt>'-'</tt> is a synonym for the default internal encoding.
15087 * If the value is +nil+ no conversion occurs.
15088 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15089 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15090 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15091 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15092 * when the stream closes; otherwise it remains open.
15093 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15094 * #path method.
15095 *
15096 * Also available are the options offered in String#encode,
15097 * which may control conversion between external and internal encoding.
15098 *
15099 * == Basic \IO
15100 *
15101 * You can perform basic stream \IO with these methods,
15102 * which typically operate on multi-byte strings:
15103 *
15104 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15105 * - IO#write: Writes zero or more strings to the stream;
15106 * each given object that is not already a string is converted via +to_s+.
15107 *
15108 * === Position
15109 *
15110 * An \IO stream has a nonnegative integer _position_,
15111 * which is the byte offset at which the next read or write is to occur.
15112 * A new stream has position zero (and line number zero);
15113 * method +rewind+ resets the position (and line number) to zero.
15114 *
15115 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15116 * Encoding::Converter instances used for that \IO.
15117 *
15118 * The relevant methods:
15119 *
15120 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15121 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15122 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15123 * relative to a given position +whence+
15124 * (indicating the beginning, end, or current position).
15125 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15126 *
15127 * === Open and Closed Streams
15128 *
15129 * A new \IO stream may be open for reading, open for writing, or both.
15130 *
15131 * A stream is automatically closed when claimed by the garbage collector.
15132 *
15133 * Attempted reading or writing on a closed stream raises an exception.
15134 *
15135 * The relevant methods:
15136 *
15137 * - IO#close: Closes the stream for both reading and writing.
15138 * - IO#close_read: Closes the stream for reading.
15139 * - IO#close_write: Closes the stream for writing.
15140 * - IO#closed?: Returns whether the stream is closed.
15141 *
15142 * === End-of-Stream
15143 *
15144 * You can query whether a stream is positioned at its end:
15145 *
15146 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15147 *
15148 * You can reposition to end-of-stream by using method IO#seek:
15149 *
15150 * f = File.new('t.txt')
15151 * f.eof? # => false
15152 * f.seek(0, :END)
15153 * f.eof? # => true
15154 * f.close
15155 *
15156 * Or by reading all stream content (which is slower than using IO#seek):
15157 *
15158 * f.rewind
15159 * f.eof? # => false
15160 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15161 * f.eof? # => true
15162 *
15163 * == Line \IO
15164 *
15165 * \Class \IO supports line-oriented
15166 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15167 *
15168 * === Line Input
15169 *
15170 * \Class \IO supports line-oriented input for
15171 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15172 *
15173 * ==== \File Line Input
15174 *
15175 * You can read lines from a file using these methods:
15176 *
15177 * - IO.foreach: Reads each line and passes it to the given block.
15178 * - IO.readlines: Reads and returns all lines in an array.
15179 *
15180 * For each of these methods:
15181 *
15182 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15183 * - Line parsing depends on the effective <i>line separator</i>;
15184 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15185 * - The length of each returned line depends on the effective <i>line limit</i>;
15186 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15187 *
15188 * ==== Stream Line Input
15189 *
15190 * You can read lines from an \IO stream using these methods:
15191 *
15192 * - IO#each_line: Reads each remaining line, passing it to the given block.
15193 * - IO#gets: Returns the next line.
15194 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15195 * - IO#readlines: Returns all remaining lines in an array.
15196 *
15197 * For each of these methods:
15198 *
15199 * - Reading may begin mid-line,
15200 * depending on the stream's _position_;
15201 * see {Position}[rdoc-ref:IO@Position].
15202 * - Line parsing depends on the effective <i>line separator</i>;
15203 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15204 * - The length of each returned line depends on the effective <i>line limit</i>;
15205 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15206 *
15207 * ===== Line Separator
15208 *
15209 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15210 * the string that determines what is considered a line;
15211 * it is sometimes called the <i>input record separator</i>.
15212 *
15213 * The default line separator is taken from global variable <tt>$/</tt>,
15214 * whose initial value is <tt>"\n"</tt>.
15215 *
15216 * Generally, the line to be read next is all data
15217 * from the current {position}[rdoc-ref:IO@Position]
15218 * to the next line separator
15219 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15220 *
15221 * f = File.new('t.txt')
15222 * # Method gets with no sep argument returns the next line, according to $/.
15223 * f.gets # => "First line\n"
15224 * f.gets # => "Second line\n"
15225 * f.gets # => "\n"
15226 * f.gets # => "Fourth line\n"
15227 * f.gets # => "Fifth line\n"
15228 * f.close
15229 *
15230 * You can use a different line separator by passing argument +sep+:
15231 *
15232 * f = File.new('t.txt')
15233 * f.gets('l') # => "First l"
15234 * f.gets('li') # => "ine\nSecond li"
15235 * f.gets('lin') # => "ne\n\nFourth lin"
15236 * f.gets # => "e\n"
15237 * f.close
15238 *
15239 * Or by setting global variable <tt>$/</tt>:
15240 *
15241 * f = File.new('t.txt')
15242 * $/ = 'l'
15243 * f.gets # => "First l"
15244 * f.gets # => "ine\nSecond l"
15245 * f.gets # => "ine\n\nFourth l"
15246 * f.close
15247 *
15248 * ===== Special Line Separator Values
15249 *
15250 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15251 * accepts two special values for parameter +sep+:
15252 *
15253 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15254 *
15255 * f = File.new('t.txt')
15256 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15257 * f.close
15258 *
15259 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15260 * (paragraphs being separated by two consecutive line separators):
15261 *
15262 * f = File.new('t.txt')
15263 * f.gets('') # => "First line\nSecond line\n\n"
15264 * f.gets('') # => "Fourth line\nFifth line\n"
15265 * f.close
15266 *
15267 * ===== Line Limit
15268 *
15269 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15270 * uses an integer <i>line limit</i>,
15271 * which restricts the number of bytes that may be returned.
15272 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15273 * than the limit).
15274 *
15275 * The default limit value is <tt>-1</tt>;
15276 * any negative limit value means that there is no limit.
15277 *
15278 * If there is no limit, the line is determined only by +sep+.
15279 *
15280 * # Text with 1-byte characters.
15281 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15282 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15283 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15284 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15285 * # No more than one line.
15286 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15287 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15288 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15289 *
15290 * # Text with 2-byte characters, which will not be split.
15291 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15292 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15293 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15294 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15295 *
15296 * ===== Line Separator and Line Limit
15297 *
15298 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15299 *
15300 * - Returns the next line as determined by line separator +sep+.
15301 * - But returns no more bytes than are allowed by the limit +limit+.
15302 *
15303 * Example:
15304 *
15305 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15306 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15307 *
15308 * ===== Line Number
15309 *
15310 * A readable \IO stream has a non-negative integer <i>line number</i>:
15311 *
15312 * - IO#lineno: Returns the line number.
15313 * - IO#lineno=: Resets and returns the line number.
15314 *
15315 * Unless modified by a call to method IO#lineno=,
15316 * the line number is the number of lines read
15317 * by certain line-oriented methods,
15318 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15319 *
15320 * - IO.foreach: Increments the line number on each call to the block.
15321 * - IO#each_line: Increments the line number on each call to the block.
15322 * - IO#gets: Increments the line number.
15323 * - IO#readline: Increments the line number.
15324 * - IO#readlines: Increments the line number for each line read.
15325 *
15326 * A new stream is initially has line number zero (and position zero);
15327 * method +rewind+ resets the line number (and position) to zero:
15328 *
15329 * f = File.new('t.txt')
15330 * f.lineno # => 0
15331 * f.gets # => "First line\n"
15332 * f.lineno # => 1
15333 * f.rewind
15334 * f.lineno # => 0
15335 * f.close
15336 *
15337 * Reading lines from a stream usually changes its line number:
15338 *
15339 * f = File.new('t.txt', 'r')
15340 * f.lineno # => 0
15341 * f.readline # => "This is line one.\n"
15342 * f.lineno # => 1
15343 * f.readline # => "This is the second line.\n"
15344 * f.lineno # => 2
15345 * f.readline # => "Here's the third line.\n"
15346 * f.lineno # => 3
15347 * f.eof? # => true
15348 * f.close
15349 *
15350 * Iterating over lines in a stream usually changes its line number:
15351 *
15352 * File.open('t.txt') do |f|
15353 * f.each_line do |line|
15354 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15355 * end
15356 * end
15357 *
15358 * Output:
15359 *
15360 * "position=11 eof?=false lineno=1"
15361 * "position=23 eof?=false lineno=2"
15362 * "position=24 eof?=false lineno=3"
15363 * "position=36 eof?=false lineno=4"
15364 * "position=47 eof?=true lineno=5"
15365 *
15366 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15367 * the line number does not affect where the next read or write will occur:
15368 *
15369 * f = File.new('t.txt')
15370 * f.lineno = 1000
15371 * f.lineno # => 1000
15372 * f.gets # => "First line\n"
15373 * f.lineno # => 1001
15374 * f.close
15375 *
15376 * Associated with the line number is the global variable <tt>$.</tt>:
15377 *
15378 * - When a stream is opened, <tt>$.</tt> is not set;
15379 * its value is left over from previous activity in the process:
15380 *
15381 * $. = 41
15382 * f = File.new('t.txt')
15383 * $. = 41
15384 * # => 41
15385 * f.close
15386 *
15387 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15388 *
15389 * f0 = File.new('t.txt')
15390 * f1 = File.new('t.dat')
15391 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15392 * $. # => 5
15393 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15394 * $. # => 1
15395 * f0.close
15396 * f1.close
15397 *
15398 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15399 *
15400 * f = File.new('t.txt')
15401 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15402 * $. # => 5
15403 * f.rewind
15404 * f.seek(0, :SET)
15405 * $. # => 5
15406 * f.close
15407 *
15408 * === Line Output
15409 *
15410 * You can write to an \IO stream line-by-line using this method:
15411 *
15412 * - IO#puts: Writes objects to the stream.
15413 *
15414 * == Character \IO
15415 *
15416 * You can process an \IO stream character-by-character using these methods:
15417 *
15418 * - IO#getc: Reads and returns the next character from the stream.
15419 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15420 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15421 * - IO#putc: Writes a character to the stream.
15422 * - IO#each_char: Reads each remaining character in the stream,
15423 * passing the character to the given block.
15424 *
15425 * == Byte \IO
15426 *
15427 * You can process an \IO stream byte-by-byte using these methods:
15428 *
15429 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15430 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15431 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15432 * - IO#each_byte: Reads each remaining byte in the stream,
15433 * passing the byte to the given block.
15434 *
15435 * == Codepoint \IO
15436 *
15437 * You can process an \IO stream codepoint-by-codepoint:
15438 *
15439 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15440 *
15441 * == What's Here
15442 *
15443 * First, what's elsewhere. \Class \IO:
15444 *
15445 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15446 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15447 * which provides dozens of additional methods.
15448 *
15449 * Here, class \IO provides methods that are useful for:
15450 *
15451 * - {Creating}[rdoc-ref:IO@Creating]
15452 * - {Reading}[rdoc-ref:IO@Reading]
15453 * - {Writing}[rdoc-ref:IO@Writing]
15454 * - {Positioning}[rdoc-ref:IO@Positioning]
15455 * - {Iterating}[rdoc-ref:IO@Iterating]
15456 * - {Settings}[rdoc-ref:IO@Settings]
15457 * - {Querying}[rdoc-ref:IO@Querying]
15458 * - {Buffering}[rdoc-ref:IO@Buffering]
15459 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15460 * - {Other}[rdoc-ref:IO@Other]
15461 *
15462 * === Creating
15463 *
15464 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15465 * integer file descriptor.
15466 * - ::open: Creates a new \IO object.
15467 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15468 * - ::popen: Creates an \IO object to interact with a subprocess.
15469 * - ::select: Selects which given \IO instances are ready for reading,
15470 * writing, or have pending exceptions.
15471 *
15472 * === Reading
15473 *
15474 * - ::binread: Returns a binary string with all or a subset of bytes
15475 * from the given file.
15476 * - ::read: Returns a string with all or a subset of bytes from the given file.
15477 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15478 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15479 * - #getc: Returns the next character read from +self+ as a string.
15480 * - #gets: Returns the line read from +self+.
15481 * - #pread: Returns all or the next _n_ bytes read from +self+,
15482 * not updating the receiver's offset.
15483 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15484 * for a given _n_.
15485 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15486 * in non-block mode.
15487 * - #readbyte: Returns the next byte read from +self+;
15488 * same as #getbyte, but raises an exception on end-of-stream.
15489 * - #readchar: Returns the next character read from +self+;
15490 * same as #getc, but raises an exception on end-of-stream.
15491 * - #readline: Returns the next line read from +self+;
15492 * same as #getline, but raises an exception of end-of-stream.
15493 * - #readlines: Returns an array of all lines read read from +self+.
15494 * - #readpartial: Returns up to the given number of bytes from +self+.
15495 *
15496 * === Writing
15497 *
15498 * - ::binwrite: Writes the given string to the file at the given filepath,
15499 * in binary mode.
15500 * - ::write: Writes the given string to +self+.
15501 * - #<<: Appends the given string to +self+.
15502 * - #print: Prints last read line or given objects to +self+.
15503 * - #printf: Writes to +self+ based on the given format string and objects.
15504 * - #putc: Writes a character to +self+.
15505 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15506 * - #pwrite: Writes the given string at the given offset,
15507 * not updating the receiver's offset.
15508 * - #write: Writes one or more given strings to +self+.
15509 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15510 *
15511 * === Positioning
15512 *
15513 * - #lineno: Returns the current line number in +self+.
15514 * - #lineno=: Sets the line number is +self+.
15515 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15516 * - #pos=: Sets the byte offset in +self+.
15517 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15518 * - #rewind: Positions +self+ to the beginning of input.
15519 * - #seek: Sets the offset for +self+ relative to given position.
15520 *
15521 * === Iterating
15522 *
15523 * - ::foreach: Yields each line of given file to the block.
15524 * - #each (aliased as #each_line): Calls the given block
15525 * with each successive line in +self+.
15526 * - #each_byte: Calls the given block with each successive byte in +self+
15527 * as an integer.
15528 * - #each_char: Calls the given block with each successive character in +self+
15529 * as a string.
15530 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15531 * as an integer.
15532 *
15533 * === Settings
15534 *
15535 * - #autoclose=: Sets whether +self+ auto-closes.
15536 * - #binmode: Sets +self+ to binary mode.
15537 * - #close: Closes +self+.
15538 * - #close_on_exec=: Sets the close-on-exec flag.
15539 * - #close_read: Closes +self+ for reading.
15540 * - #close_write: Closes +self+ for writing.
15541 * - #set_encoding: Sets the encoding for +self+.
15542 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15543 * Unicode byte-order-mark.
15544 * - #sync=: Sets the sync-mode to the given value.
15545 *
15546 * === Querying
15547 *
15548 * - #autoclose?: Returns whether +self+ auto-closes.
15549 * - #binmode?: Returns whether +self+ is in binary mode.
15550 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15551 * - #closed?: Returns whether +self+ is closed.
15552 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15553 * - #external_encoding: Returns the external encoding object for +self+.
15554 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15555 * - #internal_encoding: Returns the internal encoding object for +self+.
15556 * - #pid: Returns the process ID of a child process associated with +self+,
15557 * if +self+ was created by ::popen.
15558 * - #stat: Returns the File::Stat object containing status information for +self+.
15559 * - #sync: Returns whether +self+ is in sync-mode.
15560 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15561 *
15562 * === Buffering
15563 *
15564 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15565 * - #flush: Flushes any buffered data within +self+ to the underlying
15566 * operating system.
15567 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15568 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15569 * - #ungetc: Prepends buffer for +self+ with given string.
15570 *
15571 * === Low-Level Access
15572 *
15573 * - ::sysopen: Opens the file given by its path,
15574 * returning the integer file descriptor.
15575 * - #advise: Announces the intention to access data from +self+ in a specific way.
15576 * - #fcntl: Passes a low-level command to the file specified
15577 * by the given file descriptor.
15578 * - #ioctl: Passes a low-level command to the device specified
15579 * by the given file descriptor.
15580 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15581 * - #sysseek: Sets the offset for +self+.
15582 * - #syswrite: Writes the given string to +self+ using a low-level write.
15583 *
15584 * === Other
15585 *
15586 * - ::copy_stream: Copies data from a source to a destination,
15587 * each of which is a filepath or an \IO-like object.
15588 * - ::try_convert: Returns a new \IO object resulting from converting
15589 * the given object.
15590 * - #inspect: Returns the string representation of +self+.
15591 *
15592 */
15593
15594void
15595Init_IO(void)
15596{
15597 VALUE rb_cARGF;
15598#ifdef __CYGWIN__
15599#include <sys/cygwin.h>
15600 static struct __cygwin_perfile pf[] =
15601 {
15602 {"", O_RDONLY | O_BINARY},
15603 {"", O_WRONLY | O_BINARY},
15604 {"", O_RDWR | O_BINARY},
15605 {"", O_APPEND | O_BINARY},
15606 {NULL, 0}
15607 };
15608 cygwin_internal(CW_PERFILE, pf);
15609#endif
15610
15611 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15612 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15613
15614 id_write = rb_intern_const("write");
15615 id_read = rb_intern_const("read");
15616 id_getc = rb_intern_const("getc");
15617 id_flush = rb_intern_const("flush");
15618 id_readpartial = rb_intern_const("readpartial");
15619 id_set_encoding = rb_intern_const("set_encoding");
15620 id_fileno = rb_intern_const("fileno");
15621
15622 rb_define_global_function("syscall", rb_f_syscall, -1);
15623
15624 rb_define_global_function("open", rb_f_open, -1);
15625 rb_define_global_function("printf", rb_f_printf, -1);
15626 rb_define_global_function("print", rb_f_print, -1);
15627 rb_define_global_function("putc", rb_f_putc, 1);
15628 rb_define_global_function("puts", rb_f_puts, -1);
15629 rb_define_global_function("gets", rb_f_gets, -1);
15630 rb_define_global_function("readline", rb_f_readline, -1);
15631 rb_define_global_function("select", rb_f_select, -1);
15632
15633 rb_define_global_function("readlines", rb_f_readlines, -1);
15634
15635 rb_define_global_function("`", rb_f_backquote, 1);
15636
15637 rb_define_global_function("p", rb_f_p, -1);
15638 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15639
15640 rb_cIO = rb_define_class("IO", rb_cObject);
15641 rb_include_module(rb_cIO, rb_mEnumerable);
15642
15643 /* Can be raised by IO operations when IO#timeout= is set. */
15644 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15645
15646 /* Readable event mask for IO#wait. */
15647 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15648 /* Writable event mask for IO#wait. */
15649 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15650 /* Priority event mask for IO#wait. */
15651 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15652
15653 /* exception to wait for reading. see IO.select. */
15654 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15655 /* exception to wait for writing. see IO.select. */
15656 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15657 /* exception to wait for reading by EAGAIN. see IO.select. */
15658 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15659 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15660 /* exception to wait for writing by EAGAIN. see IO.select. */
15661 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15662 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15663#if EAGAIN == EWOULDBLOCK
15664 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15665 /* same as IO::EAGAINWaitReadable */
15666 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15667 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15668 /* same as IO::EAGAINWaitWritable */
15669 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15670#else
15671 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15672 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15673 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15674 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15675 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15676 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15677#endif
15678 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15679 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15680 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15681 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15682 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15683 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15684
15685#if 0
15686 /* This is necessary only for forcing rdoc handle File::open */
15687 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15688#endif
15689
15690 rb_define_alloc_func(rb_cIO, io_alloc);
15691 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15692 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15693 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15694 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15695 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15696 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15697 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15698 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15699 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15700 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15701 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15702 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15703 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15704 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15705 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15706
15707 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15708
15709 rb_output_fs = Qnil;
15710 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15711
15712 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15713 rb_vm_register_global_object(rb_default_rs);
15714 rb_rs = rb_default_rs;
15715 rb_output_rs = Qnil;
15716 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15717 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15718 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15719
15720 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15721 rb_gvar_ractor_local("$_");
15722
15723 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15724 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15725
15726 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15727 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15728 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15729 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15730
15731 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15732 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15733 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15734 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15735 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15736
15737 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15738 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15739
15740 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15741 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15742
15743 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15744 rb_define_alias(rb_cIO, "to_i", "fileno");
15745 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15746
15747 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15748 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15749
15750 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15751 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15752 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15753 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15754
15755 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15756 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15757
15758 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15759
15760 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15761 rb_define_method(rb_cIO, "read", io_read, -1);
15762 rb_define_method(rb_cIO, "write", io_write_m, -1);
15763 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15764 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15765 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15766 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15767 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15768 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15769 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15770 rb_define_method(rb_cIO, "<<", rb_io_addstr, 1);
15771 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15772 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15773 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15774 /* Set I/O position from the beginning */
15775 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15776 /* Set I/O position from the current position */
15777 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15778 /* Set I/O position from the end */
15779 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15780#ifdef SEEK_DATA
15781 /* Set I/O position to the next location containing data */
15782 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15783#endif
15784#ifdef SEEK_HOLE
15785 /* Set I/O position to the next hole */
15786 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15787#endif
15788 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15789 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15790 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15791 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15792 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15793
15794 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15795 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15796
15797 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15798 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15799 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15800 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15801
15802 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15803 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15804 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15805 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15806 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15807 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15808
15809 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15810 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15811 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15812
15813 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15814 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15815
15816 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15817
15818 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15819 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15820 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15821 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15822
15823 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15824 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15825
15826 rb_define_method(rb_cIO, "wait", io_wait, -1);
15827
15828 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15829 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15830 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15831
15832 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15833 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15834 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15835 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15836
15837 rb_gvar_ractor_local("$stdin");
15838 rb_gvar_ractor_local("$stdout");
15839 rb_gvar_ractor_local("$>");
15840 rb_gvar_ractor_local("$stderr");
15841
15842 rb_global_variable(&rb_stdin);
15843 rb_stdin = rb_io_prep_stdin();
15844 rb_global_variable(&rb_stdout);
15845 rb_stdout = rb_io_prep_stdout();
15846 rb_global_variable(&rb_stderr);
15847 rb_stderr = rb_io_prep_stderr();
15848
15849 orig_stdout = rb_stdout;
15850 orig_stderr = rb_stderr;
15851
15852 /* Holds the original stdin */
15853 rb_define_global_const("STDIN", rb_stdin);
15854 /* Holds the original stdout */
15855 rb_define_global_const("STDOUT", rb_stdout);
15856 /* Holds the original stderr */
15857 rb_define_global_const("STDERR", rb_stderr);
15858
15859#if 0
15860 /* Hack to get rdoc to regard ARGF as a class: */
15861 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15862#endif
15863
15864 rb_cARGF = rb_class_new(rb_cObject);
15865 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15866 rb_define_alloc_func(rb_cARGF, argf_alloc);
15867
15868 rb_include_module(rb_cARGF, rb_mEnumerable);
15869
15870 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15871 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15872 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15873 rb_define_alias(rb_cARGF, "inspect", "to_s");
15874 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15875
15876 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15877 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15878 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15879 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15880 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15881 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15882 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15883 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15884 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15885
15886 rb_define_method(rb_cARGF, "read", argf_read, -1);
15887 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15888 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15889 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15890 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15891 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15892 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15893 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15894 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15895 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15896 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15897 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15898 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15899 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15900 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15901 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15902 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15903 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15904 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15905 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15906
15907 rb_define_method(rb_cARGF, "write", argf_write, -1);
15908 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15909 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15910 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15911 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15912
15913 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15914 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15915 rb_define_method(rb_cARGF, "file", argf_file, 0);
15916 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15917 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15918 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15919
15920 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15921 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15922
15923 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15924 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15925
15926 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15927 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15928 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15929
15930 argf = rb_class_new_instance(0, 0, rb_cARGF);
15931
15932 rb_define_readonly_variable("$<", &argf);
15933 /*
15934 * ARGF is a stream designed for use in scripts that process files given
15935 * as command-line arguments or passed in via STDIN.
15936 *
15937 * See ARGF (the class) for more details.
15938 */
15939 rb_define_global_const("ARGF", argf);
15940
15941 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15942 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15943 ARGF.filename = rb_str_new2("-");
15944
15945 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15946 rb_gvar_ractor_local("$-i");
15947
15948 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15949
15950#if defined (_WIN32) || defined(__CYGWIN__)
15951 atexit(pipe_atexit);
15952#endif
15953
15954 Init_File();
15955
15956 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15957
15958 sym_mode = ID2SYM(rb_intern_const("mode"));
15959 sym_perm = ID2SYM(rb_intern_const("perm"));
15960 sym_flags = ID2SYM(rb_intern_const("flags"));
15961 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15962 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15963 sym_encoding = ID2SYM(rb_id_encoding());
15964 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15965 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15966 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15967 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15968 sym_normal = ID2SYM(rb_intern_const("normal"));
15969 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15970 sym_random = ID2SYM(rb_intern_const("random"));
15971 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15972 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15973 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15974 sym_SET = ID2SYM(rb_intern_const("SET"));
15975 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15976 sym_END = ID2SYM(rb_intern_const("END"));
15977#ifdef SEEK_DATA
15978 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15979#endif
15980#ifdef SEEK_HOLE
15981 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15982#endif
15983 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15984 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15985}
15986
15987#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:14668
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:14662
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:1289
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:788
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:8607
rb_io_gets
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4303
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:8733
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:2350
rb_write_error
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9162
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:5172
rb_io_getbyte
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5078
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:9338
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:2695
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:9142
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:6384
rb_io_binmode
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6338
rb_io_ungetc
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5236
rb_pipe
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7385
rb_gets
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10407
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:7268
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:7275
rb_io_close
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5758
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:2938
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:3680
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:958
rb_str_new_frozen
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1465
rb_str_dup
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1920
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:3448
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:3272
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:3622
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:2854
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:3152
rb_str_unlocktmp
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3255
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:2652
rb_str_buf_new
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1647
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:1603
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:1597
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:2935
rb_set_class_path
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:433
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:1951
rb_class_name
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:492
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:3823
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:824
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:3809
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:6470
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:6603
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:2918
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:6752
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:6527
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:1591
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:7085
rb_io_descriptor
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2898
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:9384
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:1650
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:1609
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:2972
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:5866
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:2015
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:3424
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:6877
rb_io_wait_writable
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1548
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:9255
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:1665
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:1514
rb_io_synchronized
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7372
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:1453
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:14628
rb_p
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9041
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:640
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:452
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:616
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:446
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:482
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:652
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:628
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:458
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:13911
argf
Definition io.c:236
binwrite_arg
Definition io.c:1735
bufread_arg
Definition io.c:3092
copy_stream_struct
Definition io.c:12442
fiber_scheduler_wait_for_arguments
Definition io.c:12496
finish_writeconv_arg
Definition io.c:5466
foreach_arg
Definition io.c:11955
getline_arg
Definition io.c:4070
io_encoding_set_args
Definition io.c:11769
io_internal_read_struct
Definition io.c:1124
io_internal_write_struct
Definition io.c:1135
iovec
Definition win32.h:226
pipe_list
Definition io.c:7281
prdwr_internal_arg
Definition io.c:6164
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:519
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:12184
select_args
Definition io.c:10776
sysopen_struct
Definition io.c:7022
timeval
Definition missing.h:63
write_arg
Definition io.c:1741
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