Ruby 3.5.0dev (2025-02-20 revision 34098b669c0cbc024cd08e686891f1dfe0a10aaf)
io.c (34098b669c0cbc024cd08e686891f1dfe0a10aaf)
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
120#include "ccan/list/list.h"
121#include "dln.h"
122#include "encindex.h"
123#include "id.h"
124#include "internal.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
136#include "ruby/io.h"
137#include "ruby/io/buffer.h"
138#include "ruby/missing.h"
139#include "ruby/thread.h"
140#include "ruby/util.h"
141#include "ruby_atomic.h"
142#include "ruby/ractor.h"
143
144#if !USE_POLL
145# include "vm_core.h"
146#endif
147
148#include "builtin.h"
149
150#ifndef O_ACCMODE
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152#endif
153
154#ifndef PIPE_BUF
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
157# else
158# define PIPE_BUF 512 /* is this ok? */
159# endif
160#endif
161
162#ifndef EWOULDBLOCK
163# define EWOULDBLOCK EAGAIN
164#endif
165
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168off_t __syscall(quad_t number, ...);
169#endif
170
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
175
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177
178/* define system APIs */
179#ifdef _WIN32
180#undef open
181#define open rb_w32_uopen
182#undef rename
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
185#endif
186
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
200
202static VALUE orig_stdout, orig_stderr;
203
204VALUE rb_output_fs;
205VALUE rb_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
225VALUE
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
231VALUE 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
236struct 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
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
299{
300 rb_maygvl_fd_fix_cloexec(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
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
780VALUE
782{
783 rb_check_frozen(io);
784 return io;
785}
786
787void
789{
790 if (!fptr) {
791 rb_raise(rb_eIOError, "uninitialized stream");
792 }
793}
794
795void
797{
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;
807 return fptr;
808}
809
810VALUE
812{
813 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
814}
815
816VALUE
818{
819 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
820}
821
822VALUE
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
833VALUE
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 */
856VALUE
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 */
885VALUE
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
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
1016{
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1020 }
1021}
1022
1023void
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
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
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
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
1136 VALUE th;
1137 rb_io_t *fptr;
1138 int nonblock;
1139 int fd;
1140
1141 const void *buf;
1142 size_t capa;
1143 struct timeval *timeout;
1144};
1145
1146#ifdef HAVE_WRITEV
1147struct io_internal_writev_struct {
1148 VALUE th;
1149 rb_io_t *fptr;
1150 int nonblock;
1151 int fd;
1152
1153 int iovcnt;
1154 const struct iovec *iov;
1155 struct timeval *timeout;
1156};
1157#endif
1158
1159static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1160
1166static inline int
1167io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1168{
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1170 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1171 return -1;
1172 }
1173
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1175
1176 if (ready > 0) {
1177 return ready;
1178 }
1179 else if (ready == 0) {
1180 errno = ETIMEDOUT;
1181 return -1;
1182 }
1183
1184 errno = error;
1185 return -1;
1186}
1187
1188static VALUE
1189internal_read_func(void *ptr)
1190{
1191 struct io_internal_read_struct *iis = ptr;
1192 ssize_t result;
1193
1194 if (iis->timeout && !iis->nonblock) {
1195 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1196 return -1;
1197 }
1198 }
1199
1200 retry:
1201 result = read(iis->fd, iis->buf, iis->capa);
1202
1203 if (result < 0 && !iis->nonblock) {
1204 if (io_again_p(errno)) {
1205 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1206 return -1;
1207 }
1208 else {
1209 goto retry;
1210 }
1211 }
1212 }
1213
1214 return result;
1215}
1216
1217#if defined __APPLE__
1218# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1219#else
1220# define do_write_retry(code) result = code
1221#endif
1222
1223static VALUE
1224internal_write_func(void *ptr)
1225{
1226 struct io_internal_write_struct *iis = ptr;
1227 ssize_t result;
1228
1229 if (iis->timeout && !iis->nonblock) {
1230 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1231 return -1;
1232 }
1233 }
1234
1235 retry:
1236 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1237
1238 if (result < 0 && !iis->nonblock) {
1239 int e = errno;
1240 if (io_again_p(e)) {
1241 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1242 return -1;
1243 }
1244 else {
1245 goto retry;
1246 }
1247 }
1248 }
1249
1250 return result;
1251}
1252
1253#ifdef HAVE_WRITEV
1254static VALUE
1255internal_writev_func(void *ptr)
1256{
1257 struct io_internal_writev_struct *iis = ptr;
1258 ssize_t result;
1259
1260 if (iis->timeout && !iis->nonblock) {
1261 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1262 return -1;
1263 }
1264 }
1265
1266 retry:
1267 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1268
1269 if (result < 0 && !iis->nonblock) {
1270 if (io_again_p(errno)) {
1271 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1272 return -1;
1273 }
1274 else {
1275 goto retry;
1276 }
1277 }
1278 }
1279
1280 return result;
1281}
1282#endif
1283
1284static ssize_t
1285rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1286{
1287 VALUE scheduler = rb_fiber_scheduler_current();
1288 if (scheduler != Qnil) {
1289 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1290
1291 if (!UNDEF_P(result)) {
1293 }
1294 }
1295
1296 struct io_internal_read_struct iis = {
1297 .th = rb_thread_current(),
1298 .fptr = fptr,
1299 .nonblock = 0,
1300 .fd = fptr->fd,
1301
1302 .buf = buf,
1303 .capa = count,
1304 .timeout = NULL,
1305 };
1306
1307 struct timeval timeout_storage;
1308
1309 if (fptr->timeout != Qnil) {
1310 timeout_storage = rb_time_interval(fptr->timeout);
1311 iis.timeout = &timeout_storage;
1312 }
1313
1314 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1315}
1316
1317static ssize_t
1318rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1319{
1320 VALUE scheduler = rb_fiber_scheduler_current();
1321 if (scheduler != Qnil) {
1322 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1323
1324 if (!UNDEF_P(result)) {
1326 }
1327 }
1328
1329 struct io_internal_write_struct iis = {
1330 .th = rb_thread_current(),
1331 .fptr = fptr,
1332 .nonblock = 0,
1333 .fd = fptr->fd,
1334
1335 .buf = buf,
1336 .capa = count,
1337 .timeout = NULL
1338 };
1339
1340 struct timeval timeout_storage;
1341
1342 if (fptr->timeout != Qnil) {
1343 timeout_storage = rb_time_interval(fptr->timeout);
1344 iis.timeout = &timeout_storage;
1345 }
1346
1347 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1348}
1349
1350#ifdef HAVE_WRITEV
1351static ssize_t
1352rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1353{
1354 if (!iovcnt) return 0;
1355
1356 VALUE scheduler = rb_fiber_scheduler_current();
1357 if (scheduler != Qnil) {
1358 // This path assumes at least one `iov`:
1359 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1360
1361 if (!UNDEF_P(result)) {
1363 }
1364 }
1365
1366 struct io_internal_writev_struct iis = {
1367 .th = rb_thread_current(),
1368 .fptr = fptr,
1369 .nonblock = 0,
1370 .fd = fptr->fd,
1371
1372 .iov = iov,
1373 .iovcnt = iovcnt,
1374 .timeout = NULL
1375 };
1376
1377 struct timeval timeout_storage;
1378
1379 if (fptr->timeout != Qnil) {
1380 timeout_storage = rb_time_interval(fptr->timeout);
1381 iis.timeout = &timeout_storage;
1382 }
1383
1384 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1385}
1386#endif
1387
1388static VALUE
1389io_flush_buffer_sync(void *arg)
1390{
1391 rb_io_t *fptr = arg;
1392 long l = fptr->wbuf.len;
1393 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1394
1395 if (fptr->wbuf.len <= r) {
1396 fptr->wbuf.off = 0;
1397 fptr->wbuf.len = 0;
1398 return 0;
1399 }
1400
1401 if (0 <= r) {
1402 fptr->wbuf.off += (int)r;
1403 fptr->wbuf.len -= (int)r;
1404 errno = EAGAIN;
1405 }
1406
1407 return (VALUE)-1;
1408}
1409
1410static VALUE
1411io_flush_buffer_async(VALUE arg)
1412{
1413 rb_io_t *fptr = (rb_io_t *)arg;
1414 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1415}
1416
1417static inline int
1418io_flush_buffer(rb_io_t *fptr)
1419{
1420 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1421 return (int)io_flush_buffer_async((VALUE)fptr);
1422 }
1423 else {
1424 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1425 }
1426}
1427
1428static int
1429io_fflush(rb_io_t *fptr)
1430{
1431 rb_io_check_closed(fptr);
1432
1433 if (fptr->wbuf.len == 0)
1434 return 0;
1435
1436 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1437 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1438 return -1;
1439
1440 rb_io_check_closed(fptr);
1441 }
1442
1443 return 0;
1444}
1445
1446VALUE
1447rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1448{
1449 VALUE scheduler = rb_fiber_scheduler_current();
1450
1451 if (scheduler != Qnil) {
1452 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1453 }
1454
1455 rb_io_t * fptr = NULL;
1456 RB_IO_POINTER(io, fptr);
1457
1458 struct timeval tv_storage;
1459 struct timeval *tv = NULL;
1460
1461 if (NIL_OR_UNDEF_P(timeout)) {
1462 timeout = fptr->timeout;
1463 }
1464
1465 if (timeout != Qnil) {
1466 tv_storage = rb_time_interval(timeout);
1467 tv = &tv_storage;
1468 }
1469
1470 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1471
1472 if (ready < 0) {
1473 rb_sys_fail(0);
1474 }
1475
1476 // Not sure if this is necessary:
1477 rb_io_check_closed(fptr);
1478
1479 if (ready) {
1480 return RB_INT2NUM(ready);
1481 }
1482 else {
1483 return Qfalse;
1484 }
1485}
1486
1487static VALUE
1488io_from_fd(int fd)
1489{
1490 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1491}
1492
1493static int
1494io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1495{
1496 VALUE scheduler = rb_fiber_scheduler_current();
1497
1498 if (scheduler != Qnil) {
1499 return RTEST(
1500 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1501 );
1502 }
1503
1504 return rb_thread_wait_for_single_fd(fd, events, timeout);
1505}
1506
1507int
1509{
1510 io_fd_check_closed(f);
1511
1512 VALUE scheduler = rb_fiber_scheduler_current();
1513
1514 switch (errno) {
1515 case EINTR:
1516#if defined(ERESTART)
1517 case ERESTART:
1518#endif
1520 return TRUE;
1521
1522 case EAGAIN:
1523#if EWOULDBLOCK != EAGAIN
1524 case EWOULDBLOCK:
1525#endif
1526 if (scheduler != Qnil) {
1527 return RTEST(
1528 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1529 );
1530 }
1531 else {
1532 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1533 }
1534 return TRUE;
1535
1536 default:
1537 return FALSE;
1538 }
1539}
1540
1541int
1543{
1544 io_fd_check_closed(f);
1545
1546 VALUE scheduler = rb_fiber_scheduler_current();
1547
1548 switch (errno) {
1549 case EINTR:
1550#if defined(ERESTART)
1551 case ERESTART:
1552#endif
1553 /*
1554 * In old Linux, several special files under /proc and /sys don't handle
1555 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1556 * Otherwise, we face nasty hang up. Sigh.
1557 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1558 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1559 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1560 * Then rb_thread_check_ints() is enough.
1561 */
1563 return TRUE;
1564
1565 case EAGAIN:
1566#if EWOULDBLOCK != EAGAIN
1567 case EWOULDBLOCK:
1568#endif
1569 if (scheduler != Qnil) {
1570 return RTEST(
1571 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1572 );
1573 }
1574 else {
1575 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1576 }
1577 return TRUE;
1578
1579 default:
1580 return FALSE;
1581 }
1582}
1583
1584int
1585rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1586{
1587 return io_wait_for_single_fd(fd, events, timeout);
1588}
1589
1590int
1592{
1593 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1594}
1595
1596int
1598{
1599 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1600}
1601
1602VALUE
1603rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1604{
1605 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1606 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1607 // instead relies on `read(-1) -> -1` which causes this code path. We then
1608 // check here whether the IO was in fact closed. Probably it's better to
1609 // check that `fptr->fd != -1` before using it in syscall.
1610 rb_io_check_closed(RFILE(io)->fptr);
1611
1612 switch (error) {
1613 // In old Linux, several special files under /proc and /sys don't handle
1614 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1615 // Otherwise, we face nasty hang up. Sigh.
1616 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1617 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1618 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1619 // Then rb_thread_check_ints() is enough.
1620 case EINTR:
1621#if defined(ERESTART)
1622 case ERESTART:
1623#endif
1624 // We might have pending interrupts since the previous syscall was interrupted:
1626
1627 // The operation was interrupted, so retry it immediately:
1628 return events;
1629
1630 case EAGAIN:
1631#if EWOULDBLOCK != EAGAIN
1632 case EWOULDBLOCK:
1633#endif
1634 // The operation would block, so wait for the specified events:
1635 return rb_io_wait(io, events, timeout);
1636
1637 default:
1638 // Non-specific error, no event is ready:
1639 return Qnil;
1640 }
1641}
1642
1643int
1645{
1646 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1647
1648 if (RTEST(result)) {
1649 return RB_NUM2INT(result);
1650 }
1651 else if (result == RUBY_Qfalse) {
1652 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1653 }
1654
1655 return 0;
1656}
1657
1658int
1660{
1661 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1662
1663 if (RTEST(result)) {
1664 return RB_NUM2INT(result);
1665 }
1666 else if (result == RUBY_Qfalse) {
1667 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1668 }
1669
1670 return 0;
1671}
1672
1673static void
1674make_writeconv(rb_io_t *fptr)
1675{
1676 if (!fptr->writeconv_initialized) {
1677 const char *senc, *denc;
1678 rb_encoding *enc;
1679 int ecflags;
1680 VALUE ecopts;
1681
1682 fptr->writeconv_initialized = 1;
1683
1684 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1685 ecopts = fptr->encs.ecopts;
1686
1687 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1688 /* no encoding conversion */
1689 fptr->writeconv_pre_ecflags = 0;
1690 fptr->writeconv_pre_ecopts = Qnil;
1691 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1692 if (!fptr->writeconv)
1693 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1695 }
1696 else {
1697 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1698 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1699 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1700 /* single conversion */
1701 fptr->writeconv_pre_ecflags = ecflags;
1702 fptr->writeconv_pre_ecopts = ecopts;
1703 fptr->writeconv = NULL;
1705 }
1706 else {
1707 /* double conversion */
1708 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1709 fptr->writeconv_pre_ecopts = ecopts;
1710 if (senc) {
1711 denc = rb_enc_name(enc);
1712 fptr->writeconv_asciicompat = rb_str_new2(senc);
1713 }
1714 else {
1715 senc = denc = "";
1716 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1717 }
1719 ecopts = fptr->encs.ecopts;
1720 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1721 if (!fptr->writeconv)
1722 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1723 }
1724 }
1725 }
1726}
1727
1728/* writing functions */
1730 rb_io_t *fptr;
1731 const char *ptr;
1732 long length;
1733};
1734
1736 VALUE io;
1737 VALUE str;
1738 int nosync;
1739};
1740
1741#ifdef HAVE_WRITEV
1742static ssize_t
1743io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1744{
1745 if (fptr->wbuf.len) {
1746 struct iovec iov[2];
1747
1748 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1749 iov[0].iov_len = fptr->wbuf.len;
1750 iov[1].iov_base = (void*)ptr;
1751 iov[1].iov_len = length;
1752
1753 ssize_t result = rb_writev_internal(fptr, iov, 2);
1754
1755 if (result < 0)
1756 return result;
1757
1758 if (result >= fptr->wbuf.len) {
1759 // We wrote more than the internal buffer:
1760 result -= fptr->wbuf.len;
1761 fptr->wbuf.off = 0;
1762 fptr->wbuf.len = 0;
1763 }
1764 else {
1765 // We only wrote less data than the internal buffer:
1766 fptr->wbuf.off += (int)result;
1767 fptr->wbuf.len -= (int)result;
1768
1769 result = 0;
1770 }
1771
1772 return result;
1773 }
1774 else {
1775 return rb_io_write_memory(fptr, ptr, length);
1776 }
1777}
1778#else
1779static ssize_t
1780io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1781{
1782 long remaining = length;
1783
1784 if (fptr->wbuf.len) {
1785 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1786 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1787 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1788 fptr->wbuf.off = 0;
1789 }
1790
1791 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1792 fptr->wbuf.len += (int)length;
1793
1794 // We copied the entire incoming data to the internal buffer:
1795 remaining = 0;
1796 }
1797
1798 // Flush the internal buffer:
1799 if (io_fflush(fptr) < 0) {
1800 return -1;
1801 }
1802
1803 // If all the data was buffered, we are done:
1804 if (remaining == 0) {
1805 return length;
1806 }
1807 }
1808
1809 // Otherwise, we should write the data directly:
1810 return rb_io_write_memory(fptr, ptr, length);
1811}
1812#endif
1813
1814static VALUE
1815io_binwrite_string(VALUE arg)
1816{
1817 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1818
1819 const char *ptr = p->ptr;
1820 size_t remaining = p->length;
1821
1822 while (remaining) {
1823 // Write as much as possible:
1824 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1825
1826 if (result == 0) {
1827 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1828 // should try again immediately.
1829 }
1830 else if (result > 0) {
1831 if ((size_t)result == remaining) break;
1832 ptr += result;
1833 remaining -= result;
1834 }
1835 // Wait for it to become writable:
1836 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1837 rb_io_check_closed(p->fptr);
1838 }
1839 else {
1840 // The error was unrelated to waiting for it to become writable, so we fail:
1841 return -1;
1842 }
1843 }
1844
1845 return p->length;
1846}
1847
1848inline static void
1849io_allocate_write_buffer(rb_io_t *fptr, int sync)
1850{
1851 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1852 fptr->wbuf.off = 0;
1853 fptr->wbuf.len = 0;
1854 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1855 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1856 }
1857
1858 if (NIL_P(fptr->write_lock)) {
1859 fptr->write_lock = rb_mutex_new();
1860 rb_mutex_allow_trap(fptr->write_lock, 1);
1861 }
1862}
1863
1864static inline int
1865io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1866{
1867 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1868 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1869 return 1;
1870
1871 // If the amount of data we want to write exceeds the internal buffer:
1872 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1873 return 1;
1874
1875 // Otherwise, we can append to the internal buffer:
1876 return 0;
1877}
1878
1879static long
1880io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1881{
1882 if (len <= 0) return len;
1883
1884 // Don't write anything if current thread has a pending interrupt:
1886
1887 io_allocate_write_buffer(fptr, !nosync);
1888
1889 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1890 struct binwrite_arg arg;
1891
1892 arg.fptr = fptr;
1893 arg.ptr = ptr;
1894 arg.length = len;
1895
1896 if (!NIL_P(fptr->write_lock)) {
1897 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1898 }
1899 else {
1900 return io_binwrite_string((VALUE)&arg);
1901 }
1902 }
1903 else {
1904 if (fptr->wbuf.off) {
1905 if (fptr->wbuf.len)
1906 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1907 fptr->wbuf.off = 0;
1908 }
1909
1910 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1911 fptr->wbuf.len += (int)len;
1912
1913 return len;
1914 }
1915}
1916
1917# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1918 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1919
1920#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1921 MODE_BTMODE(d, e, f) : \
1922 MODE_BTMODE(a, b, c))
1923
1924static VALUE
1925do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1926{
1927 if (NEED_WRITECONV(fptr)) {
1928 VALUE common_encoding = Qnil;
1929 SET_BINARY_MODE(fptr);
1930
1931 make_writeconv(fptr);
1932
1933 if (fptr->writeconv) {
1934#define fmode (fptr->mode)
1935 if (!NIL_P(fptr->writeconv_asciicompat))
1936 common_encoding = fptr->writeconv_asciicompat;
1937 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1938 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1939 rb_enc_name(rb_enc_get(str)));
1940 }
1941#undef fmode
1942 }
1943 else {
1944 if (fptr->encs.enc2)
1945 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1946 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1947 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1948 }
1949
1950 if (!NIL_P(common_encoding)) {
1951 str = rb_str_encode(str, common_encoding,
1953 *converted = 1;
1954 }
1955
1956 if (fptr->writeconv) {
1958 *converted = 1;
1959 }
1960 }
1961#if RUBY_CRLF_ENVIRONMENT
1962#define fmode (fptr->mode)
1963 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1964 if ((fptr->mode & FMODE_READABLE) &&
1966 setmode(fptr->fd, O_BINARY);
1967 }
1968 else {
1969 setmode(fptr->fd, O_TEXT);
1970 }
1971 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1972 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1973 rb_enc_name(rb_enc_get(str)));
1974 }
1975 }
1976#undef fmode
1977#endif
1978 return str;
1979}
1980
1981static long
1982io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1983{
1984 int converted = 0;
1985 VALUE tmp;
1986 long n, len;
1987 const char *ptr;
1988
1989#ifdef _WIN32
1990 if (fptr->mode & FMODE_TTY) {
1991 long len = rb_w32_write_console(str, fptr->fd);
1992 if (len > 0) return len;
1993 }
1994#endif
1995
1996 str = do_writeconv(str, fptr, &converted);
1997 if (converted)
1998 OBJ_FREEZE(str);
1999
2000 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2001 RSTRING_GETMEM(tmp, ptr, len);
2002 n = io_binwrite(ptr, len, fptr, nosync);
2003 rb_str_tmp_frozen_release(str, tmp);
2004
2005 return n;
2006}
2007
2008ssize_t
2009rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2010{
2011 rb_io_t *fptr;
2012
2013 GetOpenFile(io, fptr);
2015 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2016}
2017
2018static VALUE
2019io_write(VALUE io, VALUE str, int nosync)
2020{
2021 rb_io_t *fptr;
2022 long n;
2023 VALUE tmp;
2024
2025 io = GetWriteIO(io);
2026 str = rb_obj_as_string(str);
2027 tmp = rb_io_check_io(io);
2028
2029 if (NIL_P(tmp)) {
2030 /* port is not IO, call write method for it. */
2031 return rb_funcall(io, id_write, 1, str);
2032 }
2033
2034 io = tmp;
2035 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2036
2037 GetOpenFile(io, fptr);
2039
2040 n = io_fwrite(str, fptr, nosync);
2041 if (n < 0L) rb_sys_fail_on_write(fptr);
2042
2043 return LONG2FIX(n);
2044}
2045
2046#ifdef HAVE_WRITEV
2047struct binwritev_arg {
2048 rb_io_t *fptr;
2049 struct iovec *iov;
2050 int iovcnt;
2051 size_t total;
2052};
2053
2054static VALUE
2055io_binwritev_internal(VALUE arg)
2056{
2057 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2058
2059 size_t remaining = p->total;
2060 size_t offset = 0;
2061
2062 rb_io_t *fptr = p->fptr;
2063 struct iovec *iov = p->iov;
2064 int iovcnt = p->iovcnt;
2065
2066 while (remaining) {
2067 long result = rb_writev_internal(fptr, iov, iovcnt);
2068
2069 if (result >= 0) {
2070 offset += result;
2071 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2072 if (offset < (size_t)fptr->wbuf.len) {
2073 fptr->wbuf.off += result;
2074 fptr->wbuf.len -= result;
2075 }
2076 else {
2077 offset -= (size_t)fptr->wbuf.len;
2078 fptr->wbuf.off = 0;
2079 fptr->wbuf.len = 0;
2080 }
2081 }
2082
2083 if (offset == p->total) {
2084 return p->total;
2085 }
2086
2087 while (result >= (ssize_t)iov->iov_len) {
2088 /* iovcnt > 0 */
2089 result -= iov->iov_len;
2090 iov->iov_len = 0;
2091 iov++;
2092
2093 if (!--iovcnt) {
2094 // I don't believe this code path can ever occur.
2095 return offset;
2096 }
2097 }
2098
2099 iov->iov_base = (char *)iov->iov_base + result;
2100 iov->iov_len -= result;
2101 }
2102 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2103 rb_io_check_closed(fptr);
2104 }
2105 else {
2106 return -1;
2107 }
2108 }
2109
2110 return offset;
2111}
2112
2113static long
2114io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2115{
2116 // Don't write anything if current thread has a pending interrupt:
2118
2119 if (iovcnt == 0) return 0;
2120
2121 size_t total = 0;
2122 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2123
2124 io_allocate_write_buffer(fptr, 1);
2125
2126 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2127 // The end of the buffered data:
2128 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2129
2130 if (offset + total <= (size_t)fptr->wbuf.capa) {
2131 for (int i = 1; i < iovcnt; i++) {
2132 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2133 offset += iov[i].iov_len;
2134 }
2135
2136 fptr->wbuf.len += total;
2137
2138 return total;
2139 }
2140 else {
2141 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2142 iov[0].iov_len = fptr->wbuf.len;
2143 }
2144 }
2145 else {
2146 // The first iov is reserved for the internal buffer, and it's empty.
2147 iov++;
2148
2149 if (!--iovcnt) {
2150 // If there are no other io vectors we are done.
2151 return 0;
2152 }
2153 }
2154
2155 struct binwritev_arg arg;
2156 arg.fptr = fptr;
2157 arg.iov = iov;
2158 arg.iovcnt = iovcnt;
2159 arg.total = total;
2160
2161 if (!NIL_P(fptr->write_lock)) {
2162 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2163 }
2164 else {
2165 return io_binwritev_internal((VALUE)&arg);
2166 }
2167}
2168
2169static long
2170io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2171{
2172 int i, converted, iovcnt = argc + 1;
2173 long n;
2174 VALUE v1, v2, str, tmp, *tmp_array;
2175 struct iovec *iov;
2176
2177 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2178 tmp_array = ALLOCV_N(VALUE, v2, argc);
2179
2180 for (i = 0; i < argc; i++) {
2181 str = rb_obj_as_string(argv[i]);
2182 converted = 0;
2183 str = do_writeconv(str, fptr, &converted);
2184
2185 if (converted)
2186 OBJ_FREEZE(str);
2187
2188 tmp = rb_str_tmp_frozen_acquire(str);
2189 tmp_array[i] = tmp;
2190
2191 /* iov[0] is reserved for buffer of fptr */
2192 iov[i+1].iov_base = RSTRING_PTR(tmp);
2193 iov[i+1].iov_len = RSTRING_LEN(tmp);
2194 }
2195
2196 n = io_binwritev(iov, iovcnt, fptr);
2197 if (v1) ALLOCV_END(v1);
2198
2199 for (i = 0; i < argc; i++) {
2200 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2201 }
2202
2203 if (v2) ALLOCV_END(v2);
2204
2205 return n;
2206}
2207
2208static int
2209iovcnt_ok(int iovcnt)
2210{
2211#ifdef IOV_MAX
2212 return iovcnt < IOV_MAX;
2213#else /* GNU/Hurd has writev, but no IOV_MAX */
2214 return 1;
2215#endif
2216}
2217#endif /* HAVE_WRITEV */
2218
2219static VALUE
2220io_writev(int argc, const VALUE *argv, VALUE io)
2221{
2222 rb_io_t *fptr;
2223 long n;
2224 VALUE tmp, total = INT2FIX(0);
2225 int i, cnt = 1;
2226
2227 io = GetWriteIO(io);
2228 tmp = rb_io_check_io(io);
2229
2230 if (NIL_P(tmp)) {
2231 /* port is not IO, call write method for it. */
2232 return rb_funcallv(io, id_write, argc, argv);
2233 }
2234
2235 io = tmp;
2236
2237 GetOpenFile(io, fptr);
2239
2240 for (i = 0; i < argc; i += cnt) {
2241#ifdef HAVE_WRITEV
2242 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2243 n = io_fwritev(cnt, &argv[i], fptr);
2244 }
2245 else
2246#endif
2247 {
2248 cnt = 1;
2249 /* sync at last item */
2250 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2251 }
2252
2253 if (n < 0L)
2254 rb_sys_fail_on_write(fptr);
2255
2256 total = rb_fix_plus(LONG2FIX(n), total);
2257 }
2258
2259 return total;
2260}
2261
2262/*
2263 * call-seq:
2264 * write(*objects) -> integer
2265 *
2266 * Writes each of the given +objects+ to +self+,
2267 * which must be opened for writing
2268 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2269 * returns the total number bytes written;
2270 * each of +objects+ that is not a string is converted via method +to_s+:
2271 *
2272 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2273 * $stdout.write('foo', :bar, 2, "\n") # => 8
2274 *
2275 * Output:
2276 *
2277 * Hello, World!
2278 * foobar2
2279 *
2280 * Related: IO#read.
2281 */
2282
2283static VALUE
2284io_write_m(int argc, VALUE *argv, VALUE io)
2285{
2286 if (argc != 1) {
2287 return io_writev(argc, argv, io);
2288 }
2289 else {
2290 VALUE str = argv[0];
2291 return io_write(io, str, 0);
2292 }
2293}
2294
2295VALUE
2296rb_io_write(VALUE io, VALUE str)
2297{
2298 return rb_funcallv(io, id_write, 1, &str);
2299}
2300
2301static VALUE
2302rb_io_writev(VALUE io, int argc, const VALUE *argv)
2303{
2304 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2305 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2306 VALUE klass = CLASS_OF(io);
2307 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2309 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2310 " which accepts just one argument",
2311 klass, sep
2312 );
2313 }
2314
2315 do rb_io_write(io, *argv++); while (--argc);
2316
2317 return Qnil;
2318 }
2319
2320 return rb_funcallv(io, id_write, argc, argv);
2321}
2322
2323/*
2324 * call-seq:
2325 * self << object -> self
2326 *
2327 * Writes the given +object+ to +self+,
2328 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2329 * returns +self+;
2330 * if +object+ is not a string, it is converted via method +to_s+:
2331 *
2332 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2333 * $stdout << 'foo' << :bar << 2 << "\n"
2334 *
2335 * Output:
2336 *
2337 * Hello, World!
2338 * foobar2
2339 *
2340 */
2341
2342
2343VALUE
2345{
2346 rb_io_write(io, str);
2347 return io;
2348}
2349
2350#ifdef HAVE_FSYNC
2351static VALUE
2352nogvl_fsync(void *ptr)
2353{
2354 rb_io_t *fptr = ptr;
2355
2356#ifdef _WIN32
2357 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2358 return 0;
2359#endif
2360 return (VALUE)fsync(fptr->fd);
2361}
2362#endif
2363
2364VALUE
2365rb_io_flush_raw(VALUE io, int sync)
2366{
2367 rb_io_t *fptr;
2368
2369 if (!RB_TYPE_P(io, T_FILE)) {
2370 return rb_funcall(io, id_flush, 0);
2371 }
2372
2373 io = GetWriteIO(io);
2374 GetOpenFile(io, fptr);
2375
2376 if (fptr->mode & FMODE_WRITABLE) {
2377 if (io_fflush(fptr) < 0)
2378 rb_sys_fail_on_write(fptr);
2379 }
2380 if (fptr->mode & FMODE_READABLE) {
2381 io_unread(fptr, true);
2382 }
2383
2384 return io;
2385}
2386
2387/*
2388 * call-seq:
2389 * flush -> self
2390 *
2391 * Flushes data buffered in +self+ to the operating system
2392 * (but does not necessarily flush data buffered in the operating system):
2393 *
2394 * $stdout.print 'no newline' # Not necessarily flushed.
2395 * $stdout.flush # Flushed.
2396 *
2397 */
2398
2399VALUE
2400rb_io_flush(VALUE io)
2401{
2402 return rb_io_flush_raw(io, 1);
2403}
2404
2405/*
2406 * call-seq:
2407 * tell -> integer
2408 *
2409 * Returns the current position (in bytes) in +self+
2410 * (see {Position}[rdoc-ref:IO@Position]):
2411 *
2412 * f = File.open('t.txt')
2413 * f.tell # => 0
2414 * f.gets # => "First line\n"
2415 * f.tell # => 12
2416 * f.close
2417 *
2418 * Related: IO#pos=, IO#seek.
2419 */
2420
2421static VALUE
2422rb_io_tell(VALUE io)
2423{
2424 rb_io_t *fptr;
2425 rb_off_t pos;
2426
2427 GetOpenFile(io, fptr);
2428 pos = io_tell(fptr);
2429 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2430 pos -= fptr->rbuf.len;
2431 return OFFT2NUM(pos);
2432}
2433
2434static VALUE
2435rb_io_seek(VALUE io, VALUE offset, int whence)
2436{
2437 rb_io_t *fptr;
2438 rb_off_t pos;
2439
2440 pos = NUM2OFFT(offset);
2441 GetOpenFile(io, fptr);
2442 pos = io_seek(fptr, pos, whence);
2443 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2444
2445 return INT2FIX(0);
2446}
2447
2448static int
2449interpret_seek_whence(VALUE vwhence)
2450{
2451 if (vwhence == sym_SET)
2452 return SEEK_SET;
2453 if (vwhence == sym_CUR)
2454 return SEEK_CUR;
2455 if (vwhence == sym_END)
2456 return SEEK_END;
2457#ifdef SEEK_DATA
2458 if (vwhence == sym_DATA)
2459 return SEEK_DATA;
2460#endif
2461#ifdef SEEK_HOLE
2462 if (vwhence == sym_HOLE)
2463 return SEEK_HOLE;
2464#endif
2465 return NUM2INT(vwhence);
2466}
2467
2468/*
2469 * call-seq:
2470 * seek(offset, whence = IO::SEEK_SET) -> 0
2471 *
2472 * Seeks to the position given by integer +offset+
2473 * (see {Position}[rdoc-ref:IO@Position])
2474 * and constant +whence+, which is one of:
2475 *
2476 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2477 * Repositions the stream to its current position plus the given +offset+:
2478 *
2479 * f = File.open('t.txt')
2480 * f.tell # => 0
2481 * f.seek(20, :CUR) # => 0
2482 * f.tell # => 20
2483 * f.seek(-10, :CUR) # => 0
2484 * f.tell # => 10
2485 * f.close
2486 *
2487 * - +:END+ or <tt>IO::SEEK_END</tt>:
2488 * Repositions the stream to its end plus the given +offset+:
2489 *
2490 * f = File.open('t.txt')
2491 * f.tell # => 0
2492 * f.seek(0, :END) # => 0 # Repositions to stream end.
2493 * f.tell # => 52
2494 * f.seek(-20, :END) # => 0
2495 * f.tell # => 32
2496 * f.seek(-40, :END) # => 0
2497 * f.tell # => 12
2498 * f.close
2499 *
2500 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2501 * Repositions the stream to the given +offset+:
2502 *
2503 * f = File.open('t.txt')
2504 * f.tell # => 0
2505 * f.seek(20, :SET) # => 0
2506 * f.tell # => 20
2507 * f.seek(40, :SET) # => 0
2508 * f.tell # => 40
2509 * f.close
2510 *
2511 * Related: IO#pos=, IO#tell.
2512 *
2513 */
2514
2515static VALUE
2516rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2517{
2518 VALUE offset, ptrname;
2519 int whence = SEEK_SET;
2520
2521 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2522 whence = interpret_seek_whence(ptrname);
2523 }
2524
2525 return rb_io_seek(io, offset, whence);
2526}
2527
2528/*
2529 * call-seq:
2530 * pos = new_position -> new_position
2531 *
2532 * Seeks to the given +new_position+ (in bytes);
2533 * see {Position}[rdoc-ref:IO@Position]:
2534 *
2535 * f = File.open('t.txt')
2536 * f.tell # => 0
2537 * f.pos = 20 # => 20
2538 * f.tell # => 20
2539 * f.close
2540 *
2541 * Related: IO#seek, IO#tell.
2542 *
2543 */
2544
2545static VALUE
2546rb_io_set_pos(VALUE io, VALUE offset)
2547{
2548 rb_io_t *fptr;
2549 rb_off_t pos;
2550
2551 pos = NUM2OFFT(offset);
2552 GetOpenFile(io, fptr);
2553 pos = io_seek(fptr, pos, SEEK_SET);
2554 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2555
2556 return OFFT2NUM(pos);
2557}
2558
2559static void clear_readconv(rb_io_t *fptr);
2560
2561/*
2562 * call-seq:
2563 * rewind -> 0
2564 *
2565 * Repositions the stream to its beginning,
2566 * setting both the position and the line number to zero;
2567 * see {Position}[rdoc-ref:IO@Position]
2568 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2569 *
2570 * f = File.open('t.txt')
2571 * f.tell # => 0
2572 * f.lineno # => 0
2573 * f.gets # => "First line\n"
2574 * f.tell # => 12
2575 * f.lineno # => 1
2576 * f.rewind # => 0
2577 * f.tell # => 0
2578 * f.lineno # => 0
2579 * f.close
2580 *
2581 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2582 *
2583 */
2584
2585static VALUE
2586rb_io_rewind(VALUE io)
2587{
2588 rb_io_t *fptr;
2589
2590 GetOpenFile(io, fptr);
2591 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2592 if (io == ARGF.current_file) {
2593 ARGF.lineno -= fptr->lineno;
2594 }
2595 fptr->lineno = 0;
2596 if (fptr->readconv) {
2597 clear_readconv(fptr);
2598 }
2599
2600 return INT2FIX(0);
2601}
2602
2603static int
2604fptr_wait_readable(rb_io_t *fptr)
2605{
2606 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2607
2608 if (result)
2609 rb_io_check_closed(fptr);
2610
2611 return result;
2612}
2613
2614static int
2615io_fillbuf(rb_io_t *fptr)
2616{
2617 ssize_t r;
2618
2619 if (fptr->rbuf.ptr == NULL) {
2620 fptr->rbuf.off = 0;
2621 fptr->rbuf.len = 0;
2622 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2623 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2624#ifdef _WIN32
2625 fptr->rbuf.capa--;
2626#endif
2627 }
2628 if (fptr->rbuf.len == 0) {
2629 retry:
2630 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2631
2632 if (r < 0) {
2633 if (fptr_wait_readable(fptr))
2634 goto retry;
2635
2636 int e = errno;
2637 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2638 if (!NIL_P(fptr->pathv)) {
2639 rb_str_append(path, fptr->pathv);
2640 }
2641
2642 rb_syserr_fail_path(e, path);
2643 }
2644 if (r > 0) rb_io_check_closed(fptr);
2645 fptr->rbuf.off = 0;
2646 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2647 if (r == 0)
2648 return -1; /* EOF */
2649 }
2650 return 0;
2651}
2652
2653/*
2654 * call-seq:
2655 * eof -> true or false
2656 *
2657 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2658 * see {Position}[rdoc-ref:IO@Position]:
2659 *
2660 * f = File.open('t.txt')
2661 * f.eof # => false
2662 * f.seek(0, :END) # => 0
2663 * f.eof # => true
2664 * f.close
2665 *
2666 * Raises an exception unless the stream is opened for reading;
2667 * see {Mode}[rdoc-ref:File@Access+Modes].
2668 *
2669 * If +self+ is a stream such as pipe or socket, this method
2670 * blocks until the other end sends some data or closes it:
2671 *
2672 * r, w = IO.pipe
2673 * Thread.new { sleep 1; w.close }
2674 * r.eof? # => true # After 1-second wait.
2675 *
2676 * r, w = IO.pipe
2677 * Thread.new { sleep 1; w.puts "a" }
2678 * r.eof? # => false # After 1-second wait.
2679 *
2680 * r, w = IO.pipe
2681 * r.eof? # blocks forever
2682 *
2683 * Note that this method reads data to the input byte buffer. So
2684 * IO#sysread may not behave as you intend with IO#eof?, unless you
2685 * call IO#rewind first (which is not available for some streams).
2686 */
2687
2688VALUE
2690{
2691 rb_io_t *fptr;
2692
2693 GetOpenFile(io, fptr);
2695
2696 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2697 if (READ_DATA_PENDING(fptr)) return Qfalse;
2698 READ_CHECK(fptr);
2699#if RUBY_CRLF_ENVIRONMENT
2700 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2701 return RBOOL(eof(fptr->fd));
2702 }
2703#endif
2704 return RBOOL(io_fillbuf(fptr) < 0);
2705}
2706
2707/*
2708 * call-seq:
2709 * sync -> true or false
2710 *
2711 * Returns the current sync mode of the stream.
2712 * When sync mode is true, all output is immediately flushed to the underlying
2713 * operating system and is not buffered by Ruby internally. See also #fsync.
2714 *
2715 * f = File.open('t.tmp', 'w')
2716 * f.sync # => false
2717 * f.sync = true
2718 * f.sync # => true
2719 * f.close
2720 *
2721 */
2722
2723static VALUE
2724rb_io_sync(VALUE io)
2725{
2726 rb_io_t *fptr;
2727
2728 io = GetWriteIO(io);
2729 GetOpenFile(io, fptr);
2730 return RBOOL(fptr->mode & FMODE_SYNC);
2731}
2732
2733#ifdef HAVE_FSYNC
2734
2735/*
2736 * call-seq:
2737 * sync = boolean -> boolean
2738 *
2739 * Sets the _sync_ _mode_ for the stream to the given value;
2740 * returns the given value.
2741 *
2742 * Values for the sync mode:
2743 *
2744 * - +true+: All output is immediately flushed to the
2745 * underlying operating system and is not buffered internally.
2746 * - +false+: Output may be buffered internally.
2747 *
2748 * Example;
2749 *
2750 * f = File.open('t.tmp', 'w')
2751 * f.sync # => false
2752 * f.sync = true
2753 * f.sync # => true
2754 * f.close
2755 *
2756 * Related: IO#fsync.
2757 *
2758 */
2759
2760static VALUE
2761rb_io_set_sync(VALUE io, VALUE sync)
2762{
2763 rb_io_t *fptr;
2764
2765 io = GetWriteIO(io);
2766 GetOpenFile(io, fptr);
2767 if (RTEST(sync)) {
2768 fptr->mode |= FMODE_SYNC;
2769 }
2770 else {
2771 fptr->mode &= ~FMODE_SYNC;
2772 }
2773 return sync;
2774}
2775
2776/*
2777 * call-seq:
2778 * fsync -> 0
2779 *
2780 * Immediately writes to disk all data buffered in the stream,
2781 * via the operating system's <tt>fsync(2)</tt>.
2782
2783 * Note this difference:
2784 *
2785 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2786 * but does not guarantee that the operating system actually writes the data to disk.
2787 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2788 * and that data is written to disk.
2789 *
2790 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2791 *
2792 */
2793
2794static VALUE
2795rb_io_fsync(VALUE io)
2796{
2797 rb_io_t *fptr;
2798
2799 io = GetWriteIO(io);
2800 GetOpenFile(io, fptr);
2801
2802 if (io_fflush(fptr) < 0)
2803 rb_sys_fail_on_write(fptr);
2804
2805 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2806 rb_sys_fail_path(fptr->pathv);
2807
2808 return INT2FIX(0);
2809}
2810#else
2811# define rb_io_fsync rb_f_notimplement
2812# define rb_io_sync rb_f_notimplement
2813static VALUE
2814rb_io_set_sync(VALUE io, VALUE sync)
2815{
2818}
2819#endif
2820
2821#ifdef HAVE_FDATASYNC
2822static VALUE
2823nogvl_fdatasync(void *ptr)
2824{
2825 rb_io_t *fptr = ptr;
2826
2827#ifdef _WIN32
2828 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2829 return 0;
2830#endif
2831 return (VALUE)fdatasync(fptr->fd);
2832}
2833
2834/*
2835 * call-seq:
2836 * fdatasync -> 0
2837 *
2838 * Immediately writes to disk all data buffered in the stream,
2839 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2840 * otherwise via <tt>fsync(2)</tt>, if supported;
2841 * otherwise raises an exception.
2842 *
2843 */
2844
2845static VALUE
2846rb_io_fdatasync(VALUE io)
2847{
2848 rb_io_t *fptr;
2849
2850 io = GetWriteIO(io);
2851 GetOpenFile(io, fptr);
2852
2853 if (io_fflush(fptr) < 0)
2854 rb_sys_fail_on_write(fptr);
2855
2856 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2857 return INT2FIX(0);
2858
2859 /* fall back */
2860 return rb_io_fsync(io);
2861}
2862#else
2863#define rb_io_fdatasync rb_io_fsync
2864#endif
2865
2866/*
2867 * call-seq:
2868 * fileno -> integer
2869 *
2870 * Returns the integer file descriptor for the stream:
2871 *
2872 * $stdin.fileno # => 0
2873 * $stdout.fileno # => 1
2874 * $stderr.fileno # => 2
2875 * File.open('t.txt').fileno # => 10
2876 * f.close
2877 *
2878 */
2879
2880static VALUE
2881rb_io_fileno(VALUE io)
2882{
2883 rb_io_t *fptr = RFILE(io)->fptr;
2884 int fd;
2885
2886 rb_io_check_closed(fptr);
2887 fd = fptr->fd;
2888 return INT2FIX(fd);
2889}
2890
2891int
2893{
2894 if (RB_TYPE_P(io, T_FILE)) {
2895 rb_io_t *fptr = RFILE(io)->fptr;
2896 rb_io_check_closed(fptr);
2897 return fptr->fd;
2898 }
2899 else {
2900 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2901 if (!UNDEF_P(fileno)) {
2902 return RB_NUM2INT(fileno);
2903 }
2904 }
2905
2906 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2907
2909}
2910
2911int
2913{
2914 rb_io_t *fptr;
2915 GetOpenFile(io, fptr);
2916 return fptr->mode;
2917}
2918
2919/*
2920 * call-seq:
2921 * pid -> integer or nil
2922 *
2923 * Returns the process ID of a child process associated with the stream,
2924 * which will have been set by IO#popen, or +nil+ if the stream was not
2925 * created by IO#popen:
2926 *
2927 * pipe = IO.popen("-")
2928 * if pipe
2929 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2930 * else
2931 * $stderr.puts "In child, pid is #{$$}"
2932 * end
2933 *
2934 * Output:
2935 *
2936 * In child, pid is 26209
2937 * In parent, child pid is 26209
2938 *
2939 */
2940
2941static VALUE
2942rb_io_pid(VALUE io)
2943{
2944 rb_io_t *fptr;
2945
2946 GetOpenFile(io, fptr);
2947 if (!fptr->pid)
2948 return Qnil;
2949 return PIDT2NUM(fptr->pid);
2950}
2951
2952/*
2953 * call-seq:
2954 * path -> string or nil
2955 *
2956 * Returns the path associated with the IO, or +nil+ if there is no path
2957 * associated with the IO. It is not guaranteed that the path exists on
2958 * the filesystem.
2959 *
2960 * $stdin.path # => "<STDIN>"
2961 *
2962 * File.open("testfile") {|f| f.path} # => "testfile"
2963 */
2964
2965VALUE
2967{
2968 rb_io_t *fptr = RFILE(io)->fptr;
2969
2970 if (!fptr)
2971 return Qnil;
2972
2973 return rb_obj_dup(fptr->pathv);
2974}
2975
2976/*
2977 * call-seq:
2978 * inspect -> string
2979 *
2980 * Returns a string representation of +self+:
2981 *
2982 * f = File.open('t.txt')
2983 * f.inspect # => "#<File:t.txt>"
2984 * f.close
2985 *
2986 */
2987
2988static VALUE
2989rb_io_inspect(VALUE obj)
2990{
2991 rb_io_t *fptr;
2992 VALUE result;
2993 static const char closed[] = " (closed)";
2994
2995 fptr = RFILE(obj)->fptr;
2996 if (!fptr) return rb_any_to_s(obj);
2997 result = rb_str_new_cstr("#<");
2998 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2999 rb_str_cat2(result, ":");
3000 if (NIL_P(fptr->pathv)) {
3001 if (fptr->fd < 0) {
3002 rb_str_cat(result, closed+1, strlen(closed)-1);
3003 }
3004 else {
3005 rb_str_catf(result, "fd %d", fptr->fd);
3006 }
3007 }
3008 else {
3009 rb_str_append(result, fptr->pathv);
3010 if (fptr->fd < 0) {
3011 rb_str_cat(result, closed, strlen(closed));
3012 }
3013 }
3014 return rb_str_cat2(result, ">");
3015}
3016
3017/*
3018 * call-seq:
3019 * to_io -> self
3020 *
3021 * Returns +self+.
3022 *
3023 */
3024
3025static VALUE
3026rb_io_to_io(VALUE io)
3027{
3028 return io;
3029}
3030
3031/* reading functions */
3032static long
3033read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3034{
3035 int n;
3036
3037 n = READ_DATA_PENDING_COUNT(fptr);
3038 if (n <= 0) return 0;
3039 if (n > len) n = (int)len;
3040 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3041 fptr->rbuf.off += n;
3042 fptr->rbuf.len -= n;
3043 return n;
3044}
3045
3046static long
3047io_bufread(char *ptr, long len, rb_io_t *fptr)
3048{
3049 long offset = 0;
3050 long n = len;
3051 long c;
3052
3053 if (READ_DATA_PENDING(fptr) == 0) {
3054 while (n > 0) {
3055 again:
3056 rb_io_check_closed(fptr);
3057 c = rb_io_read_memory(fptr, ptr+offset, n);
3058 if (c == 0) break;
3059 if (c < 0) {
3060 if (fptr_wait_readable(fptr))
3061 goto again;
3062 return -1;
3063 }
3064 offset += c;
3065 if ((n -= c) <= 0) break;
3066 }
3067 return len - n;
3068 }
3069
3070 while (n > 0) {
3071 c = read_buffered_data(ptr+offset, n, fptr);
3072 if (c > 0) {
3073 offset += c;
3074 if ((n -= c) <= 0) break;
3075 }
3076 rb_io_check_closed(fptr);
3077 if (io_fillbuf(fptr) < 0) {
3078 break;
3079 }
3080 }
3081 return len - n;
3082}
3083
3084static int io_setstrbuf(VALUE *str, long len);
3085
3087 char *str_ptr;
3088 long len;
3089 rb_io_t *fptr;
3090};
3091
3092static VALUE
3093bufread_call(VALUE arg)
3094{
3095 struct bufread_arg *p = (struct bufread_arg *)arg;
3096 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3097 return Qundef;
3098}
3099
3100static long
3101io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3102{
3103 long len;
3104 struct bufread_arg arg;
3105
3106 io_setstrbuf(&str, offset + size);
3107 arg.str_ptr = RSTRING_PTR(str) + offset;
3108 arg.len = size;
3109 arg.fptr = fptr;
3110 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3111 len = arg.len;
3112 if (len < 0) rb_sys_fail_path(fptr->pathv);
3113 return len;
3114}
3115
3116static long
3117remain_size(rb_io_t *fptr)
3118{
3119 struct stat st;
3120 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3121 rb_off_t pos;
3122
3123 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3124#if defined(__HAIKU__)
3125 && (st.st_dev > 3)
3126#endif
3127 )
3128 {
3129 if (io_fflush(fptr) < 0)
3130 rb_sys_fail_on_write(fptr);
3131 pos = lseek(fptr->fd, 0, SEEK_CUR);
3132 if (st.st_size >= pos && pos >= 0) {
3133 siz += st.st_size - pos;
3134 if (siz > LONG_MAX) {
3135 rb_raise(rb_eIOError, "file too big for single read");
3136 }
3137 }
3138 }
3139 else {
3140 siz += BUFSIZ;
3141 }
3142 return (long)siz;
3143}
3144
3145static VALUE
3146io_enc_str(VALUE str, rb_io_t *fptr)
3147{
3148 rb_enc_associate(str, io_read_encoding(fptr));
3149 return str;
3150}
3151
3152static rb_encoding *io_read_encoding(rb_io_t *fptr);
3153
3154static void
3155make_readconv(rb_io_t *fptr, int size)
3156{
3157 if (!fptr->readconv) {
3158 int ecflags;
3159 VALUE ecopts;
3160 const char *sname, *dname;
3161 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3162 ecopts = fptr->encs.ecopts;
3163 if (fptr->encs.enc2) {
3164 sname = rb_enc_name(fptr->encs.enc2);
3165 dname = rb_enc_name(io_read_encoding(fptr));
3166 }
3167 else {
3168 sname = dname = "";
3169 }
3170 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3171 if (!fptr->readconv)
3172 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3173 fptr->cbuf.off = 0;
3174 fptr->cbuf.len = 0;
3175 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3176 fptr->cbuf.capa = size;
3177 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3178 }
3179}
3180
3181#define MORE_CHAR_SUSPENDED Qtrue
3182#define MORE_CHAR_FINISHED Qnil
3183static VALUE
3184fill_cbuf(rb_io_t *fptr, int ec_flags)
3185{
3186 const unsigned char *ss, *sp, *se;
3187 unsigned char *ds, *dp, *de;
3189 int putbackable;
3190 int cbuf_len0;
3191 VALUE exc;
3192
3193 ec_flags |= ECONV_PARTIAL_INPUT;
3194
3195 if (fptr->cbuf.len == fptr->cbuf.capa)
3196 return MORE_CHAR_SUSPENDED; /* cbuf full */
3197 if (fptr->cbuf.len == 0)
3198 fptr->cbuf.off = 0;
3199 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3200 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3201 fptr->cbuf.off = 0;
3202 }
3203
3204 cbuf_len0 = fptr->cbuf.len;
3205
3206 while (1) {
3207 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3208 se = sp + fptr->rbuf.len;
3209 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3210 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3211 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3212 fptr->rbuf.off += (int)(sp - ss);
3213 fptr->rbuf.len -= (int)(sp - ss);
3214 fptr->cbuf.len += (int)(dp - ds);
3215
3216 putbackable = rb_econv_putbackable(fptr->readconv);
3217 if (putbackable) {
3218 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3219 fptr->rbuf.off -= putbackable;
3220 fptr->rbuf.len += putbackable;
3221 }
3222
3223 exc = rb_econv_make_exception(fptr->readconv);
3224 if (!NIL_P(exc))
3225 return exc;
3226
3227 if (cbuf_len0 != fptr->cbuf.len)
3228 return MORE_CHAR_SUSPENDED;
3229
3230 if (res == econv_finished) {
3231 return MORE_CHAR_FINISHED;
3232 }
3233
3234 if (res == econv_source_buffer_empty) {
3235 if (fptr->rbuf.len == 0) {
3236 READ_CHECK(fptr);
3237 if (io_fillbuf(fptr) < 0) {
3238 if (!fptr->readconv) {
3239 return MORE_CHAR_FINISHED;
3240 }
3241 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3242 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3243 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3244 fptr->cbuf.len += (int)(dp - ds);
3246 break;
3247 }
3248 }
3249 }
3250 }
3251 if (cbuf_len0 != fptr->cbuf.len)
3252 return MORE_CHAR_SUSPENDED;
3253
3254 return MORE_CHAR_FINISHED;
3255}
3256
3257static VALUE
3258more_char(rb_io_t *fptr)
3259{
3260 VALUE v;
3261 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3262 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3263 rb_exc_raise(v);
3264 return v;
3265}
3266
3267static VALUE
3268io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3269{
3270 VALUE str = Qnil;
3271 if (strp) {
3272 str = *strp;
3273 if (NIL_P(str)) {
3274 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3275 }
3276 else {
3277 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3278 }
3279 rb_enc_associate(str, fptr->encs.enc);
3280 }
3281 fptr->cbuf.off += len;
3282 fptr->cbuf.len -= len;
3283 /* xxx: set coderange */
3284 if (fptr->cbuf.len == 0)
3285 fptr->cbuf.off = 0;
3286 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3287 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3288 fptr->cbuf.off = 0;
3289 }
3290 return str;
3291}
3292
3293static int
3294io_setstrbuf(VALUE *str, long len)
3295{
3296#ifdef _WIN32
3297 if (len > 0)
3298 len = (len + 1) & ~1L; /* round up for wide char */
3299#endif
3300 if (NIL_P(*str)) {
3301 *str = rb_str_new(0, len);
3302 return TRUE;
3303 }
3304 else {
3305 VALUE s = StringValue(*str);
3306 rb_str_modify(s);
3307
3308 long clen = RSTRING_LEN(s);
3309 if (clen >= len) {
3310 return FALSE;
3311 }
3312 len -= clen;
3313 }
3314 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3316 }
3317 return FALSE;
3318}
3319
3320#define MAX_REALLOC_GAP 4096
3321static void
3322io_shrink_read_string(VALUE str, long n)
3323{
3324 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3325 rb_str_resize(str, n);
3326 }
3327}
3328
3329static void
3330io_set_read_length(VALUE str, long n, int shrinkable)
3331{
3332 if (RSTRING_LEN(str) != n) {
3333 rb_str_modify(str);
3334 rb_str_set_len(str, n);
3335 if (shrinkable) io_shrink_read_string(str, n);
3336 }
3337}
3338
3339static VALUE
3340read_all(rb_io_t *fptr, long siz, VALUE str)
3341{
3342 long bytes;
3343 long n;
3344 long pos;
3345 rb_encoding *enc;
3346 int cr;
3347 int shrinkable;
3348
3349 if (NEED_READCONV(fptr)) {
3350 int first = !NIL_P(str);
3351 SET_BINARY_MODE(fptr);
3352 shrinkable = io_setstrbuf(&str,0);
3353 make_readconv(fptr, 0);
3354 while (1) {
3355 VALUE v;
3356 if (fptr->cbuf.len) {
3357 if (first) rb_str_set_len(str, first = 0);
3358 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3359 }
3360 v = fill_cbuf(fptr, 0);
3361 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3362 if (fptr->cbuf.len) {
3363 if (first) rb_str_set_len(str, first = 0);
3364 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3365 }
3366 rb_exc_raise(v);
3367 }
3368 if (v == MORE_CHAR_FINISHED) {
3369 clear_readconv(fptr);
3370 if (first) rb_str_set_len(str, first = 0);
3371 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3372 return io_enc_str(str, fptr);
3373 }
3374 }
3375 }
3376
3377 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3378 bytes = 0;
3379 pos = 0;
3380
3381 enc = io_read_encoding(fptr);
3382 cr = 0;
3383
3384 if (siz == 0) siz = BUFSIZ;
3385 shrinkable = io_setstrbuf(&str, siz);
3386 for (;;) {
3387 READ_CHECK(fptr);
3388 n = io_fread(str, bytes, siz - bytes, fptr);
3389 if (n == 0 && bytes == 0) {
3390 rb_str_set_len(str, 0);
3391 break;
3392 }
3393 bytes += n;
3394 rb_str_set_len(str, bytes);
3395 if (cr != ENC_CODERANGE_BROKEN)
3396 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3397 if (bytes < siz) break;
3398 siz += BUFSIZ;
3399
3400 size_t capa = rb_str_capacity(str);
3401 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3402 if (capa < BUFSIZ) {
3403 capa = BUFSIZ;
3404 }
3405 else if (capa > IO_MAX_BUFFER_GROWTH) {
3406 capa = IO_MAX_BUFFER_GROWTH;
3407 }
3409 }
3410 }
3411 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3412 str = io_enc_str(str, fptr);
3413 ENC_CODERANGE_SET(str, cr);
3414 return str;
3415}
3416
3417void
3419{
3420 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3421 rb_sys_fail_path(fptr->pathv);
3422 }
3423}
3424
3425static VALUE
3426io_read_memory_call(VALUE arg)
3427{
3428 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3429
3430 VALUE scheduler = rb_fiber_scheduler_current();
3431 if (scheduler != Qnil) {
3432 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3433
3434 if (!UNDEF_P(result)) {
3435 // This is actually returned as a pseudo-VALUE and later cast to a long:
3437 }
3438 }
3439
3440 if (iis->nonblock) {
3441 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3442 }
3443 else {
3444 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3445 }
3446}
3447
3448static long
3449io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3450{
3451 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3452}
3453
3454#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3455
3456static VALUE
3457io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3458{
3459 rb_io_t *fptr;
3460 VALUE length, str;
3461 long n, len;
3462 struct io_internal_read_struct iis;
3463 int shrinkable;
3464
3465 rb_scan_args(argc, argv, "11", &length, &str);
3466
3467 if ((len = NUM2LONG(length)) < 0) {
3468 rb_raise(rb_eArgError, "negative length %ld given", len);
3469 }
3470
3471 shrinkable = io_setstrbuf(&str, len);
3472
3473 GetOpenFile(io, fptr);
3475
3476 if (len == 0) {
3477 io_set_read_length(str, 0, shrinkable);
3478 return str;
3479 }
3480
3481 if (!nonblock)
3482 READ_CHECK(fptr);
3483 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3484 if (n <= 0) {
3485 again:
3486 if (nonblock) {
3487 rb_io_set_nonblock(fptr);
3488 }
3489 io_setstrbuf(&str, len);
3490 iis.th = rb_thread_current();
3491 iis.fptr = fptr;
3492 iis.nonblock = nonblock;
3493 iis.fd = fptr->fd;
3494 iis.buf = RSTRING_PTR(str);
3495 iis.capa = len;
3496 iis.timeout = NULL;
3497 n = io_read_memory_locktmp(str, &iis);
3498 if (n < 0) {
3499 int e = errno;
3500 if (!nonblock && fptr_wait_readable(fptr))
3501 goto again;
3502 if (nonblock && (io_again_p(e))) {
3503 if (no_exception)
3504 return sym_wait_readable;
3505 else
3506 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3507 e, "read would block");
3508 }
3509 rb_syserr_fail_path(e, fptr->pathv);
3510 }
3511 }
3512 io_set_read_length(str, n, shrinkable);
3513
3514 if (n == 0)
3515 return Qnil;
3516 else
3517 return str;
3518}
3519
3520/*
3521 * call-seq:
3522 * readpartial(maxlen) -> string
3523 * readpartial(maxlen, out_string) -> out_string
3524 *
3525 * Reads up to +maxlen+ bytes from the stream;
3526 * returns a string (either a new string or the given +out_string+).
3527 * Its encoding is:
3528 *
3529 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3530 * - ASCII-8BIT, otherwise.
3531 *
3532 * - Contains +maxlen+ bytes from the stream, if available.
3533 * - Otherwise contains all available bytes, if any available.
3534 * - Otherwise is an empty string.
3535 *
3536 * With the single non-negative integer argument +maxlen+ given,
3537 * returns a new string:
3538 *
3539 * f = File.new('t.txt')
3540 * f.readpartial(20) # => "First line\nSecond l"
3541 * f.readpartial(20) # => "ine\n\nFourth line\n"
3542 * f.readpartial(20) # => "Fifth line\n"
3543 * f.readpartial(20) # Raises EOFError.
3544 * f.close
3545 *
3546 * With both argument +maxlen+ and string argument +out_string+ given,
3547 * returns modified +out_string+:
3548 *
3549 * f = File.new('t.txt')
3550 * s = 'foo'
3551 * f.readpartial(20, s) # => "First line\nSecond l"
3552 * s = 'bar'
3553 * f.readpartial(0, s) # => ""
3554 * f.close
3555 *
3556 * This method is useful for a stream such as a pipe, a socket, or a tty.
3557 * It blocks only when no data is immediately available.
3558 * This means that it blocks only when _all_ of the following are true:
3559 *
3560 * - The byte buffer in the stream is empty.
3561 * - The content of the stream is empty.
3562 * - The stream is not at EOF.
3563 *
3564 * When blocked, the method waits for either more data or EOF on the stream:
3565 *
3566 * - If more data is read, the method returns the data.
3567 * - If EOF is reached, the method raises EOFError.
3568 *
3569 * When not blocked, the method responds immediately:
3570 *
3571 * - Returns data from the buffer if there is any.
3572 * - Otherwise returns data from the stream if there is any.
3573 * - Otherwise raises EOFError if the stream has reached EOF.
3574 *
3575 * Note that this method is similar to sysread. The differences are:
3576 *
3577 * - If the byte buffer is not empty, read from the byte buffer
3578 * instead of "sysread for buffered IO (IOError)".
3579 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3580 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3581 * readpartial retries the system call.
3582 *
3583 * The latter means that readpartial is non-blocking-flag insensitive.
3584 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3585 * if the fd is blocking mode.
3586 *
3587 * Examples:
3588 *
3589 * # # Returned Buffer Content Pipe Content
3590 * r, w = IO.pipe #
3591 * w << 'abc' # "" "abc".
3592 * r.readpartial(4096) # => "abc" "" ""
3593 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3594 *
3595 * # # Returned Buffer Content Pipe Content
3596 * r, w = IO.pipe #
3597 * w << 'abc' # "" "abc"
3598 * w.close # "" "abc" EOF
3599 * r.readpartial(4096) # => "abc" "" EOF
3600 * r.readpartial(4096) # raises EOFError
3601 *
3602 * # # Returned Buffer Content Pipe Content
3603 * r, w = IO.pipe #
3604 * w << "abc\ndef\n" # "" "abc\ndef\n"
3605 * r.gets # => "abc\n" "def\n" ""
3606 * w << "ghi\n" # "def\n" "ghi\n"
3607 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3608 * r.readpartial(4096) # => "ghi\n" "" ""
3609 *
3610 */
3611
3612static VALUE
3613io_readpartial(int argc, VALUE *argv, VALUE io)
3614{
3615 VALUE ret;
3616
3617 ret = io_getpartial(argc, argv, io, Qnil, 0);
3618 if (NIL_P(ret))
3619 rb_eof_error();
3620 return ret;
3621}
3622
3623static VALUE
3624io_nonblock_eof(int no_exception)
3625{
3626 if (!no_exception) {
3627 rb_eof_error();
3628 }
3629 return Qnil;
3630}
3631
3632/* :nodoc: */
3633static VALUE
3634io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3635{
3636 rb_io_t *fptr;
3637 long n, len;
3638 struct io_internal_read_struct iis;
3639 int shrinkable;
3640
3641 if ((len = NUM2LONG(length)) < 0) {
3642 rb_raise(rb_eArgError, "negative length %ld given", len);
3643 }
3644
3645 shrinkable = io_setstrbuf(&str, len);
3646 rb_bool_expected(ex, "exception", TRUE);
3647
3648 GetOpenFile(io, fptr);
3650
3651 if (len == 0) {
3652 io_set_read_length(str, 0, shrinkable);
3653 return str;
3654 }
3655
3656 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3657 if (n <= 0) {
3658 rb_fd_set_nonblock(fptr->fd);
3659 shrinkable |= io_setstrbuf(&str, len);
3660 iis.fptr = fptr;
3661 iis.nonblock = 1;
3662 iis.fd = fptr->fd;
3663 iis.buf = RSTRING_PTR(str);
3664 iis.capa = len;
3665 iis.timeout = NULL;
3666 n = io_read_memory_locktmp(str, &iis);
3667 if (n < 0) {
3668 int e = errno;
3669 if (io_again_p(e)) {
3670 if (!ex) return sym_wait_readable;
3671 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3672 e, "read would block");
3673 }
3674 rb_syserr_fail_path(e, fptr->pathv);
3675 }
3676 }
3677 io_set_read_length(str, n, shrinkable);
3678
3679 if (n == 0) {
3680 if (!ex) return Qnil;
3681 rb_eof_error();
3682 }
3683
3684 return str;
3685}
3686
3687/* :nodoc: */
3688static VALUE
3689io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3690{
3691 rb_io_t *fptr;
3692 long n;
3693
3694 if (!RB_TYPE_P(str, T_STRING))
3695 str = rb_obj_as_string(str);
3696 rb_bool_expected(ex, "exception", TRUE);
3697
3698 io = GetWriteIO(io);
3699 GetOpenFile(io, fptr);
3701
3702 if (io_fflush(fptr) < 0)
3703 rb_sys_fail_on_write(fptr);
3704
3705 rb_fd_set_nonblock(fptr->fd);
3706 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3707 RB_GC_GUARD(str);
3708
3709 if (n < 0) {
3710 int e = errno;
3711 if (io_again_p(e)) {
3712 if (!ex) {
3713 return sym_wait_writable;
3714 }
3715 else {
3716 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3717 }
3718 }
3719 rb_syserr_fail_path(e, fptr->pathv);
3720 }
3721
3722 return LONG2FIX(n);
3723}
3724
3725/*
3726 * call-seq:
3727 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3728 *
3729 * Reads bytes from the stream; the stream must be opened for reading
3730 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3731 *
3732 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3733 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3734 *
3735 * Returns a string (either a new string or the given +out_string+)
3736 * containing the bytes read.
3737 * The encoding of the string depends on both +maxLen+ and +out_string+:
3738 *
3739 * - +maxlen+ is +nil+: uses internal encoding of +self+
3740 * (regardless of whether +out_string+ was given).
3741 * - +maxlen+ not +nil+:
3742 *
3743 * - +out_string+ given: encoding of +out_string+ not modified.
3744 * - +out_string+ not given: ASCII-8BIT is used.
3745 *
3746 * <b>Without Argument +out_string+</b>
3747 *
3748 * When argument +out_string+ is omitted,
3749 * the returned value is a new string:
3750 *
3751 * f = File.new('t.txt')
3752 * f.read
3753 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3754 * f.rewind
3755 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3756 * f.read(30) # => "rth line\r\nFifth line\r\n"
3757 * f.read(30) # => nil
3758 * f.close
3759 *
3760 * If +maxlen+ is zero, returns an empty string.
3761 *
3762 * <b> With Argument +out_string+</b>
3763 *
3764 * When argument +out_string+ is given,
3765 * the returned value is +out_string+, whose content is replaced:
3766 *
3767 * f = File.new('t.txt')
3768 * s = 'foo' # => "foo"
3769 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3770 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3771 * f.rewind
3772 * s = 'bar'
3773 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3774 * s # => "First line\r\nSecond line\r\n\r\nFou"
3775 * s = 'baz'
3776 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3777 * s # => "rth line\r\nFifth line\r\n"
3778 * s = 'bat'
3779 * f.read(30, s) # => nil
3780 * s # => ""
3781 * f.close
3782 *
3783 * Note that this method behaves like the fread() function in C.
3784 * This means it retries to invoke read(2) system calls to read data
3785 * with the specified maxlen (or until EOF).
3786 *
3787 * This behavior is preserved even if the stream is in non-blocking mode.
3788 * (This method is non-blocking-flag insensitive as other methods.)
3789 *
3790 * If you need the behavior like a single read(2) system call,
3791 * consider #readpartial, #read_nonblock, and #sysread.
3792 *
3793 * Related: IO#write.
3794 */
3795
3796static VALUE
3797io_read(int argc, VALUE *argv, VALUE io)
3798{
3799 rb_io_t *fptr;
3800 long n, len;
3801 VALUE length, str;
3802 int shrinkable;
3803#if RUBY_CRLF_ENVIRONMENT
3804 int previous_mode;
3805#endif
3806
3807 rb_scan_args(argc, argv, "02", &length, &str);
3808
3809 if (NIL_P(length)) {
3810 GetOpenFile(io, fptr);
3812 return read_all(fptr, remain_size(fptr), str);
3813 }
3814 len = NUM2LONG(length);
3815 if (len < 0) {
3816 rb_raise(rb_eArgError, "negative length %ld given", len);
3817 }
3818
3819 shrinkable = io_setstrbuf(&str,len);
3820
3821 GetOpenFile(io, fptr);
3823 if (len == 0) {
3824 io_set_read_length(str, 0, shrinkable);
3825 return str;
3826 }
3827
3828 READ_CHECK(fptr);
3829#if RUBY_CRLF_ENVIRONMENT
3830 previous_mode = set_binary_mode_with_seek_cur(fptr);
3831#endif
3832 n = io_fread(str, 0, len, fptr);
3833 io_set_read_length(str, n, shrinkable);
3834#if RUBY_CRLF_ENVIRONMENT
3835 if (previous_mode == O_TEXT) {
3836 setmode(fptr->fd, O_TEXT);
3837 }
3838#endif
3839 if (n == 0) return Qnil;
3840
3841 return str;
3842}
3843
3844static void
3845rscheck(const char *rsptr, long rslen, VALUE rs)
3846{
3847 if (!rs) return;
3848 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3849 rb_raise(rb_eRuntimeError, "rs modified");
3850}
3851
3852static const char *
3853search_delim(const char *p, long len, int delim, rb_encoding *enc)
3854{
3855 if (rb_enc_mbminlen(enc) == 1) {
3856 p = memchr(p, delim, len);
3857 if (p) return p + 1;
3858 }
3859 else {
3860 const char *end = p + len;
3861 while (p < end) {
3862 int r = rb_enc_precise_mbclen(p, end, enc);
3863 if (!MBCLEN_CHARFOUND_P(r)) {
3864 p += rb_enc_mbminlen(enc);
3865 continue;
3866 }
3867 int n = MBCLEN_CHARFOUND_LEN(r);
3868 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3869 return p + n;
3870 }
3871 p += n;
3872 }
3873 }
3874 return NULL;
3875}
3876
3877static int
3878appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3879{
3880 VALUE str = *strp;
3881 long limit = *lp;
3882
3883 if (NEED_READCONV(fptr)) {
3884 SET_BINARY_MODE(fptr);
3885 make_readconv(fptr, 0);
3886 do {
3887 const char *p, *e;
3888 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3889 if (searchlen) {
3890 p = READ_CHAR_PENDING_PTR(fptr);
3891 if (0 < limit && limit < searchlen)
3892 searchlen = (int)limit;
3893 e = search_delim(p, searchlen, delim, enc);
3894 if (e) {
3895 int len = (int)(e-p);
3896 if (NIL_P(str))
3897 *strp = str = rb_str_new(p, len);
3898 else
3899 rb_str_buf_cat(str, p, len);
3900 fptr->cbuf.off += len;
3901 fptr->cbuf.len -= len;
3902 limit -= len;
3903 *lp = limit;
3904 return delim;
3905 }
3906
3907 if (NIL_P(str))
3908 *strp = str = rb_str_new(p, searchlen);
3909 else
3910 rb_str_buf_cat(str, p, searchlen);
3911 fptr->cbuf.off += searchlen;
3912 fptr->cbuf.len -= searchlen;
3913 limit -= searchlen;
3914
3915 if (limit == 0) {
3916 *lp = limit;
3917 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3918 }
3919 }
3920 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3921 clear_readconv(fptr);
3922 *lp = limit;
3923 return EOF;
3924 }
3925
3926 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3927 do {
3928 long pending = READ_DATA_PENDING_COUNT(fptr);
3929 if (pending > 0) {
3930 const char *p = READ_DATA_PENDING_PTR(fptr);
3931 const char *e;
3932 long last;
3933
3934 if (limit > 0 && pending > limit) pending = limit;
3935 e = search_delim(p, pending, delim, enc);
3936 if (e) pending = e - p;
3937 if (!NIL_P(str)) {
3938 last = RSTRING_LEN(str);
3939 rb_str_resize(str, last + pending);
3940 }
3941 else {
3942 last = 0;
3943 *strp = str = rb_str_buf_new(pending);
3944 rb_str_set_len(str, pending);
3945 }
3946 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3947 limit -= pending;
3948 *lp = limit;
3949 if (e) return delim;
3950 if (limit == 0)
3951 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3952 }
3953 READ_CHECK(fptr);
3954 } while (io_fillbuf(fptr) >= 0);
3955 *lp = limit;
3956 return EOF;
3957}
3958
3959static inline int
3960swallow(rb_io_t *fptr, int term)
3961{
3962 if (NEED_READCONV(fptr)) {
3963 rb_encoding *enc = io_read_encoding(fptr);
3964 int needconv = rb_enc_mbminlen(enc) != 1;
3965 SET_BINARY_MODE(fptr);
3966 make_readconv(fptr, 0);
3967 do {
3968 size_t cnt;
3969 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3970 const char *p = READ_CHAR_PENDING_PTR(fptr);
3971 int i;
3972 if (!needconv) {
3973 if (*p != term) return TRUE;
3974 i = (int)cnt;
3975 while (--i && *++p == term);
3976 }
3977 else {
3978 const char *e = p + cnt;
3979 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3980 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3981 i = (int)(e - p);
3982 }
3983 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3984 }
3985 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3986 return FALSE;
3987 }
3988
3989 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3990 do {
3991 size_t cnt;
3992 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3993 char buf[1024];
3994 const char *p = READ_DATA_PENDING_PTR(fptr);
3995 int i;
3996 if (cnt > sizeof buf) cnt = sizeof buf;
3997 if (*p != term) return TRUE;
3998 i = (int)cnt;
3999 while (--i && *++p == term);
4000 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4001 rb_sys_fail_path(fptr->pathv);
4002 }
4003 READ_CHECK(fptr);
4004 } while (io_fillbuf(fptr) == 0);
4005 return FALSE;
4006}
4007
4008static VALUE
4009rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4010{
4011 VALUE str = Qnil;
4012 int len = 0;
4013 long pos = 0;
4014 int cr = 0;
4015
4016 do {
4017 int pending = READ_DATA_PENDING_COUNT(fptr);
4018
4019 if (pending > 0) {
4020 const char *p = READ_DATA_PENDING_PTR(fptr);
4021 const char *e;
4022 int chomplen = 0;
4023
4024 e = memchr(p, '\n', pending);
4025 if (e) {
4026 pending = (int)(e - p + 1);
4027 if (chomp) {
4028 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4029 }
4030 }
4031 if (NIL_P(str)) {
4032 str = rb_str_new(p, pending - chomplen);
4033 fptr->rbuf.off += pending;
4034 fptr->rbuf.len -= pending;
4035 }
4036 else {
4037 rb_str_resize(str, len + pending - chomplen);
4038 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4039 fptr->rbuf.off += chomplen;
4040 fptr->rbuf.len -= chomplen;
4041 if (pending == 1 && chomplen == 1 && len > 0) {
4042 if (RSTRING_PTR(str)[len-1] == '\r') {
4043 rb_str_resize(str, --len);
4044 break;
4045 }
4046 }
4047 }
4048 len += pending - chomplen;
4049 if (cr != ENC_CODERANGE_BROKEN)
4050 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4051 if (e) break;
4052 }
4053 READ_CHECK(fptr);
4054 } while (io_fillbuf(fptr) >= 0);
4055 if (NIL_P(str)) return Qnil;
4056
4057 str = io_enc_str(str, fptr);
4058 ENC_CODERANGE_SET(str, cr);
4059 fptr->lineno++;
4060
4061 return str;
4062}
4063
4065 VALUE io;
4066 VALUE rs;
4067 long limit;
4068 unsigned int chomp: 1;
4069};
4070
4071static void
4072extract_getline_opts(VALUE opts, struct getline_arg *args)
4073{
4074 int chomp = FALSE;
4075 if (!NIL_P(opts)) {
4076 static ID kwds[1];
4077 VALUE vchomp;
4078 if (!kwds[0]) {
4079 kwds[0] = rb_intern_const("chomp");
4080 }
4081 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4082 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4083 }
4084 args->chomp = chomp;
4085}
4086
4087static void
4088extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4089{
4090 VALUE rs = rb_rs, lim = Qnil;
4091
4092 if (argc == 1) {
4093 VALUE tmp = Qnil;
4094
4095 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4096 rs = tmp;
4097 }
4098 else {
4099 lim = argv[0];
4100 }
4101 }
4102 else if (2 <= argc) {
4103 rs = argv[0], lim = argv[1];
4104 if (!NIL_P(rs))
4105 StringValue(rs);
4106 }
4107 args->rs = rs;
4108 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4109}
4110
4111static void
4112check_getline_args(VALUE *rsp, long *limit, VALUE io)
4113{
4114 rb_io_t *fptr;
4115 VALUE rs = *rsp;
4116
4117 if (!NIL_P(rs)) {
4118 rb_encoding *enc_rs, *enc_io;
4119
4120 GetOpenFile(io, fptr);
4121 enc_rs = rb_enc_get(rs);
4122 enc_io = io_read_encoding(fptr);
4123 if (enc_io != enc_rs &&
4124 (!is_ascii_string(rs) ||
4125 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4126 if (rs == rb_default_rs) {
4127 rs = rb_enc_str_new(0, 0, enc_io);
4128 rb_str_buf_cat_ascii(rs, "\n");
4129 *rsp = rs;
4130 }
4131 else {
4132 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4133 rb_enc_name(enc_io),
4134 rb_enc_name(enc_rs));
4135 }
4136 }
4137 }
4138}
4139
4140static void
4141prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4142{
4143 VALUE opts;
4144 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4145 extract_getline_args(argc, argv, args);
4146 extract_getline_opts(opts, args);
4147 check_getline_args(&args->rs, &args->limit, io);
4148}
4149
4150static VALUE
4151rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4152{
4153 VALUE str = Qnil;
4154 int nolimit = 0;
4155 rb_encoding *enc;
4156
4158 if (NIL_P(rs) && limit < 0) {
4159 str = read_all(fptr, 0, Qnil);
4160 if (RSTRING_LEN(str) == 0) return Qnil;
4161 }
4162 else if (limit == 0) {
4163 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4164 }
4165 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4166 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4167 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4168 return rb_io_getline_fast(fptr, enc, chomp);
4169 }
4170 else {
4171 int c, newline = -1;
4172 const char *rsptr = 0;
4173 long rslen = 0;
4174 int rspara = 0;
4175 int extra_limit = 16;
4176 int chomp_cr = chomp;
4177
4178 SET_BINARY_MODE(fptr);
4179 enc = io_read_encoding(fptr);
4180
4181 if (!NIL_P(rs)) {
4182 rslen = RSTRING_LEN(rs);
4183 if (rslen == 0) {
4184 rsptr = "\n\n";
4185 rslen = 2;
4186 rspara = 1;
4187 swallow(fptr, '\n');
4188 rs = 0;
4189 if (!rb_enc_asciicompat(enc)) {
4190 rs = rb_usascii_str_new(rsptr, rslen);
4191 rs = rb_str_conv_enc(rs, 0, enc);
4192 OBJ_FREEZE(rs);
4193 rsptr = RSTRING_PTR(rs);
4194 rslen = RSTRING_LEN(rs);
4195 }
4196 newline = '\n';
4197 }
4198 else if (rb_enc_mbminlen(enc) == 1) {
4199 rsptr = RSTRING_PTR(rs);
4200 newline = (unsigned char)rsptr[rslen - 1];
4201 }
4202 else {
4203 rs = rb_str_conv_enc(rs, 0, enc);
4204 rsptr = RSTRING_PTR(rs);
4205 const char *e = rsptr + rslen;
4206 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4207 int n;
4208 newline = rb_enc_codepoint_len(last, e, &n, enc);
4209 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4210 }
4211 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4212 }
4213
4214 /* MS - Optimization */
4215 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4216 const char *s, *p, *pp, *e;
4217
4218 if (c == newline) {
4219 if (RSTRING_LEN(str) < rslen) continue;
4220 s = RSTRING_PTR(str);
4221 e = RSTRING_END(str);
4222 p = e - rslen;
4223 if (!at_char_boundary(s, p, e, enc)) continue;
4224 if (!rspara) rscheck(rsptr, rslen, rs);
4225 if (memcmp(p, rsptr, rslen) == 0) {
4226 if (chomp) {
4227 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4228 rb_str_set_len(str, p - s);
4229 }
4230 break;
4231 }
4232 }
4233 if (limit == 0) {
4234 s = RSTRING_PTR(str);
4235 p = RSTRING_END(str);
4236 pp = rb_enc_prev_char(s, p, p, enc);
4237 if (extra_limit && pp &&
4238 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4239 /* relax the limit while incomplete character.
4240 * extra_limit limits the relax length */
4241 limit = 1;
4242 extra_limit--;
4243 }
4244 else {
4245 nolimit = 1;
4246 break;
4247 }
4248 }
4249 }
4250
4251 if (rspara && c != EOF)
4252 swallow(fptr, '\n');
4253 if (!NIL_P(str))
4254 str = io_enc_str(str, fptr);
4255 }
4256
4257 if (!NIL_P(str) && !nolimit) {
4258 fptr->lineno++;
4259 }
4260
4261 return str;
4262}
4263
4264static VALUE
4265rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4266{
4267 rb_io_t *fptr;
4268 int old_lineno, new_lineno;
4269 VALUE str;
4270
4271 GetOpenFile(io, fptr);
4272 old_lineno = fptr->lineno;
4273 str = rb_io_getline_0(rs, limit, chomp, fptr);
4274 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4275 if (io == ARGF.current_file) {
4276 ARGF.lineno += new_lineno - old_lineno;
4277 ARGF.last_lineno = ARGF.lineno;
4278 }
4279 else {
4280 ARGF.last_lineno = new_lineno;
4281 }
4282 }
4283
4284 return str;
4285}
4286
4287static VALUE
4288rb_io_getline(int argc, VALUE *argv, VALUE io)
4289{
4290 struct getline_arg args;
4291
4292 prepare_getline_args(argc, argv, &args, io);
4293 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4294}
4295
4296VALUE
4298{
4299 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4300}
4301
4302VALUE
4303rb_io_gets_internal(VALUE io)
4304{
4305 rb_io_t *fptr;
4306 GetOpenFile(io, fptr);
4307 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4308}
4309
4310/*
4311 * call-seq:
4312 * gets(sep = $/, chomp: false) -> string or nil
4313 * gets(limit, chomp: false) -> string or nil
4314 * gets(sep, limit, chomp: false) -> string or nil
4315 *
4316 * Reads and returns a line from the stream;
4317 * assigns the return value to <tt>$_</tt>.
4318 * See {Line IO}[rdoc-ref:IO@Line+IO].
4319 *
4320 * With no arguments given, returns the next line
4321 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4322 *
4323 * f = File.open('t.txt')
4324 * f.gets # => "First line\n"
4325 * $_ # => "First line\n"
4326 * f.gets # => "\n"
4327 * f.gets # => "Fourth line\n"
4328 * f.gets # => "Fifth line\n"
4329 * f.gets # => nil
4330 * f.close
4331 *
4332 * With only string argument +sep+ given,
4333 * returns the next line as determined by line separator +sep+,
4334 * or +nil+ if none;
4335 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4336 *
4337 * f = File.new('t.txt')
4338 * f.gets('l') # => "First l"
4339 * f.gets('li') # => "ine\nSecond li"
4340 * f.gets('lin') # => "ne\n\nFourth lin"
4341 * f.gets # => "e\n"
4342 * f.close
4343 *
4344 * The two special values for +sep+ are honored:
4345 *
4346 * f = File.new('t.txt')
4347 * # Get all.
4348 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4349 * f.rewind
4350 * # Get paragraph (up to two line separators).
4351 * f.gets('') # => "First line\nSecond line\n\n"
4352 * f.close
4353 *
4354 * With only integer argument +limit+ given,
4355 * limits the number of bytes in the line;
4356 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4357 *
4358 * # No more than one line.
4359 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4360 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4361 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4362 *
4363 * With arguments +sep+ and +limit+ given,
4364 * combines the two behaviors
4365 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4366 *
4367 * Optional keyword argument +chomp+ specifies whether line separators
4368 * are to be omitted:
4369 *
4370 * f = File.open('t.txt')
4371 * # Chomp the lines.
4372 * f.gets(chomp: true) # => "First line"
4373 * f.gets(chomp: true) # => "Second line"
4374 * f.gets(chomp: true) # => ""
4375 * f.gets(chomp: true) # => "Fourth line"
4376 * f.gets(chomp: true) # => "Fifth line"
4377 * f.gets(chomp: true) # => nil
4378 * f.close
4379 *
4380 */
4381
4382static VALUE
4383rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4384{
4385 VALUE str;
4386
4387 str = rb_io_getline(argc, argv, io);
4388 rb_lastline_set(str);
4389
4390 return str;
4391}
4392
4393/*
4394 * call-seq:
4395 * lineno -> integer
4396 *
4397 * Returns the current line number for the stream;
4398 * see {Line Number}[rdoc-ref:IO@Line+Number].
4399 *
4400 */
4401
4402static VALUE
4403rb_io_lineno(VALUE io)
4404{
4405 rb_io_t *fptr;
4406
4407 GetOpenFile(io, fptr);
4409 return INT2NUM(fptr->lineno);
4410}
4411
4412/*
4413 * call-seq:
4414 * lineno = integer -> integer
4415 *
4416 * Sets and returns the line number for the stream;
4417 * see {Line Number}[rdoc-ref:IO@Line+Number].
4418 *
4419 */
4420
4421static VALUE
4422rb_io_set_lineno(VALUE io, VALUE lineno)
4423{
4424 rb_io_t *fptr;
4425
4426 GetOpenFile(io, fptr);
4428 fptr->lineno = NUM2INT(lineno);
4429 return lineno;
4430}
4431
4432/* :nodoc: */
4433static VALUE
4434io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4435{
4436 long limit = -1;
4437 if (NIL_P(lim)) {
4438 VALUE tmp = Qnil;
4439 // If sep is specified, but it's not a string and not nil, then assume
4440 // it's the limit (it should be an integer)
4441 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4442 // If the user has specified a non-nil / non-string value
4443 // for the separator, we assume it's the limit and set the
4444 // separator to default: rb_rs.
4445 lim = sep;
4446 limit = NUM2LONG(lim);
4447 sep = rb_rs;
4448 }
4449 else {
4450 sep = tmp;
4451 }
4452 }
4453 else {
4454 if (!NIL_P(sep)) StringValue(sep);
4455 limit = NUM2LONG(lim);
4456 }
4457
4458 check_getline_args(&sep, &limit, io);
4459
4460 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4461 rb_lastline_set_up(line, 1);
4462
4463 if (NIL_P(line)) {
4464 rb_eof_error();
4465 }
4466 return line;
4467}
4468
4469static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4470
4471/*
4472 * call-seq:
4473 * readlines(sep = $/, chomp: false) -> array
4474 * readlines(limit, chomp: false) -> array
4475 * readlines(sep, limit, chomp: false) -> array
4476 *
4477 * Reads and returns all remaining line from the stream;
4478 * does not modify <tt>$_</tt>.
4479 * See {Line IO}[rdoc-ref:IO@Line+IO].
4480 *
4481 * With no arguments given, returns lines
4482 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4483 *
4484 * f = File.new('t.txt')
4485 * f.readlines
4486 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4487 * f.readlines # => []
4488 * f.close
4489 *
4490 * With only string argument +sep+ given,
4491 * returns lines as determined by line separator +sep+,
4492 * or +nil+ if none;
4493 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4494 *
4495 * f = File.new('t.txt')
4496 * f.readlines('li')
4497 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4498 * f.close
4499 *
4500 * The two special values for +sep+ are honored:
4501 *
4502 * f = File.new('t.txt')
4503 * # Get all into one string.
4504 * f.readlines(nil)
4505 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4506 * # Get paragraphs (up to two line separators).
4507 * f.rewind
4508 * f.readlines('')
4509 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4510 * f.close
4511 *
4512 * With only integer argument +limit+ given,
4513 * limits the number of bytes in each line;
4514 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4515 *
4516 * f = File.new('t.txt')
4517 * f.readlines(8)
4518 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4519 * f.close
4520 *
4521 * With arguments +sep+ and +limit+ given,
4522 * combines the two behaviors
4523 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4524 *
4525 * Optional keyword argument +chomp+ specifies whether line separators
4526 * are to be omitted:
4527 *
4528 * f = File.new('t.txt')
4529 * f.readlines(chomp: true)
4530 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4531 * f.close
4532 *
4533 */
4534
4535static VALUE
4536rb_io_readlines(int argc, VALUE *argv, VALUE io)
4537{
4538 struct getline_arg args;
4539
4540 prepare_getline_args(argc, argv, &args, io);
4541 return io_readlines(&args, io);
4542}
4543
4544static VALUE
4545io_readlines(const struct getline_arg *arg, VALUE io)
4546{
4547 VALUE line, ary;
4548
4549 if (arg->limit == 0)
4550 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4551 ary = rb_ary_new();
4552 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4553 rb_ary_push(ary, line);
4554 }
4555 return ary;
4556}
4557
4558/*
4559 * call-seq:
4560 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4561 * each_line(limit, chomp: false) {|line| ... } -> self
4562 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4563 * each_line -> enumerator
4564 *
4565 * Calls the block with each remaining line read from the stream;
4566 * returns +self+.
4567 * Does nothing if already at end-of-stream;
4568 * See {Line IO}[rdoc-ref:IO@Line+IO].
4569 *
4570 * With no arguments given, reads lines
4571 * as determined by line separator <tt>$/</tt>:
4572 *
4573 * f = File.new('t.txt')
4574 * f.each_line {|line| p line }
4575 * f.each_line {|line| fail 'Cannot happen' }
4576 * f.close
4577 *
4578 * Output:
4579 *
4580 * "First line\n"
4581 * "Second line\n"
4582 * "\n"
4583 * "Fourth line\n"
4584 * "Fifth line\n"
4585 *
4586 * With only string argument +sep+ given,
4587 * reads lines as determined by line separator +sep+;
4588 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4589 *
4590 * f = File.new('t.txt')
4591 * f.each_line('li') {|line| p line }
4592 * f.close
4593 *
4594 * Output:
4595 *
4596 * "First li"
4597 * "ne\nSecond li"
4598 * "ne\n\nFourth li"
4599 * "ne\nFifth li"
4600 * "ne\n"
4601 *
4602 * The two special values for +sep+ are honored:
4603 *
4604 * f = File.new('t.txt')
4605 * # Get all into one string.
4606 * f.each_line(nil) {|line| p line }
4607 * f.close
4608 *
4609 * Output:
4610 *
4611 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4612 *
4613 * f.rewind
4614 * # Get paragraphs (up to two line separators).
4615 * f.each_line('') {|line| p line }
4616 *
4617 * Output:
4618 *
4619 * "First line\nSecond line\n\n"
4620 * "Fourth line\nFifth line\n"
4621 *
4622 * With only integer argument +limit+ given,
4623 * limits the number of bytes in each line;
4624 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4625 *
4626 * f = File.new('t.txt')
4627 * f.each_line(8) {|line| p line }
4628 * f.close
4629 *
4630 * Output:
4631 *
4632 * "First li"
4633 * "ne\n"
4634 * "Second l"
4635 * "ine\n"
4636 * "\n"
4637 * "Fourth l"
4638 * "ine\n"
4639 * "Fifth li"
4640 * "ne\n"
4641 *
4642 * With arguments +sep+ and +limit+ given,
4643 * combines the two behaviors
4644 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4645 *
4646 * Optional keyword argument +chomp+ specifies whether line separators
4647 * are to be omitted:
4648 *
4649 * f = File.new('t.txt')
4650 * f.each_line(chomp: true) {|line| p line }
4651 * f.close
4652 *
4653 * Output:
4654 *
4655 * "First line"
4656 * "Second line"
4657 * ""
4658 * "Fourth line"
4659 * "Fifth line"
4660 *
4661 * Returns an Enumerator if no block is given.
4662 */
4663
4664static VALUE
4665rb_io_each_line(int argc, VALUE *argv, VALUE io)
4666{
4667 VALUE str;
4668 struct getline_arg args;
4669
4670 RETURN_ENUMERATOR(io, argc, argv);
4671 prepare_getline_args(argc, argv, &args, io);
4672 if (args.limit == 0)
4673 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4674 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4675 rb_yield(str);
4676 }
4677 return io;
4678}
4679
4680/*
4681 * call-seq:
4682 * each_byte {|byte| ... } -> self
4683 * each_byte -> enumerator
4684 *
4685 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4686 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4687 *
4688 * f = File.new('t.rus')
4689 * a = []
4690 * f.each_byte {|b| a << b }
4691 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4692 * f.close
4693 *
4694 * Returns an Enumerator if no block is given.
4695 *
4696 * Related: IO#each_char, IO#each_codepoint.
4697 *
4698 */
4699
4700static VALUE
4701rb_io_each_byte(VALUE io)
4702{
4703 rb_io_t *fptr;
4704
4705 RETURN_ENUMERATOR(io, 0, 0);
4706 GetOpenFile(io, fptr);
4707
4708 do {
4709 while (fptr->rbuf.len > 0) {
4710 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4711 fptr->rbuf.len--;
4712 rb_yield(INT2FIX(*p & 0xff));
4714 errno = 0;
4715 }
4716 READ_CHECK(fptr);
4717 } while (io_fillbuf(fptr) >= 0);
4718 return io;
4719}
4720
4721static VALUE
4722io_getc(rb_io_t *fptr, rb_encoding *enc)
4723{
4724 int r, n, cr = 0;
4725 VALUE str;
4726
4727 if (NEED_READCONV(fptr)) {
4728 rb_encoding *read_enc = io_read_encoding(fptr);
4729
4730 str = Qnil;
4731 SET_BINARY_MODE(fptr);
4732 make_readconv(fptr, 0);
4733
4734 while (1) {
4735 if (fptr->cbuf.len) {
4736 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4737 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4738 read_enc);
4739 if (!MBCLEN_NEEDMORE_P(r))
4740 break;
4741 if (fptr->cbuf.len == fptr->cbuf.capa) {
4742 rb_raise(rb_eIOError, "too long character");
4743 }
4744 }
4745
4746 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4747 if (fptr->cbuf.len == 0) {
4748 clear_readconv(fptr);
4749 return Qnil;
4750 }
4751 /* return an unit of an incomplete character just before EOF */
4752 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4753 fptr->cbuf.off += 1;
4754 fptr->cbuf.len -= 1;
4755 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4757 return str;
4758 }
4759 }
4760 if (MBCLEN_INVALID_P(r)) {
4761 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4762 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4763 read_enc);
4764 io_shift_cbuf(fptr, r, &str);
4766 }
4767 else {
4768 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4770 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4771 ISASCII(RSTRING_PTR(str)[0])) {
4772 cr = ENC_CODERANGE_7BIT;
4773 }
4774 }
4775 str = io_enc_str(str, fptr);
4776 ENC_CODERANGE_SET(str, cr);
4777 return str;
4778 }
4779
4780 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4781 if (io_fillbuf(fptr) < 0) {
4782 return Qnil;
4783 }
4784 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4785 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4786 fptr->rbuf.off += 1;
4787 fptr->rbuf.len -= 1;
4788 cr = ENC_CODERANGE_7BIT;
4789 }
4790 else {
4791 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4792 if (MBCLEN_CHARFOUND_P(r) &&
4793 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4794 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4795 fptr->rbuf.off += n;
4796 fptr->rbuf.len -= n;
4798 }
4799 else if (MBCLEN_NEEDMORE_P(r)) {
4800 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4801 fptr->rbuf.len = 0;
4802 getc_needmore:
4803 if (io_fillbuf(fptr) != -1) {
4804 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4805 fptr->rbuf.off++;
4806 fptr->rbuf.len--;
4807 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4808 if (MBCLEN_NEEDMORE_P(r)) {
4809 goto getc_needmore;
4810 }
4811 else if (MBCLEN_CHARFOUND_P(r)) {
4813 }
4814 }
4815 }
4816 else {
4817 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4818 fptr->rbuf.off++;
4819 fptr->rbuf.len--;
4820 }
4821 }
4822 if (!cr) cr = ENC_CODERANGE_BROKEN;
4823 str = io_enc_str(str, fptr);
4824 ENC_CODERANGE_SET(str, cr);
4825 return str;
4826}
4827
4828/*
4829 * call-seq:
4830 * each_char {|c| ... } -> self
4831 * each_char -> enumerator
4832 *
4833 * Calls the given block with each character in the stream; returns +self+.
4834 * See {Character IO}[rdoc-ref:IO@Character+IO].
4835 *
4836 * f = File.new('t.rus')
4837 * a = []
4838 * f.each_char {|c| a << c.ord }
4839 * a # => [1090, 1077, 1089, 1090]
4840 * f.close
4841 *
4842 * Returns an Enumerator if no block is given.
4843 *
4844 * Related: IO#each_byte, IO#each_codepoint.
4845 *
4846 */
4847
4848static VALUE
4849rb_io_each_char(VALUE io)
4850{
4851 rb_io_t *fptr;
4852 rb_encoding *enc;
4853 VALUE c;
4854
4855 RETURN_ENUMERATOR(io, 0, 0);
4856 GetOpenFile(io, fptr);
4858
4859 enc = io_input_encoding(fptr);
4860 READ_CHECK(fptr);
4861 while (!NIL_P(c = io_getc(fptr, enc))) {
4862 rb_yield(c);
4863 }
4864 return io;
4865}
4866
4867/*
4868 * call-seq:
4869 * each_codepoint {|c| ... } -> self
4870 * each_codepoint -> enumerator
4871 *
4872 * Calls the given block with each codepoint in the stream; returns +self+:
4873 *
4874 * f = File.new('t.rus')
4875 * a = []
4876 * f.each_codepoint {|c| a << c }
4877 * a # => [1090, 1077, 1089, 1090]
4878 * f.close
4879 *
4880 * Returns an Enumerator if no block is given.
4881 *
4882 * Related: IO#each_byte, IO#each_char.
4883 *
4884 */
4885
4886static VALUE
4887rb_io_each_codepoint(VALUE io)
4888{
4889 rb_io_t *fptr;
4890 rb_encoding *enc;
4891 unsigned int c;
4892 int r, n;
4893
4894 RETURN_ENUMERATOR(io, 0, 0);
4895 GetOpenFile(io, fptr);
4897
4898 READ_CHECK(fptr);
4899 if (NEED_READCONV(fptr)) {
4900 SET_BINARY_MODE(fptr);
4901 r = 1; /* no invalid char yet */
4902 for (;;) {
4903 make_readconv(fptr, 0);
4904 for (;;) {
4905 if (fptr->cbuf.len) {
4906 if (fptr->encs.enc)
4907 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4908 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4909 fptr->encs.enc);
4910 else
4911 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4912 if (!MBCLEN_NEEDMORE_P(r))
4913 break;
4914 if (fptr->cbuf.len == fptr->cbuf.capa) {
4915 rb_raise(rb_eIOError, "too long character");
4916 }
4917 }
4918 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4919 clear_readconv(fptr);
4920 if (!MBCLEN_CHARFOUND_P(r)) {
4921 enc = fptr->encs.enc;
4922 goto invalid;
4923 }
4924 return io;
4925 }
4926 }
4927 if (MBCLEN_INVALID_P(r)) {
4928 enc = fptr->encs.enc;
4929 goto invalid;
4930 }
4931 n = MBCLEN_CHARFOUND_LEN(r);
4932 if (fptr->encs.enc) {
4933 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4934 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4935 fptr->encs.enc);
4936 }
4937 else {
4938 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4939 }
4940 fptr->cbuf.off += n;
4941 fptr->cbuf.len -= n;
4942 rb_yield(UINT2NUM(c));
4944 }
4945 }
4946 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4947 enc = io_input_encoding(fptr);
4948 while (io_fillbuf(fptr) >= 0) {
4949 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4950 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4951 if (MBCLEN_CHARFOUND_P(r) &&
4952 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4953 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4954 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4955 fptr->rbuf.off += n;
4956 fptr->rbuf.len -= n;
4957 rb_yield(UINT2NUM(c));
4958 }
4959 else if (MBCLEN_INVALID_P(r)) {
4960 goto invalid;
4961 }
4962 else if (MBCLEN_NEEDMORE_P(r)) {
4963 char cbuf[8], *p = cbuf;
4964 int more = MBCLEN_NEEDMORE_LEN(r);
4965 if (more > numberof(cbuf)) goto invalid;
4966 more += n = fptr->rbuf.len;
4967 if (more > numberof(cbuf)) goto invalid;
4968 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4969 (p += n, (more -= n) > 0)) {
4970 if (io_fillbuf(fptr) < 0) goto invalid;
4971 if ((n = fptr->rbuf.len) > more) n = more;
4972 }
4973 r = rb_enc_precise_mbclen(cbuf, p, enc);
4974 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4975 c = rb_enc_codepoint(cbuf, p, enc);
4976 rb_yield(UINT2NUM(c));
4977 }
4978 else {
4979 continue;
4980 }
4982 }
4983 return io;
4984
4985 invalid:
4986 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4988}
4989
4990/*
4991 * call-seq:
4992 * getc -> character or nil
4993 *
4994 * Reads and returns the next 1-character string from the stream;
4995 * returns +nil+ if already at end-of-stream.
4996 * See {Character IO}[rdoc-ref:IO@Character+IO].
4997 *
4998 * f = File.open('t.txt')
4999 * f.getc # => "F"
5000 * f.close
5001 * f = File.open('t.rus')
5002 * f.getc.ord # => 1090
5003 * f.close
5004 *
5005 * Related: IO#readchar (may raise EOFError).
5006 *
5007 */
5008
5009static VALUE
5010rb_io_getc(VALUE io)
5011{
5012 rb_io_t *fptr;
5013 rb_encoding *enc;
5014
5015 GetOpenFile(io, fptr);
5017
5018 enc = io_input_encoding(fptr);
5019 READ_CHECK(fptr);
5020 return io_getc(fptr, enc);
5021}
5022
5023/*
5024 * call-seq:
5025 * readchar -> string
5026 *
5027 * Reads and returns the next 1-character string from the stream;
5028 * raises EOFError if already at end-of-stream.
5029 * See {Character IO}[rdoc-ref:IO@Character+IO].
5030 *
5031 * f = File.open('t.txt')
5032 * f.readchar # => "F"
5033 * f.close
5034 * f = File.open('t.rus')
5035 * f.readchar.ord # => 1090
5036 * f.close
5037 *
5038 * Related: IO#getc (will not raise EOFError).
5039 *
5040 */
5041
5042static VALUE
5043rb_io_readchar(VALUE io)
5044{
5045 VALUE c = rb_io_getc(io);
5046
5047 if (NIL_P(c)) {
5048 rb_eof_error();
5049 }
5050 return c;
5051}
5052
5053/*
5054 * call-seq:
5055 * getbyte -> integer or nil
5056 *
5057 * Reads and returns the next byte (in range 0..255) from the stream;
5058 * returns +nil+ if already at end-of-stream.
5059 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5060 *
5061 * f = File.open('t.txt')
5062 * f.getbyte # => 70
5063 * f.close
5064 * f = File.open('t.rus')
5065 * f.getbyte # => 209
5066 * f.close
5067 *
5068 * Related: IO#readbyte (may raise EOFError).
5069 */
5070
5071VALUE
5073{
5074 rb_io_t *fptr;
5075 int c;
5076
5077 GetOpenFile(io, fptr);
5079 READ_CHECK(fptr);
5080 VALUE r_stdout = rb_ractor_stdout();
5081 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5082 rb_io_t *ofp;
5083 GetOpenFile(r_stdout, ofp);
5084 if (ofp->mode & FMODE_TTY) {
5085 rb_io_flush(r_stdout);
5086 }
5087 }
5088 if (io_fillbuf(fptr) < 0) {
5089 return Qnil;
5090 }
5091 fptr->rbuf.off++;
5092 fptr->rbuf.len--;
5093 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5094 return INT2FIX(c & 0xff);
5095}
5096
5097/*
5098 * call-seq:
5099 * readbyte -> integer
5100 *
5101 * Reads and returns the next byte (in range 0..255) from the stream;
5102 * raises EOFError if already at end-of-stream.
5103 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5104 *
5105 * f = File.open('t.txt')
5106 * f.readbyte # => 70
5107 * f.close
5108 * f = File.open('t.rus')
5109 * f.readbyte # => 209
5110 * f.close
5111 *
5112 * Related: IO#getbyte (will not raise EOFError).
5113 *
5114 */
5115
5116static VALUE
5117rb_io_readbyte(VALUE io)
5118{
5119 VALUE c = rb_io_getbyte(io);
5120
5121 if (NIL_P(c)) {
5122 rb_eof_error();
5123 }
5124 return c;
5125}
5126
5127/*
5128 * call-seq:
5129 * ungetbyte(integer) -> nil
5130 * ungetbyte(string) -> nil
5131 *
5132 * Pushes back ("unshifts") the given data onto the stream's buffer,
5133 * placing the data so that it is next to be read; returns +nil+.
5134 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5135 *
5136 * Note that:
5137 *
5138 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5139 * - Calling #rewind on the stream discards the pushed-back data.
5140 *
5141 * When argument +integer+ is given, uses only its low-order byte:
5142 *
5143 * File.write('t.tmp', '012')
5144 * f = File.open('t.tmp')
5145 * f.ungetbyte(0x41) # => nil
5146 * f.read # => "A012"
5147 * f.rewind
5148 * f.ungetbyte(0x4243) # => nil
5149 * f.read # => "C012"
5150 * f.close
5151 *
5152 * When argument +string+ is given, uses all bytes:
5153 *
5154 * File.write('t.tmp', '012')
5155 * f = File.open('t.tmp')
5156 * f.ungetbyte('A') # => nil
5157 * f.read # => "A012"
5158 * f.rewind
5159 * f.ungetbyte('BCDE') # => nil
5160 * f.read # => "BCDE012"
5161 * f.close
5162 *
5163 */
5164
5165VALUE
5167{
5168 rb_io_t *fptr;
5169
5170 GetOpenFile(io, fptr);
5172 switch (TYPE(b)) {
5173 case T_NIL:
5174 return Qnil;
5175 case T_FIXNUM:
5176 case T_BIGNUM: ;
5177 VALUE v = rb_int_modulo(b, INT2FIX(256));
5178 unsigned char c = NUM2INT(v) & 0xFF;
5179 b = rb_str_new((const char *)&c, 1);
5180 break;
5181 default:
5182 StringValue(b);
5183 }
5184 io_ungetbyte(b, fptr);
5185 return Qnil;
5186}
5187
5188/*
5189 * call-seq:
5190 * ungetc(integer) -> nil
5191 * ungetc(string) -> nil
5192 *
5193 * Pushes back ("unshifts") the given data onto the stream's buffer,
5194 * placing the data so that it is next to be read; returns +nil+.
5195 * See {Character IO}[rdoc-ref:IO@Character+IO].
5196 *
5197 * Note that:
5198 *
5199 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5200 * - Calling #rewind on the stream discards the pushed-back data.
5201 *
5202 * When argument +integer+ is given, interprets the integer as a character:
5203 *
5204 * File.write('t.tmp', '012')
5205 * f = File.open('t.tmp')
5206 * f.ungetc(0x41) # => nil
5207 * f.read # => "A012"
5208 * f.rewind
5209 * f.ungetc(0x0442) # => nil
5210 * f.getc.ord # => 1090
5211 * f.close
5212 *
5213 * When argument +string+ is given, uses all characters:
5214 *
5215 * File.write('t.tmp', '012')
5216 * f = File.open('t.tmp')
5217 * f.ungetc('A') # => nil
5218 * f.read # => "A012"
5219 * f.rewind
5220 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5221 * f.getc.ord # => 1090
5222 * f.getc.ord # => 1077
5223 * f.getc.ord # => 1089
5224 * f.getc.ord # => 1090
5225 * f.close
5226 *
5227 */
5228
5229VALUE
5231{
5232 rb_io_t *fptr;
5233 long len;
5234
5235 GetOpenFile(io, fptr);
5237 if (FIXNUM_P(c)) {
5238 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5239 }
5240 else if (RB_BIGNUM_TYPE_P(c)) {
5241 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5242 }
5243 else {
5244 StringValue(c);
5245 }
5246 if (NEED_READCONV(fptr)) {
5247 SET_BINARY_MODE(fptr);
5248 len = RSTRING_LEN(c);
5249#if SIZEOF_LONG > SIZEOF_INT
5250 if (len > INT_MAX)
5251 rb_raise(rb_eIOError, "ungetc failed");
5252#endif
5253 make_readconv(fptr, (int)len);
5254 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5255 rb_raise(rb_eIOError, "ungetc failed");
5256 if (fptr->cbuf.off < len) {
5257 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5258 fptr->cbuf.ptr+fptr->cbuf.off,
5259 char, fptr->cbuf.len);
5260 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5261 }
5262 fptr->cbuf.off -= (int)len;
5263 fptr->cbuf.len += (int)len;
5264 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5265 }
5266 else {
5267 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5268 io_ungetbyte(c, fptr);
5269 }
5270 return Qnil;
5271}
5272
5273/*
5274 * call-seq:
5275 * isatty -> true or false
5276 *
5277 * Returns +true+ if the stream is associated with a terminal device (tty),
5278 * +false+ otherwise:
5279 *
5280 * f = File.new('t.txt').isatty #=> false
5281 * f.close
5282 * f = File.new('/dev/tty').isatty #=> true
5283 * f.close
5284 *
5285 */
5286
5287static VALUE
5288rb_io_isatty(VALUE io)
5289{
5290 rb_io_t *fptr;
5291
5292 GetOpenFile(io, fptr);
5293 return RBOOL(isatty(fptr->fd) != 0);
5294}
5295
5296#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5297/*
5298 * call-seq:
5299 * close_on_exec? -> true or false
5300 *
5301 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5302 *
5303 * f = File.open('t.txt')
5304 * f.close_on_exec? # => true
5305 * f.close_on_exec = false
5306 * f.close_on_exec? # => false
5307 * f.close
5308 *
5309 */
5310
5311static VALUE
5312rb_io_close_on_exec_p(VALUE io)
5313{
5314 rb_io_t *fptr;
5315 VALUE write_io;
5316 int fd, ret;
5317
5318 write_io = GetWriteIO(io);
5319 if (io != write_io) {
5320 GetOpenFile(write_io, fptr);
5321 if (fptr && 0 <= (fd = fptr->fd)) {
5322 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5323 if (!(ret & FD_CLOEXEC)) return Qfalse;
5324 }
5325 }
5326
5327 GetOpenFile(io, fptr);
5328 if (fptr && 0 <= (fd = fptr->fd)) {
5329 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5330 if (!(ret & FD_CLOEXEC)) return Qfalse;
5331 }
5332 return Qtrue;
5333}
5334#else
5335#define rb_io_close_on_exec_p rb_f_notimplement
5336#endif
5337
5338#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5339/*
5340 * call-seq:
5341 * self.close_on_exec = bool -> true or false
5342 *
5343 * Sets a close-on-exec flag.
5344 *
5345 * f = File.open(File::NULL)
5346 * f.close_on_exec = true
5347 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5348 * f.closed? #=> false
5349 *
5350 * Ruby sets close-on-exec flags of all file descriptors by default
5351 * since Ruby 2.0.0.
5352 * So you don't need to set by yourself.
5353 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5354 * if another thread use fork() and exec() (via system() method for example).
5355 * If you really needs file descriptor inheritance to child process,
5356 * use spawn()'s argument such as fd=>fd.
5357 */
5358
5359static VALUE
5360rb_io_set_close_on_exec(VALUE io, VALUE arg)
5361{
5362 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5363 rb_io_t *fptr;
5364 VALUE write_io;
5365 int fd, ret;
5366
5367 write_io = GetWriteIO(io);
5368 if (io != write_io) {
5369 GetOpenFile(write_io, fptr);
5370 if (fptr && 0 <= (fd = fptr->fd)) {
5371 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5372 if ((ret & FD_CLOEXEC) != flag) {
5373 ret = (ret & ~FD_CLOEXEC) | flag;
5374 ret = fcntl(fd, F_SETFD, ret);
5375 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5376 }
5377 }
5378
5379 }
5380
5381 GetOpenFile(io, fptr);
5382 if (fptr && 0 <= (fd = fptr->fd)) {
5383 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5384 if ((ret & FD_CLOEXEC) != flag) {
5385 ret = (ret & ~FD_CLOEXEC) | flag;
5386 ret = fcntl(fd, F_SETFD, ret);
5387 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5388 }
5389 }
5390 return Qnil;
5391}
5392#else
5393#define rb_io_set_close_on_exec rb_f_notimplement
5394#endif
5395
5396#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5397#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5398
5399static VALUE
5400finish_writeconv(rb_io_t *fptr, int noalloc)
5401{
5402 unsigned char *ds, *dp, *de;
5404
5405 if (!fptr->wbuf.ptr) {
5406 unsigned char buf[1024];
5407
5409 while (res == econv_destination_buffer_full) {
5410 ds = dp = buf;
5411 de = buf + sizeof(buf);
5412 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5413 while (dp-ds) {
5414 size_t remaining = dp-ds;
5415 long result = rb_io_write_memory(fptr, ds, remaining);
5416
5417 if (result > 0) {
5418 ds += result;
5419 if ((size_t)result == remaining) break;
5420 }
5421 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5422 if (fptr->fd < 0)
5423 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5424 }
5425 else {
5426 return noalloc ? Qtrue : INT2NUM(errno);
5427 }
5428 }
5429 if (res == econv_invalid_byte_sequence ||
5430 res == econv_incomplete_input ||
5432 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5433 }
5434 }
5435
5436 return Qnil;
5437 }
5438
5440 while (res == econv_destination_buffer_full) {
5441 if (fptr->wbuf.len == fptr->wbuf.capa) {
5442 if (io_fflush(fptr) < 0) {
5443 return noalloc ? Qtrue : INT2NUM(errno);
5444 }
5445 }
5446
5447 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5448 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5449 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5450 fptr->wbuf.len += (int)(dp - ds);
5451 if (res == econv_invalid_byte_sequence ||
5452 res == econv_incomplete_input ||
5454 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5455 }
5456 }
5457 return Qnil;
5458}
5459
5461 rb_io_t *fptr;
5462 int noalloc;
5463};
5464
5465static VALUE
5466finish_writeconv_sync(VALUE arg)
5467{
5468 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5469 return finish_writeconv(p->fptr, p->noalloc);
5470}
5471
5472static void*
5473nogvl_close(void *ptr)
5474{
5475 int *fd = ptr;
5476
5477 return (void*)(intptr_t)close(*fd);
5478}
5479
5480static int
5481maygvl_close(int fd, int keepgvl)
5482{
5483 if (keepgvl)
5484 return close(fd);
5485
5486 /*
5487 * close() may block for certain file types (NFS, SO_LINGER sockets,
5488 * inotify), so let other threads run.
5489 */
5490 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5491}
5492
5493static void*
5494nogvl_fclose(void *ptr)
5495{
5496 FILE *file = ptr;
5497
5498 return (void*)(intptr_t)fclose(file);
5499}
5500
5501static int
5502maygvl_fclose(FILE *file, int keepgvl)
5503{
5504 if (keepgvl)
5505 return fclose(file);
5506
5507 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5508}
5509
5510static void free_io_buffer(rb_io_buffer_t *buf);
5511
5512static void
5513fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5514 struct rb_io_close_wait_list *busy)
5515{
5516 VALUE error = Qnil;
5517 int fd = fptr->fd;
5518 FILE *stdio_file = fptr->stdio_file;
5519 int mode = fptr->mode;
5520
5521 if (fptr->writeconv) {
5522 if (!NIL_P(fptr->write_lock) && !noraise) {
5523 struct finish_writeconv_arg arg;
5524 arg.fptr = fptr;
5525 arg.noalloc = noraise;
5526 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5527 }
5528 else {
5529 error = finish_writeconv(fptr, noraise);
5530 }
5531 }
5532 if (fptr->wbuf.len) {
5533 if (noraise) {
5534 io_flush_buffer_sync(fptr);
5535 }
5536 else {
5537 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5538 error = INT2NUM(errno);
5539 }
5540 }
5541 }
5542
5543 int done = 0;
5544
5545 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5546 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5547 done = 1;
5548 }
5549
5550 fptr->fd = -1;
5551 fptr->stdio_file = 0;
5553
5554 // Ensure waiting_fd users do not hit EBADF.
5555 if (busy) {
5556 // Wait for them to exit before we call close().
5557 rb_notify_fd_close_wait(busy);
5558 }
5559
5560 // Disable for now.
5561 // if (!done && fd >= 0) {
5562 // VALUE scheduler = rb_fiber_scheduler_current();
5563 // if (scheduler != Qnil) {
5564 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5565 // if (!UNDEF_P(result)) done = 1;
5566 // }
5567 // }
5568
5569 if (!done && stdio_file) {
5570 // stdio_file is deallocated anyway even if fclose failed.
5571 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5572 if (!noraise) {
5573 error = INT2NUM(errno);
5574 }
5575 }
5576
5577 done = 1;
5578 }
5579
5580 if (!done && fd >= 0) {
5581 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5582 // We assumes it is closed.
5583
5584 keepgvl |= !(mode & FMODE_WRITABLE);
5585 keepgvl |= noraise;
5586 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5587 if (!noraise) {
5588 error = INT2NUM(errno);
5589 }
5590 }
5591
5592 done = 1;
5593 }
5594
5595 if (!NIL_P(error) && !noraise) {
5596 if (RB_INTEGER_TYPE_P(error))
5597 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5598 else
5599 rb_exc_raise(error);
5600 }
5601}
5602
5603static void
5604fptr_finalize(rb_io_t *fptr, int noraise)
5605{
5606 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5607 free_io_buffer(&fptr->rbuf);
5608 free_io_buffer(&fptr->wbuf);
5609 clear_codeconv(fptr);
5610}
5611
5612static void
5613rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5614{
5615 if (fptr->finalize) {
5616 (*fptr->finalize)(fptr, noraise);
5617 }
5618 else {
5619 fptr_finalize(fptr, noraise);
5620 }
5621}
5622
5623static void
5624free_io_buffer(rb_io_buffer_t *buf)
5625{
5626 if (buf->ptr) {
5627 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5628 buf->ptr = NULL;
5629 }
5630}
5631
5632static void
5633clear_readconv(rb_io_t *fptr)
5634{
5635 if (fptr->readconv) {
5636 rb_econv_close(fptr->readconv);
5637 fptr->readconv = NULL;
5638 }
5639 free_io_buffer(&fptr->cbuf);
5640}
5641
5642static void
5643clear_writeconv(rb_io_t *fptr)
5644{
5645 if (fptr->writeconv) {
5647 fptr->writeconv = NULL;
5648 }
5649 fptr->writeconv_initialized = 0;
5650}
5651
5652static void
5653clear_codeconv(rb_io_t *fptr)
5654{
5655 clear_readconv(fptr);
5656 clear_writeconv(fptr);
5657}
5658
5659static void
5660rb_io_fptr_cleanup_all(rb_io_t *fptr)
5661{
5662 fptr->pathv = Qnil;
5663 if (0 <= fptr->fd)
5664 rb_io_fptr_cleanup(fptr, TRUE);
5665 fptr->write_lock = Qnil;
5666 free_io_buffer(&fptr->rbuf);
5667 free_io_buffer(&fptr->wbuf);
5668 clear_codeconv(fptr);
5669}
5670
5671void
5672rb_io_fptr_finalize_internal(void *ptr)
5673{
5674 if (!ptr) return;
5675 rb_io_fptr_cleanup_all(ptr);
5676 free(ptr);
5677}
5678
5679#undef rb_io_fptr_finalize
5680int
5681rb_io_fptr_finalize(rb_io_t *fptr)
5682{
5683 if (!fptr) {
5684 return 0;
5685 }
5686 else {
5687 rb_io_fptr_finalize_internal(fptr);
5688 return 1;
5689 }
5690}
5691#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5692
5693size_t
5694rb_io_memsize(const rb_io_t *fptr)
5695{
5696 size_t size = sizeof(rb_io_t);
5697 size += fptr->rbuf.capa;
5698 size += fptr->wbuf.capa;
5699 size += fptr->cbuf.capa;
5700 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5701 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5702 return size;
5703}
5704
5705#ifdef _WIN32
5706/* keep GVL while closing to prevent crash on Windows */
5707# define KEEPGVL TRUE
5708#else
5709# define KEEPGVL FALSE
5710#endif
5711
5712static rb_io_t *
5713io_close_fptr(VALUE io)
5714{
5715 rb_io_t *fptr;
5716 VALUE write_io;
5717 rb_io_t *write_fptr;
5718 struct rb_io_close_wait_list busy;
5719
5720 write_io = GetWriteIO(io);
5721 if (io != write_io) {
5722 write_fptr = RFILE(write_io)->fptr;
5723 if (write_fptr && 0 <= write_fptr->fd) {
5724 rb_io_fptr_cleanup(write_fptr, TRUE);
5725 }
5726 }
5727
5728 fptr = RFILE(io)->fptr;
5729 if (!fptr) return 0;
5730 if (fptr->fd < 0) return 0;
5731
5732 if (rb_notify_fd_close(fptr->fd, &busy)) {
5733 /* calls close(fptr->fd): */
5734 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5735 }
5736 rb_io_fptr_cleanup(fptr, FALSE);
5737 return fptr;
5738}
5739
5740static void
5741fptr_waitpid(rb_io_t *fptr, int nohang)
5742{
5743 int status;
5744 if (fptr->pid) {
5745 rb_last_status_clear();
5746 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5747 fptr->pid = 0;
5748 }
5749}
5750
5751VALUE
5753{
5754 rb_io_t *fptr = io_close_fptr(io);
5755 if (fptr) fptr_waitpid(fptr, 0);
5756 return Qnil;
5757}
5758
5759/*
5760 * call-seq:
5761 * close -> nil
5762 *
5763 * Closes the stream for both reading and writing
5764 * if open for either or both; returns +nil+.
5765 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5766 *
5767 * If the stream is open for writing, flushes any buffered writes
5768 * to the operating system before closing.
5769 *
5770 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5771 * (child exit status).
5772 *
5773 * It is not an error to close an IO object that has already been closed.
5774 * It just returns nil.
5775 *
5776 * Example:
5777 *
5778 * IO.popen('ruby', 'r+') do |pipe|
5779 * puts pipe.closed?
5780 * pipe.close
5781 * puts $?
5782 * puts pipe.closed?
5783 * end
5784 *
5785 * Output:
5786 *
5787 * false
5788 * pid 13760 exit 0
5789 * true
5790 *
5791 * Related: IO#close_read, IO#close_write, IO#closed?.
5792 */
5793
5794static VALUE
5795rb_io_close_m(VALUE io)
5796{
5797 rb_io_t *fptr = rb_io_get_fptr(io);
5798 if (fptr->fd < 0) {
5799 return Qnil;
5800 }
5801 rb_io_close(io);
5802 return Qnil;
5803}
5804
5805static VALUE
5806io_call_close(VALUE io)
5807{
5808 rb_check_funcall(io, rb_intern("close"), 0, 0);
5809 return io;
5810}
5811
5812static VALUE
5813ignore_closed_stream(VALUE io, VALUE exc)
5814{
5815 enum {mesg_len = sizeof(closed_stream)-1};
5816 VALUE mesg = rb_attr_get(exc, idMesg);
5817 if (!RB_TYPE_P(mesg, T_STRING) ||
5818 RSTRING_LEN(mesg) != mesg_len ||
5819 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5820 rb_exc_raise(exc);
5821 }
5822 return io;
5823}
5824
5825static VALUE
5826io_close(VALUE io)
5827{
5828 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5829 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5830 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5831 rb_eIOError, (VALUE)0);
5832 return io;
5833}
5834
5835/*
5836 * call-seq:
5837 * closed? -> true or false
5838 *
5839 * Returns +true+ if the stream is closed for both reading and writing,
5840 * +false+ otherwise.
5841 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5842 *
5843 * IO.popen('ruby', 'r+') do |pipe|
5844 * puts pipe.closed?
5845 * pipe.close_read
5846 * puts pipe.closed?
5847 * pipe.close_write
5848 * puts pipe.closed?
5849 * end
5850 *
5851 * Output:
5852 *
5853 * false
5854 * false
5855 * true
5856 *
5857 * Related: IO#close_read, IO#close_write, IO#close.
5858 */
5859VALUE
5861{
5862 rb_io_t *fptr;
5863 VALUE write_io;
5864 rb_io_t *write_fptr;
5865
5866 write_io = GetWriteIO(io);
5867 if (io != write_io) {
5868 write_fptr = RFILE(write_io)->fptr;
5869 if (write_fptr && 0 <= write_fptr->fd) {
5870 return Qfalse;
5871 }
5872 }
5873
5874 fptr = rb_io_get_fptr(io);
5875 return RBOOL(0 > fptr->fd);
5876}
5877
5878/*
5879 * call-seq:
5880 * close_read -> nil
5881 *
5882 * Closes the stream for reading if open for reading;
5883 * returns +nil+.
5884 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5885 *
5886 * If the stream was opened by IO.popen and is also closed for writing,
5887 * sets global variable <tt>$?</tt> (child exit status).
5888 *
5889 * Example:
5890 *
5891 * IO.popen('ruby', 'r+') do |pipe|
5892 * puts pipe.closed?
5893 * pipe.close_write
5894 * puts pipe.closed?
5895 * pipe.close_read
5896 * puts $?
5897 * puts pipe.closed?
5898 * end
5899 *
5900 * Output:
5901 *
5902 * false
5903 * false
5904 * pid 14748 exit 0
5905 * true
5906 *
5907 * Related: IO#close, IO#close_write, IO#closed?.
5908 */
5909
5910static VALUE
5911rb_io_close_read(VALUE io)
5912{
5913 rb_io_t *fptr;
5914 VALUE write_io;
5915
5916 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5917 if (fptr->fd < 0) return Qnil;
5918 if (is_socket(fptr->fd, fptr->pathv)) {
5919#ifndef SHUT_RD
5920# define SHUT_RD 0
5921#endif
5922 if (shutdown(fptr->fd, SHUT_RD) < 0)
5923 rb_sys_fail_path(fptr->pathv);
5924 fptr->mode &= ~FMODE_READABLE;
5925 if (!(fptr->mode & FMODE_WRITABLE))
5926 return rb_io_close(io);
5927 return Qnil;
5928 }
5929
5930 write_io = GetWriteIO(io);
5931 if (io != write_io) {
5932 rb_io_t *wfptr;
5933 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5934 wfptr->pid = fptr->pid;
5935 fptr->pid = 0;
5936 RFILE(io)->fptr = wfptr;
5937 /* bind to write_io temporarily to get rid of memory/fd leak */
5938 fptr->tied_io_for_writing = 0;
5939 RFILE(write_io)->fptr = fptr;
5940 rb_io_fptr_cleanup(fptr, FALSE);
5941 /* should not finalize fptr because another thread may be reading it */
5942 return Qnil;
5943 }
5944
5945 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5946 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5947 }
5948 return rb_io_close(io);
5949}
5950
5951/*
5952 * call-seq:
5953 * close_write -> nil
5954 *
5955 * Closes the stream for writing if open for writing;
5956 * returns +nil+.
5957 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5958 *
5959 * Flushes any buffered writes to the operating system before closing.
5960 *
5961 * If the stream was opened by IO.popen and is also closed for reading,
5962 * sets global variable <tt>$?</tt> (child exit status).
5963 *
5964 * IO.popen('ruby', 'r+') do |pipe|
5965 * puts pipe.closed?
5966 * pipe.close_read
5967 * puts pipe.closed?
5968 * pipe.close_write
5969 * puts $?
5970 * puts pipe.closed?
5971 * end
5972 *
5973 * Output:
5974 *
5975 * false
5976 * false
5977 * pid 15044 exit 0
5978 * true
5979 *
5980 * Related: IO#close, IO#close_read, IO#closed?.
5981 */
5982
5983static VALUE
5984rb_io_close_write(VALUE io)
5985{
5986 rb_io_t *fptr;
5987 VALUE write_io;
5988
5989 write_io = GetWriteIO(io);
5990 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5991 if (fptr->fd < 0) return Qnil;
5992 if (is_socket(fptr->fd, fptr->pathv)) {
5993#ifndef SHUT_WR
5994# define SHUT_WR 1
5995#endif
5996 if (shutdown(fptr->fd, SHUT_WR) < 0)
5997 rb_sys_fail_path(fptr->pathv);
5998 fptr->mode &= ~FMODE_WRITABLE;
5999 if (!(fptr->mode & FMODE_READABLE))
6000 return rb_io_close(write_io);
6001 return Qnil;
6002 }
6003
6004 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6005 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6006 }
6007
6008 if (io != write_io) {
6009 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6010 fptr->tied_io_for_writing = 0;
6011 }
6012 rb_io_close(write_io);
6013 return Qnil;
6014}
6015
6016/*
6017 * call-seq:
6018 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6019 *
6020 * Behaves like IO#seek, except that it:
6021 *
6022 * - Uses low-level system functions.
6023 * - Returns the new position.
6024 *
6025 */
6026
6027static VALUE
6028rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6029{
6030 VALUE offset, ptrname;
6031 int whence = SEEK_SET;
6032 rb_io_t *fptr;
6033 rb_off_t pos;
6034
6035 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6036 whence = interpret_seek_whence(ptrname);
6037 }
6038 pos = NUM2OFFT(offset);
6039 GetOpenFile(io, fptr);
6040 if ((fptr->mode & FMODE_READABLE) &&
6041 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6042 rb_raise(rb_eIOError, "sysseek for buffered IO");
6043 }
6044 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6045 rb_warn("sysseek for buffered IO");
6046 }
6047 errno = 0;
6048 pos = lseek(fptr->fd, pos, whence);
6049 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6050
6051 return OFFT2NUM(pos);
6052}
6053
6054/*
6055 * call-seq:
6056 * syswrite(object) -> integer
6057 *
6058 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6059 * returns the number bytes written.
6060 * If +object+ is not a string is converted via method to_s:
6061 *
6062 * f = File.new('t.tmp', 'w')
6063 * f.syswrite('foo') # => 3
6064 * f.syswrite(30) # => 2
6065 * f.syswrite(:foo) # => 3
6066 * f.close
6067 *
6068 * This methods should not be used with other stream-writer methods.
6069 *
6070 */
6071
6072static VALUE
6073rb_io_syswrite(VALUE io, VALUE str)
6074{
6075 VALUE tmp;
6076 rb_io_t *fptr;
6077 long n, len;
6078 const char *ptr;
6079
6080 if (!RB_TYPE_P(str, T_STRING))
6081 str = rb_obj_as_string(str);
6082
6083 io = GetWriteIO(io);
6084 GetOpenFile(io, fptr);
6086
6087 if (fptr->wbuf.len) {
6088 rb_warn("syswrite for buffered IO");
6089 }
6090
6091 tmp = rb_str_tmp_frozen_acquire(str);
6092 RSTRING_GETMEM(tmp, ptr, len);
6093 n = rb_io_write_memory(fptr, ptr, len);
6094 if (n < 0) rb_sys_fail_path(fptr->pathv);
6095 rb_str_tmp_frozen_release(str, tmp);
6096
6097 return LONG2FIX(n);
6098}
6099
6100/*
6101 * call-seq:
6102 * sysread(maxlen) -> string
6103 * sysread(maxlen, out_string) -> string
6104 *
6105 * Behaves like IO#readpartial, except that it uses low-level system functions.
6106 *
6107 * This method should not be used with other stream-reader methods.
6108 *
6109 */
6110
6111static VALUE
6112rb_io_sysread(int argc, VALUE *argv, VALUE io)
6113{
6114 VALUE len, str;
6115 rb_io_t *fptr;
6116 long n, ilen;
6117 struct io_internal_read_struct iis;
6118 int shrinkable;
6119
6120 rb_scan_args(argc, argv, "11", &len, &str);
6121 ilen = NUM2LONG(len);
6122
6123 shrinkable = io_setstrbuf(&str, ilen);
6124 if (ilen == 0) return str;
6125
6126 GetOpenFile(io, fptr);
6128
6129 if (READ_DATA_BUFFERED(fptr)) {
6130 rb_raise(rb_eIOError, "sysread for buffered IO");
6131 }
6132
6133 rb_io_check_closed(fptr);
6134
6135 io_setstrbuf(&str, ilen);
6136 iis.th = rb_thread_current();
6137 iis.fptr = fptr;
6138 iis.nonblock = 0;
6139 iis.fd = fptr->fd;
6140 iis.buf = RSTRING_PTR(str);
6141 iis.capa = ilen;
6142 iis.timeout = NULL;
6143 n = io_read_memory_locktmp(str, &iis);
6144
6145 if (n < 0) {
6146 rb_sys_fail_path(fptr->pathv);
6147 }
6148
6149 io_set_read_length(str, n, shrinkable);
6150
6151 if (n == 0 && ilen > 0) {
6152 rb_eof_error();
6153 }
6154
6155 return str;
6156}
6157
6159 struct rb_io *io;
6160 int fd;
6161 void *buf;
6162 size_t count;
6163 rb_off_t offset;
6164};
6165
6166static VALUE
6167internal_pread_func(void *_arg)
6168{
6169 struct prdwr_internal_arg *arg = _arg;
6170
6171 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6172}
6173
6174static VALUE
6175pread_internal_call(VALUE _arg)
6176{
6177 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6178
6179 VALUE scheduler = rb_fiber_scheduler_current();
6180 if (scheduler != Qnil) {
6181 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6182
6183 if (!UNDEF_P(result)) {
6185 }
6186 }
6187
6188 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6189}
6190
6191/*
6192 * call-seq:
6193 * pread(maxlen, offset) -> string
6194 * pread(maxlen, offset, out_string) -> string
6195 *
6196 * Behaves like IO#readpartial, except that it:
6197 *
6198 * - Reads at the given +offset+ (in bytes).
6199 * - Disregards, and does not modify, the stream's position
6200 * (see {Position}[rdoc-ref:IO@Position]).
6201 * - Bypasses any user space buffering in the stream.
6202 *
6203 * Because this method does not disturb the stream's state
6204 * (its position, in particular), +pread+ allows multiple threads and processes
6205 * to use the same \IO object for reading at various offsets.
6206 *
6207 * f = File.open('t.txt')
6208 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6209 * f.pos # => 52
6210 * # Read 12 bytes at offset 0.
6211 * f.pread(12, 0) # => "First line\n"
6212 * # Read 9 bytes at offset 8.
6213 * f.pread(9, 8) # => "ne\nSecon"
6214 * f.close
6215 *
6216 * Not available on some platforms.
6217 *
6218 */
6219static VALUE
6220rb_io_pread(int argc, VALUE *argv, VALUE io)
6221{
6222 VALUE len, offset, str;
6223 rb_io_t *fptr;
6224 ssize_t n;
6225 struct prdwr_internal_arg arg;
6226 int shrinkable;
6227
6228 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6229 arg.count = NUM2SIZET(len);
6230 arg.offset = NUM2OFFT(offset);
6231
6232 shrinkable = io_setstrbuf(&str, (long)arg.count);
6233 if (arg.count == 0) return str;
6234 arg.buf = RSTRING_PTR(str);
6235
6236 GetOpenFile(io, fptr);
6238
6239 arg.io = fptr;
6240 arg.fd = fptr->fd;
6241 rb_io_check_closed(fptr);
6242
6243 rb_str_locktmp(str);
6244 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6245
6246 if (n < 0) {
6247 rb_sys_fail_path(fptr->pathv);
6248 }
6249 io_set_read_length(str, n, shrinkable);
6250 if (n == 0 && arg.count > 0) {
6251 rb_eof_error();
6252 }
6253
6254 return str;
6255}
6256
6257static VALUE
6258internal_pwrite_func(void *_arg)
6259{
6260 struct prdwr_internal_arg *arg = _arg;
6261
6262 VALUE scheduler = rb_fiber_scheduler_current();
6263 if (scheduler != Qnil) {
6264 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6265
6266 if (!UNDEF_P(result)) {
6268 }
6269 }
6270
6271
6272 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6273}
6274
6275/*
6276 * call-seq:
6277 * pwrite(object, offset) -> integer
6278 *
6279 * Behaves like IO#write, except that it:
6280 *
6281 * - Writes at the given +offset+ (in bytes).
6282 * - Disregards, and does not modify, the stream's position
6283 * (see {Position}[rdoc-ref:IO@Position]).
6284 * - Bypasses any user space buffering in the stream.
6285 *
6286 * Because this method does not disturb the stream's state
6287 * (its position, in particular), +pwrite+ allows multiple threads and processes
6288 * to use the same \IO object for writing at various offsets.
6289 *
6290 * f = File.open('t.tmp', 'w+')
6291 * # Write 6 bytes at offset 3.
6292 * f.pwrite('ABCDEF', 3) # => 6
6293 * f.rewind
6294 * f.read # => "\u0000\u0000\u0000ABCDEF"
6295 * f.close
6296 *
6297 * Not available on some platforms.
6298 *
6299 */
6300static VALUE
6301rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6302{
6303 rb_io_t *fptr;
6304 ssize_t n;
6305 struct prdwr_internal_arg arg;
6306 VALUE tmp;
6307
6308 if (!RB_TYPE_P(str, T_STRING))
6309 str = rb_obj_as_string(str);
6310
6311 arg.offset = NUM2OFFT(offset);
6312
6313 io = GetWriteIO(io);
6314 GetOpenFile(io, fptr);
6316
6317 arg.io = fptr;
6318 arg.fd = fptr->fd;
6319
6320 tmp = rb_str_tmp_frozen_acquire(str);
6321 arg.buf = RSTRING_PTR(tmp);
6322 arg.count = (size_t)RSTRING_LEN(tmp);
6323
6324 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
6325 if (n < 0) rb_sys_fail_path(fptr->pathv);
6326 rb_str_tmp_frozen_release(str, tmp);
6327
6328 return SSIZET2NUM(n);
6329}
6330
6331VALUE
6333{
6334 rb_io_t *fptr;
6335
6336 GetOpenFile(io, fptr);
6337 if (fptr->readconv)
6339 if (fptr->writeconv)
6341 fptr->mode |= FMODE_BINMODE;
6342 fptr->mode &= ~FMODE_TEXTMODE;
6343 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6344#ifdef O_BINARY
6345 if (!fptr->readconv) {
6346 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6347 }
6348 else {
6349 setmode(fptr->fd, O_BINARY);
6350 }
6351#endif
6352 return io;
6353}
6354
6355static void
6356io_ascii8bit_binmode(rb_io_t *fptr)
6357{
6358 if (fptr->readconv) {
6359 rb_econv_close(fptr->readconv);
6360 fptr->readconv = NULL;
6361 }
6362 if (fptr->writeconv) {
6364 fptr->writeconv = NULL;
6365 }
6366 fptr->mode |= FMODE_BINMODE;
6367 fptr->mode &= ~FMODE_TEXTMODE;
6368 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6369
6370 fptr->encs.enc = rb_ascii8bit_encoding();
6371 fptr->encs.enc2 = NULL;
6372 fptr->encs.ecflags = 0;
6373 fptr->encs.ecopts = Qnil;
6374 clear_codeconv(fptr);
6375}
6376
6377VALUE
6379{
6380 rb_io_t *fptr;
6381
6382 GetOpenFile(io, fptr);
6383 io_ascii8bit_binmode(fptr);
6384
6385 return io;
6386}
6387
6388/*
6389 * call-seq:
6390 * binmode -> self
6391 *
6392 * Sets the stream's data mode as binary
6393 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6394 *
6395 * A stream's data mode may not be changed from binary to text.
6396 *
6397 */
6398
6399static VALUE
6400rb_io_binmode_m(VALUE io)
6401{
6402 VALUE write_io;
6403
6405
6406 write_io = GetWriteIO(io);
6407 if (write_io != io)
6408 rb_io_ascii8bit_binmode(write_io);
6409 return io;
6410}
6411
6412/*
6413 * call-seq:
6414 * binmode? -> true or false
6415 *
6416 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6417 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6418 *
6419 */
6420static VALUE
6421rb_io_binmode_p(VALUE io)
6422{
6423 rb_io_t *fptr;
6424 GetOpenFile(io, fptr);
6425 return RBOOL(fptr->mode & FMODE_BINMODE);
6426}
6427
6428static const char*
6429rb_io_fmode_modestr(int fmode)
6430{
6431 if (fmode & FMODE_APPEND) {
6432 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6433 return MODE_BTMODE("a+", "ab+", "at+");
6434 }
6435 return MODE_BTMODE("a", "ab", "at");
6436 }
6437 switch (fmode & FMODE_READWRITE) {
6438 default:
6439 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6440 case FMODE_READABLE:
6441 return MODE_BTMODE("r", "rb", "rt");
6442 case FMODE_WRITABLE:
6443 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6444 case FMODE_READWRITE:
6445 if (fmode & FMODE_CREATE) {
6446 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6447 }
6448 return MODE_BTMODE("r+", "rb+", "rt+");
6449 }
6450}
6451
6452static const char bom_prefix[] = "bom|";
6453static const char utf_prefix[] = "utf-";
6454enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6455enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6456
6457static int
6458io_encname_bom_p(const char *name, long len)
6459{
6460 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6461}
6462
6463int
6464rb_io_modestr_fmode(const char *modestr)
6465{
6466 int fmode = 0;
6467 const char *m = modestr, *p = NULL;
6468
6469 switch (*m++) {
6470 case 'r':
6471 fmode |= FMODE_READABLE;
6472 break;
6473 case 'w':
6475 break;
6476 case 'a':
6478 break;
6479 default:
6480 goto error;
6481 }
6482
6483 while (*m) {
6484 switch (*m++) {
6485 case 'b':
6486 fmode |= FMODE_BINMODE;
6487 break;
6488 case 't':
6489 fmode |= FMODE_TEXTMODE;
6490 break;
6491 case '+':
6492 fmode |= FMODE_READWRITE;
6493 break;
6494 case 'x':
6495 if (modestr[0] != 'w')
6496 goto error;
6497 fmode |= FMODE_EXCL;
6498 break;
6499 default:
6500 goto error;
6501 case ':':
6502 p = strchr(m, ':');
6503 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6504 fmode |= FMODE_SETENC_BY_BOM;
6505 goto finished;
6506 }
6507 }
6508
6509 finished:
6510 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6511 goto error;
6512
6513 return fmode;
6514
6515 error:
6516 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6518}
6519
6520int
6521rb_io_oflags_fmode(int oflags)
6522{
6523 int fmode = 0;
6524
6525 switch (oflags & O_ACCMODE) {
6526 case O_RDONLY:
6527 fmode = FMODE_READABLE;
6528 break;
6529 case O_WRONLY:
6530 fmode = FMODE_WRITABLE;
6531 break;
6532 case O_RDWR:
6533 fmode = FMODE_READWRITE;
6534 break;
6535 }
6536
6537 if (oflags & O_APPEND) {
6538 fmode |= FMODE_APPEND;
6539 }
6540 if (oflags & O_TRUNC) {
6541 fmode |= FMODE_TRUNC;
6542 }
6543 if (oflags & O_CREAT) {
6544 fmode |= FMODE_CREATE;
6545 }
6546 if (oflags & O_EXCL) {
6547 fmode |= FMODE_EXCL;
6548 }
6549#ifdef O_BINARY
6550 if (oflags & O_BINARY) {
6551 fmode |= FMODE_BINMODE;
6552 }
6553#endif
6554
6555 return fmode;
6556}
6557
6558static int
6559rb_io_fmode_oflags(int fmode)
6560{
6561 int oflags = 0;
6562
6563 switch (fmode & FMODE_READWRITE) {
6564 case FMODE_READABLE:
6565 oflags |= O_RDONLY;
6566 break;
6567 case FMODE_WRITABLE:
6568 oflags |= O_WRONLY;
6569 break;
6570 case FMODE_READWRITE:
6571 oflags |= O_RDWR;
6572 break;
6573 }
6574
6575 if (fmode & FMODE_APPEND) {
6576 oflags |= O_APPEND;
6577 }
6578 if (fmode & FMODE_TRUNC) {
6579 oflags |= O_TRUNC;
6580 }
6581 if (fmode & FMODE_CREATE) {
6582 oflags |= O_CREAT;
6583 }
6584 if (fmode & FMODE_EXCL) {
6585 oflags |= O_EXCL;
6586 }
6587#ifdef O_BINARY
6588 if (fmode & FMODE_BINMODE) {
6589 oflags |= O_BINARY;
6590 }
6591#endif
6592
6593 return oflags;
6594}
6595
6596int
6597rb_io_modestr_oflags(const char *modestr)
6598{
6599 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6600}
6601
6602static const char*
6603rb_io_oflags_modestr(int oflags)
6604{
6605#ifdef O_BINARY
6606# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6607#else
6608# define MODE_BINARY(a,b) (a)
6609#endif
6610 int accmode;
6611 if (oflags & O_EXCL) {
6612 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6613 }
6614 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6615 if (oflags & O_APPEND) {
6616 if (accmode == O_WRONLY) {
6617 return MODE_BINARY("a", "ab");
6618 }
6619 if (accmode == O_RDWR) {
6620 return MODE_BINARY("a+", "ab+");
6621 }
6622 }
6623 switch (accmode) {
6624 default:
6625 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6626 case O_RDONLY:
6627 return MODE_BINARY("r", "rb");
6628 case O_WRONLY:
6629 return MODE_BINARY("w", "wb");
6630 case O_RDWR:
6631 if (oflags & O_TRUNC) {
6632 return MODE_BINARY("w+", "wb+");
6633 }
6634 return MODE_BINARY("r+", "rb+");
6635 }
6636}
6637
6638/*
6639 * Convert external/internal encodings to enc/enc2
6640 * NULL => use default encoding
6641 * Qnil => no encoding specified (internal only)
6642 */
6643static void
6644rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6645{
6646 int default_ext = 0;
6647
6648 if (ext == NULL) {
6649 ext = rb_default_external_encoding();
6650 default_ext = 1;
6651 }
6652 if (rb_is_ascii8bit_enc(ext)) {
6653 /* If external is ASCII-8BIT, no transcoding */
6654 intern = NULL;
6655 }
6656 else if (intern == NULL) {
6657 intern = rb_default_internal_encoding();
6658 }
6659 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6660 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6661 /* No internal encoding => use external + no transcoding */
6662 *enc = (default_ext && intern != ext) ? NULL : ext;
6663 *enc2 = NULL;
6664 }
6665 else {
6666 *enc = intern;
6667 *enc2 = ext;
6668 }
6669}
6670
6671static void
6672unsupported_encoding(const char *name, rb_encoding *enc)
6673{
6674 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6675}
6676
6677static void
6678parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6679 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6680{
6681 const char *p;
6682 char encname[ENCODING_MAXNAMELEN+1];
6683 int idx, idx2;
6684 int fmode = fmode_p ? *fmode_p : 0;
6685 rb_encoding *ext_enc, *int_enc;
6686 long len;
6687
6688 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6689
6690 p = strrchr(estr, ':');
6691 len = p ? (p++ - estr) : (long)strlen(estr);
6692 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6693 estr += bom_prefix_len;
6694 len -= bom_prefix_len;
6695 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6696 fmode |= FMODE_SETENC_BY_BOM;
6697 }
6698 else {
6699 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6700 fmode &= ~FMODE_SETENC_BY_BOM;
6701 }
6702 }
6703 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6704 idx = -1;
6705 }
6706 else {
6707 if (p) {
6708 memcpy(encname, estr, len);
6709 encname[len] = '\0';
6710 estr = encname;
6711 }
6712 idx = rb_enc_find_index(estr);
6713 }
6714 if (fmode_p) *fmode_p = fmode;
6715
6716 if (idx >= 0)
6717 ext_enc = rb_enc_from_index(idx);
6718 else {
6719 if (idx != -2)
6720 unsupported_encoding(estr, estr_enc);
6721 ext_enc = NULL;
6722 }
6723
6724 int_enc = NULL;
6725 if (p) {
6726 if (*p == '-' && *(p+1) == '\0') {
6727 /* Special case - "-" => no transcoding */
6728 int_enc = (rb_encoding *)Qnil;
6729 }
6730 else {
6731 idx2 = rb_enc_find_index(p);
6732 if (idx2 < 0)
6733 unsupported_encoding(p, estr_enc);
6734 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6735 int_enc = (rb_encoding *)Qnil;
6736 }
6737 else
6738 int_enc = rb_enc_from_index(idx2);
6739 }
6740 }
6741
6742 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6743}
6744
6745int
6746rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6747{
6748 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6749 int extracted = 0;
6750 rb_encoding *extencoding = NULL;
6751 rb_encoding *intencoding = NULL;
6752
6753 if (!NIL_P(opt)) {
6754 VALUE v;
6755 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6756 if (v != Qnil) encoding = v;
6757 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6758 if (v != Qnil) extenc = v;
6759 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6760 if (!UNDEF_P(v)) intenc = v;
6761 }
6762 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6763 if (!NIL_P(ruby_verbose)) {
6764 int idx = rb_to_encoding_index(encoding);
6765 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6766 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6767 encoding, UNDEF_P(extenc) ? "internal" : "external");
6768 }
6769 encoding = Qnil;
6770 }
6771 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6772 extencoding = rb_to_encoding(extenc);
6773 }
6774 if (!UNDEF_P(intenc)) {
6775 if (NIL_P(intenc)) {
6776 /* internal_encoding: nil => no transcoding */
6777 intencoding = (rb_encoding *)Qnil;
6778 }
6779 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6780 char *p = StringValueCStr(tmp);
6781
6782 if (*p == '-' && *(p+1) == '\0') {
6783 /* Special case - "-" => no transcoding */
6784 intencoding = (rb_encoding *)Qnil;
6785 }
6786 else {
6787 intencoding = rb_to_encoding(intenc);
6788 }
6789 }
6790 else {
6791 intencoding = rb_to_encoding(intenc);
6792 }
6793 if (extencoding == intencoding) {
6794 intencoding = (rb_encoding *)Qnil;
6795 }
6796 }
6797 if (!NIL_P(encoding)) {
6798 extracted = 1;
6799 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6800 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6801 enc_p, enc2_p, fmode_p);
6802 }
6803 else {
6804 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6805 }
6806 }
6807 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6808 extracted = 1;
6809 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6810 }
6811 return extracted;
6812}
6813
6814static void
6815validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6816{
6817 int fmode = *fmode_p;
6818
6819 if ((fmode & FMODE_READABLE) &&
6820 !enc2 &&
6821 !(fmode & FMODE_BINMODE) &&
6822 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6823 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6824
6825 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6826 rb_raise(rb_eArgError, "newline decorator with binary mode");
6827 }
6828 if (!(fmode & FMODE_BINMODE) &&
6829 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6830 fmode |= FMODE_TEXTMODE;
6831 *fmode_p = fmode;
6832 }
6833#if !DEFAULT_TEXTMODE
6834 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6835 fmode &= ~FMODE_TEXTMODE;
6836 *fmode_p = fmode;
6837 }
6838#endif
6839}
6840
6841static void
6842extract_binmode(VALUE opthash, int *fmode)
6843{
6844 if (!NIL_P(opthash)) {
6845 VALUE v;
6846 v = rb_hash_aref(opthash, sym_textmode);
6847 if (!NIL_P(v)) {
6848 if (*fmode & FMODE_TEXTMODE)
6849 rb_raise(rb_eArgError, "textmode specified twice");
6850 if (*fmode & FMODE_BINMODE)
6851 rb_raise(rb_eArgError, "both textmode and binmode specified");
6852 if (RTEST(v))
6853 *fmode |= FMODE_TEXTMODE;
6854 }
6855 v = rb_hash_aref(opthash, sym_binmode);
6856 if (!NIL_P(v)) {
6857 if (*fmode & FMODE_BINMODE)
6858 rb_raise(rb_eArgError, "binmode specified twice");
6859 if (*fmode & FMODE_TEXTMODE)
6860 rb_raise(rb_eArgError, "both textmode and binmode specified");
6861 if (RTEST(v))
6862 *fmode |= FMODE_BINMODE;
6863 }
6864
6865 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6866 rb_raise(rb_eArgError, "both textmode and binmode specified");
6867 }
6868}
6869
6870void
6871rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6872 int *oflags_p, int *fmode_p, struct rb_io_encoding *convconfig_p)
6873{
6874 VALUE vmode;
6875 int oflags, fmode;
6876 rb_encoding *enc, *enc2;
6877 int ecflags;
6878 VALUE ecopts;
6879 int has_enc = 0, has_vmode = 0;
6880 VALUE intmode;
6881
6882 vmode = *vmode_p;
6883
6884 /* Set to defaults */
6885 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6886
6887 vmode_handle:
6888 if (NIL_P(vmode)) {
6889 fmode = FMODE_READABLE;
6890 oflags = O_RDONLY;
6891 }
6892 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6893 vmode = intmode;
6894 oflags = NUM2INT(intmode);
6895 fmode = rb_io_oflags_fmode(oflags);
6896 }
6897 else {
6898 const char *p;
6899
6900 StringValue(vmode);
6901 p = StringValueCStr(vmode);
6902 fmode = rb_io_modestr_fmode(p);
6903 oflags = rb_io_fmode_oflags(fmode);
6904 p = strchr(p, ':');
6905 if (p) {
6906 has_enc = 1;
6907 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6908 }
6909 else {
6910 rb_encoding *e;
6911
6912 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6913 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6914 }
6915 }
6916
6917 if (NIL_P(opthash)) {
6918 ecflags = (fmode & FMODE_READABLE) ?
6921#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6922 ecflags |= (fmode & FMODE_WRITABLE) ?
6923 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6924 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6925#endif
6926 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6927 ecopts = Qnil;
6928 if (fmode & FMODE_BINMODE) {
6929#ifdef O_BINARY
6930 oflags |= O_BINARY;
6931#endif
6932 if (!has_enc)
6933 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6934 }
6935#if DEFAULT_TEXTMODE
6936 else if (NIL_P(vmode)) {
6937 fmode |= DEFAULT_TEXTMODE;
6938 }
6939#endif
6940 }
6941 else {
6942 VALUE v;
6943 if (!has_vmode) {
6944 v = rb_hash_aref(opthash, sym_mode);
6945 if (!NIL_P(v)) {
6946 if (!NIL_P(vmode)) {
6947 rb_raise(rb_eArgError, "mode specified twice");
6948 }
6949 has_vmode = 1;
6950 vmode = v;
6951 goto vmode_handle;
6952 }
6953 }
6954 v = rb_hash_aref(opthash, sym_flags);
6955 if (!NIL_P(v)) {
6956 v = rb_to_int(v);
6957 oflags |= NUM2INT(v);
6958 vmode = INT2NUM(oflags);
6959 fmode = rb_io_oflags_fmode(oflags);
6960 }
6961 extract_binmode(opthash, &fmode);
6962 if (fmode & FMODE_BINMODE) {
6963#ifdef O_BINARY
6964 oflags |= O_BINARY;
6965#endif
6966 if (!has_enc)
6967 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6968 }
6969#if DEFAULT_TEXTMODE
6970 else if (NIL_P(vmode)) {
6971 fmode |= DEFAULT_TEXTMODE;
6972 }
6973#endif
6974 v = rb_hash_aref(opthash, sym_perm);
6975 if (!NIL_P(v)) {
6976 if (vperm_p) {
6977 if (!NIL_P(*vperm_p)) {
6978 rb_raise(rb_eArgError, "perm specified twice");
6979 }
6980 *vperm_p = v;
6981 }
6982 else {
6983 /* perm no use, just ignore */
6984 }
6985 }
6986 ecflags = (fmode & FMODE_READABLE) ?
6989#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6990 ecflags |= (fmode & FMODE_WRITABLE) ?
6991 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6992 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6993#endif
6994
6995 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6996 if (has_enc) {
6997 rb_raise(rb_eArgError, "encoding specified twice");
6998 }
6999 }
7000 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7001 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7002 }
7003
7004 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7005
7006 *vmode_p = vmode;
7007
7008 *oflags_p = oflags;
7009 *fmode_p = fmode;
7010 convconfig_p->enc = enc;
7011 convconfig_p->enc2 = enc2;
7012 convconfig_p->ecflags = ecflags;
7013 convconfig_p->ecopts = ecopts;
7014}
7015
7017 VALUE fname;
7018 int oflags;
7019 mode_t perm;
7020};
7021
7022static void *
7023sysopen_func(void *ptr)
7024{
7025 const struct sysopen_struct *data = ptr;
7026 const char *fname = RSTRING_PTR(data->fname);
7027 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7028}
7029
7030static inline int
7031rb_sysopen_internal(struct sysopen_struct *data)
7032{
7033 int fd;
7034 do {
7035 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7036 } while (fd < 0 && errno == EINTR);
7037 if (0 <= fd)
7038 rb_update_max_fd(fd);
7039 return fd;
7040}
7041
7042static int
7043rb_sysopen(VALUE fname, int oflags, mode_t perm)
7044{
7045 int fd = -1;
7046 struct sysopen_struct data;
7047
7048 data.fname = rb_str_encode_ospath(fname);
7049 StringValueCStr(data.fname);
7050 data.oflags = oflags;
7051 data.perm = perm;
7052
7053 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7054 rb_syserr_fail_path(first_errno, fname);
7055 }
7056 return fd;
7057}
7058
7059static inline FILE *
7060fdopen_internal(int fd, const char *modestr)
7061{
7062 FILE *file;
7063
7064#if defined(__sun)
7065 errno = 0;
7066#endif
7067 file = fdopen(fd, modestr);
7068 if (!file) {
7069#ifdef _WIN32
7070 if (errno == 0) errno = EINVAL;
7071#elif defined(__sun)
7072 if (errno == 0) errno = EMFILE;
7073#endif
7074 }
7075 return file;
7076}
7077
7078FILE *
7079rb_fdopen(int fd, const char *modestr)
7080{
7081 FILE *file = 0;
7082
7083 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7084 rb_syserr_fail(first_errno, 0);
7085 }
7086
7087 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7088#ifdef USE_SETVBUF
7089 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7090 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7091#endif
7092 return file;
7093}
7094
7095static int
7096io_check_tty(rb_io_t *fptr)
7097{
7098 int t = isatty(fptr->fd);
7099 if (t)
7100 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7101 return t;
7102}
7103
7104static VALUE rb_io_internal_encoding(VALUE);
7105static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7106
7107static int
7108io_strip_bom(VALUE io)
7109{
7110 VALUE b1, b2, b3, b4;
7111 rb_io_t *fptr;
7112
7113 GetOpenFile(io, fptr);
7114 if (!(fptr->mode & FMODE_READABLE)) return 0;
7115 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7116 switch (b1) {
7117 case INT2FIX(0xEF):
7118 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7119 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7120 if (b3 == INT2FIX(0xBF)) {
7121 return rb_utf8_encindex();
7122 }
7123 rb_io_ungetbyte(io, b3);
7124 }
7125 rb_io_ungetbyte(io, b2);
7126 break;
7127
7128 case INT2FIX(0xFE):
7129 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7130 if (b2 == INT2FIX(0xFF)) {
7131 return ENCINDEX_UTF_16BE;
7132 }
7133 rb_io_ungetbyte(io, b2);
7134 break;
7135
7136 case INT2FIX(0xFF):
7137 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7138 if (b2 == INT2FIX(0xFE)) {
7139 b3 = rb_io_getbyte(io);
7140 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7141 if (b4 == INT2FIX(0)) {
7142 return ENCINDEX_UTF_32LE;
7143 }
7144 rb_io_ungetbyte(io, b4);
7145 }
7146 rb_io_ungetbyte(io, b3);
7147 return ENCINDEX_UTF_16LE;
7148 }
7149 rb_io_ungetbyte(io, b2);
7150 break;
7151
7152 case INT2FIX(0):
7153 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7154 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7155 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7156 if (b4 == INT2FIX(0xFF)) {
7157 return ENCINDEX_UTF_32BE;
7158 }
7159 rb_io_ungetbyte(io, b4);
7160 }
7161 rb_io_ungetbyte(io, b3);
7162 }
7163 rb_io_ungetbyte(io, b2);
7164 break;
7165 }
7166 rb_io_ungetbyte(io, b1);
7167 return 0;
7168}
7169
7170static rb_encoding *
7171io_set_encoding_by_bom(VALUE io)
7172{
7173 int idx = io_strip_bom(io);
7174 rb_io_t *fptr;
7175 rb_encoding *extenc = NULL;
7176
7177 GetOpenFile(io, fptr);
7178 if (idx) {
7179 extenc = rb_enc_from_index(idx);
7180 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7181 rb_io_internal_encoding(io), Qnil);
7182 }
7183 else {
7184 fptr->encs.enc2 = NULL;
7185 }
7186 return extenc;
7187}
7188
7189static VALUE
7190rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7191 const struct rb_io_encoding *convconfig, mode_t perm)
7192{
7193 VALUE pathv;
7194 rb_io_t *fptr;
7195 struct rb_io_encoding cc;
7196 if (!convconfig) {
7197 /* Set to default encodings */
7198 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7199 cc.ecflags = 0;
7200 cc.ecopts = Qnil;
7201 convconfig = &cc;
7202 }
7203 validate_enc_binmode(&fmode, convconfig->ecflags,
7204 convconfig->enc, convconfig->enc2);
7205
7206 MakeOpenFile(io, fptr);
7207 fptr->mode = fmode;
7208 fptr->encs = *convconfig;
7209 pathv = rb_str_new_frozen(filename);
7210#ifdef O_TMPFILE
7211 if (!(oflags & O_TMPFILE)) {
7212 fptr->pathv = pathv;
7213 }
7214#else
7215 fptr->pathv = pathv;
7216#endif
7217 fptr->fd = rb_sysopen(pathv, oflags, perm);
7218 io_check_tty(fptr);
7219 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7220
7221 return io;
7222}
7223
7224static VALUE
7225rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7226{
7227 int fmode = rb_io_modestr_fmode(modestr);
7228 const char *p = strchr(modestr, ':');
7229 struct rb_io_encoding convconfig;
7230
7231 if (p) {
7232 parse_mode_enc(p+1, rb_usascii_encoding(),
7233 &convconfig.enc, &convconfig.enc2, &fmode);
7234 }
7235 else {
7236 rb_encoding *e;
7237 /* Set to default encodings */
7238
7239 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7240 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7241 }
7242
7243 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7246#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7247 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7248 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7249 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7250#endif
7251 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7252 convconfig.ecopts = Qnil;
7253
7254 return rb_file_open_generic(io, filename,
7255 rb_io_fmode_oflags(fmode),
7256 fmode,
7257 &convconfig,
7258 0666);
7259}
7260
7261VALUE
7262rb_file_open_str(VALUE fname, const char *modestr)
7263{
7264 FilePathValue(fname);
7265 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7266}
7267
7268VALUE
7269rb_file_open(const char *fname, const char *modestr)
7270{
7271 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7272}
7273
7274#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7275static struct pipe_list {
7276 rb_io_t *fptr;
7277 struct pipe_list *next;
7278} *pipe_list;
7279
7280static void
7281pipe_add_fptr(rb_io_t *fptr)
7282{
7283 struct pipe_list *list;
7284
7285 list = ALLOC(struct pipe_list);
7286 list->fptr = fptr;
7287 list->next = pipe_list;
7288 pipe_list = list;
7289}
7290
7291static void
7292pipe_del_fptr(rb_io_t *fptr)
7293{
7294 struct pipe_list **prev = &pipe_list;
7295 struct pipe_list *tmp;
7296
7297 while ((tmp = *prev) != 0) {
7298 if (tmp->fptr == fptr) {
7299 *prev = tmp->next;
7300 free(tmp);
7301 return;
7302 }
7303 prev = &tmp->next;
7304 }
7305}
7306
7307#if defined (_WIN32) || defined(__CYGWIN__)
7308static void
7309pipe_atexit(void)
7310{
7311 struct pipe_list *list = pipe_list;
7312 struct pipe_list *tmp;
7313
7314 while (list) {
7315 tmp = list->next;
7316 rb_io_fptr_finalize(list->fptr);
7317 list = tmp;
7318 }
7319}
7320#endif
7321
7322static void
7323pipe_finalize(rb_io_t *fptr, int noraise)
7324{
7325#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7326 int status = 0;
7327 if (fptr->stdio_file) {
7328 status = pclose(fptr->stdio_file);
7329 }
7330 fptr->fd = -1;
7331 fptr->stdio_file = 0;
7332 rb_last_status_set(status, fptr->pid);
7333#else
7334 fptr_finalize(fptr, noraise);
7335#endif
7336 pipe_del_fptr(fptr);
7337}
7338#endif
7339
7340static void
7341fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7342{
7343#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7344 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7345
7346 if (old_finalize == orig->finalize) return;
7347#endif
7348
7349 fptr->finalize = orig->finalize;
7350
7351#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7352 if (old_finalize != pipe_finalize) {
7353 struct pipe_list *list;
7354 for (list = pipe_list; list; list = list->next) {
7355 if (list->fptr == fptr) break;
7356 }
7357 if (!list) pipe_add_fptr(fptr);
7358 }
7359 else {
7360 pipe_del_fptr(fptr);
7361 }
7362#endif
7363}
7364
7365void
7367{
7369 fptr->mode |= FMODE_SYNC;
7370}
7371
7372void
7373rb_io_unbuffered(rb_io_t *fptr)
7374{
7375 rb_io_synchronized(fptr);
7376}
7377
7378int
7379rb_pipe(int *pipes)
7380{
7381 int ret;
7382 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7383 if (ret == 0) {
7384 rb_update_max_fd(pipes[0]);
7385 rb_update_max_fd(pipes[1]);
7386 }
7387 return ret;
7388}
7389
7390#ifdef _WIN32
7391#define HAVE_SPAWNV 1
7392#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7393#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7394#endif
7395
7396#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7397struct popen_arg {
7398 VALUE execarg_obj;
7399 struct rb_execarg *eargp;
7400 int modef;
7401 int pair[2];
7402 int write_pair[2];
7403};
7404#endif
7405
7406#ifdef HAVE_WORKING_FORK
7407# ifndef __EMSCRIPTEN__
7408static void
7409popen_redirect(struct popen_arg *p)
7410{
7411 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7412 close(p->write_pair[1]);
7413 if (p->write_pair[0] != 0) {
7414 dup2(p->write_pair[0], 0);
7415 close(p->write_pair[0]);
7416 }
7417 close(p->pair[0]);
7418 if (p->pair[1] != 1) {
7419 dup2(p->pair[1], 1);
7420 close(p->pair[1]);
7421 }
7422 }
7423 else if (p->modef & FMODE_READABLE) {
7424 close(p->pair[0]);
7425 if (p->pair[1] != 1) {
7426 dup2(p->pair[1], 1);
7427 close(p->pair[1]);
7428 }
7429 }
7430 else {
7431 close(p->pair[1]);
7432 if (p->pair[0] != 0) {
7433 dup2(p->pair[0], 0);
7434 close(p->pair[0]);
7435 }
7436 }
7437}
7438# endif
7439
7440#if defined(__linux__)
7441/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7442 * Since /proc may not be available, linux_get_maxfd is just a hint.
7443 * This function, linux_get_maxfd, must be async-signal-safe.
7444 * I.e. opendir() is not usable.
7445 *
7446 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7447 * However they are easy to re-implement in async-signal-safe manner.
7448 * (Also note that there is missing/memcmp.c.)
7449 */
7450static int
7451linux_get_maxfd(void)
7452{
7453 int fd;
7454 char buf[4096], *p, *np, *e;
7455 ssize_t ss;
7456 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7457 if (fd < 0) return fd;
7458 ss = read(fd, buf, sizeof(buf));
7459 if (ss < 0) goto err;
7460 p = buf;
7461 e = buf + ss;
7462 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7463 (np = memchr(p, '\n', e-p)) != NULL) {
7464 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7465 int fdsize;
7466 p += sizeof("FDSize:")-1;
7467 *np = '\0';
7468 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7469 close(fd);
7470 return fdsize;
7471 }
7472 p = np+1;
7473 }
7474 /* fall through */
7475
7476 err:
7477 close(fd);
7478 return (int)ss;
7479}
7480#endif
7481
7482/* This function should be async-signal-safe. */
7483void
7484rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7485{
7486#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7487 int fd, ret;
7488 int max = (int)max_file_descriptor;
7489# ifdef F_MAXFD
7490 /* F_MAXFD is available since NetBSD 2.0. */
7491 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7492 if (ret != -1)
7493 maxhint = max = ret;
7494# elif defined(__linux__)
7495 ret = linux_get_maxfd();
7496 if (maxhint < ret)
7497 maxhint = ret;
7498 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7499# endif
7500 if (max < maxhint)
7501 max = maxhint;
7502 for (fd = lowfd; fd <= max; fd++) {
7503 if (!NIL_P(noclose_fds) &&
7504 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7505 continue;
7506 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7507 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7508 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7509 }
7510# define CONTIGUOUS_CLOSED_FDS 20
7511 if (ret != -1) {
7512 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7513 max = fd + CONTIGUOUS_CLOSED_FDS;
7514 }
7515 }
7516#endif
7517}
7518
7519# ifndef __EMSCRIPTEN__
7520static int
7521popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7522{
7523 struct popen_arg *p = (struct popen_arg*)pp;
7524
7525 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7526}
7527# endif
7528#endif
7529
7530#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7531static VALUE
7532rb_execarg_fixup_v(VALUE execarg_obj)
7533{
7534 rb_execarg_parent_start(execarg_obj);
7535 return Qnil;
7536}
7537#else
7538char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7539#endif
7540
7541#ifndef __EMSCRIPTEN__
7542static VALUE
7543pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7544 const struct rb_io_encoding *convconfig)
7545{
7546 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7547 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7548 rb_pid_t pid = 0;
7549 rb_io_t *fptr;
7550 VALUE port;
7551 rb_io_t *write_fptr;
7552 VALUE write_port;
7553#if defined(HAVE_WORKING_FORK)
7554 int status;
7555 char errmsg[80] = { '\0' };
7556#endif
7557#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7558 int state;
7559 struct popen_arg arg;
7560#endif
7561 int e = 0;
7562#if defined(HAVE_SPAWNV)
7563# if defined(HAVE_SPAWNVE)
7564# define DO_SPAWN(cmd, args, envp) ((args) ? \
7565 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7566 spawne(P_NOWAIT, (cmd), (envp)))
7567# else
7568# define DO_SPAWN(cmd, args, envp) ((args) ? \
7569 spawnv(P_NOWAIT, (cmd), (args)) : \
7570 spawn(P_NOWAIT, (cmd)))
7571# endif
7572# if !defined(HAVE_WORKING_FORK)
7573 char **args = NULL;
7574# if defined(HAVE_SPAWNVE)
7575 char **envp = NULL;
7576# endif
7577# endif
7578#endif
7579#if !defined(HAVE_WORKING_FORK)
7580 struct rb_execarg sarg, *sargp = &sarg;
7581#endif
7582 FILE *fp = 0;
7583 int fd = -1;
7584 int write_fd = -1;
7585#if !defined(HAVE_WORKING_FORK)
7586 const char *cmd = 0;
7587
7588 if (prog)
7589 cmd = StringValueCStr(prog);
7590#endif
7591
7592#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7593 arg.execarg_obj = execarg_obj;
7594 arg.eargp = eargp;
7595 arg.modef = fmode;
7596 arg.pair[0] = arg.pair[1] = -1;
7597 arg.write_pair[0] = arg.write_pair[1] = -1;
7598# if !defined(HAVE_WORKING_FORK)
7599 if (eargp && !eargp->use_shell) {
7600 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7601 }
7602# endif
7603 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7605 if (rb_pipe(arg.write_pair) < 0)
7606 rb_sys_fail_str(prog);
7607 if (rb_pipe(arg.pair) < 0) {
7608 e = errno;
7609 close(arg.write_pair[0]);
7610 close(arg.write_pair[1]);
7611 rb_syserr_fail_str(e, prog);
7612 }
7613 if (eargp) {
7614 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7615 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7616 }
7617 break;
7618 case FMODE_READABLE:
7619 if (rb_pipe(arg.pair) < 0)
7620 rb_sys_fail_str(prog);
7621 if (eargp)
7622 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7623 break;
7624 case FMODE_WRITABLE:
7625 if (rb_pipe(arg.pair) < 0)
7626 rb_sys_fail_str(prog);
7627 if (eargp)
7628 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7629 break;
7630 default:
7631 rb_sys_fail_str(prog);
7632 }
7633 if (!NIL_P(execarg_obj)) {
7634 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7635 if (state) {
7636 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7637 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7638 if (0 <= arg.pair[0]) close(arg.pair[0]);
7639 if (0 <= arg.pair[1]) close(arg.pair[1]);
7640 rb_execarg_parent_end(execarg_obj);
7641 rb_jump_tag(state);
7642 }
7643
7644# if defined(HAVE_WORKING_FORK)
7645 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7646# else
7647 rb_execarg_run_options(eargp, sargp, NULL, 0);
7648# if defined(HAVE_SPAWNVE)
7649 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7650# endif
7651 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7652 /* exec failed */
7653 switch (e = errno) {
7654 case EAGAIN:
7655# if EWOULDBLOCK != EAGAIN
7656 case EWOULDBLOCK:
7657# endif
7658 rb_thread_sleep(1);
7659 continue;
7660 }
7661 break;
7662 }
7663 if (eargp)
7664 rb_execarg_run_options(sargp, NULL, NULL, 0);
7665# endif
7666 rb_execarg_parent_end(execarg_obj);
7667 }
7668 else {
7669# if defined(HAVE_WORKING_FORK)
7670 pid = rb_call_proc__fork();
7671 if (pid == 0) { /* child */
7672 popen_redirect(&arg);
7673 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7674 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7675 return Qnil;
7676 }
7677# else
7679# endif
7680 }
7681
7682 /* parent */
7683 if (pid < 0) {
7684# if defined(HAVE_WORKING_FORK)
7685 e = errno;
7686# endif
7687 close(arg.pair[0]);
7688 close(arg.pair[1]);
7690 close(arg.write_pair[0]);
7691 close(arg.write_pair[1]);
7692 }
7693# if defined(HAVE_WORKING_FORK)
7694 if (errmsg[0])
7695 rb_syserr_fail(e, errmsg);
7696# endif
7697 rb_syserr_fail_str(e, prog);
7698 }
7699 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7700 close(arg.pair[1]);
7701 fd = arg.pair[0];
7702 close(arg.write_pair[0]);
7703 write_fd = arg.write_pair[1];
7704 }
7705 else if (fmode & FMODE_READABLE) {
7706 close(arg.pair[1]);
7707 fd = arg.pair[0];
7708 }
7709 else {
7710 close(arg.pair[0]);
7711 fd = arg.pair[1];
7712 }
7713#else
7714 cmd = rb_execarg_commandline(eargp, &prog);
7715 if (!NIL_P(execarg_obj)) {
7716 rb_execarg_parent_start(execarg_obj);
7717 rb_execarg_run_options(eargp, sargp, NULL, 0);
7718 }
7719 fp = popen(cmd, modestr);
7720 e = errno;
7721 if (eargp) {
7722 rb_execarg_parent_end(execarg_obj);
7723 rb_execarg_run_options(sargp, NULL, NULL, 0);
7724 }
7725 if (!fp) rb_syserr_fail_path(e, prog);
7726 fd = fileno(fp);
7727#endif
7728
7729 port = io_alloc(rb_cIO);
7730 MakeOpenFile(port, fptr);
7731 fptr->fd = fd;
7732 fptr->stdio_file = fp;
7733 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7734 if (convconfig) {
7735 fptr->encs = *convconfig;
7736#if RUBY_CRLF_ENVIRONMENT
7739 }
7740#endif
7741 }
7742 else {
7743 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7745 }
7746#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7747 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7748 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7749 }
7750#endif
7751 }
7752 fptr->pid = pid;
7753
7754 if (0 <= write_fd) {
7755 write_port = io_alloc(rb_cIO);
7756 MakeOpenFile(write_port, write_fptr);
7757 write_fptr->fd = write_fd;
7758 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7759 fptr->mode &= ~FMODE_WRITABLE;
7760 fptr->tied_io_for_writing = write_port;
7761 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7762 }
7763
7764#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7765 fptr->finalize = pipe_finalize;
7766 pipe_add_fptr(fptr);
7767#endif
7768 return port;
7769}
7770#else
7771static VALUE
7772pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7773 const struct rb_io_encoding *convconfig)
7774{
7775 rb_raise(rb_eNotImpError, "popen() is not available");
7776}
7777#endif
7778
7779static int
7780is_popen_fork(VALUE prog)
7781{
7782 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7783#if !defined(HAVE_WORKING_FORK)
7784 rb_raise(rb_eNotImpError,
7785 "fork() function is unimplemented on this machine");
7786#else
7787 return TRUE;
7788#endif
7789 }
7790 return FALSE;
7791}
7792
7793static VALUE
7794pipe_open_s(VALUE prog, const char *modestr, int fmode,
7795 const struct rb_io_encoding *convconfig)
7796{
7797 int argc = 1;
7798 VALUE *argv = &prog;
7799 VALUE execarg_obj = Qnil;
7800
7801 if (!is_popen_fork(prog))
7802 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7803 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7804}
7805
7806static VALUE
7807pipe_close(VALUE io)
7808{
7809 rb_io_t *fptr = io_close_fptr(io);
7810 if (fptr) {
7811 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7812 }
7813 return Qnil;
7814}
7815
7816static VALUE popen_finish(VALUE port, VALUE klass);
7817
7818/*
7819 * call-seq:
7820 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7821 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7822 *
7823 * Executes the given command +cmd+ as a subprocess
7824 * whose $stdin and $stdout are connected to a new stream +io+.
7825 *
7826 * This method has potential security vulnerabilities if called with untrusted input;
7827 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7828 *
7829 * If no block is given, returns the new stream,
7830 * which depending on given +mode+ may be open for reading, writing, or both.
7831 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7832 *
7833 * If a block is given, the stream is passed to the block
7834 * (again, open for reading, writing, or both);
7835 * when the block exits, the stream is closed,
7836 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7837 *
7838 * Optional argument +mode+ may be any valid \IO mode.
7839 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7840 *
7841 * Required argument +cmd+ determines which of the following occurs:
7842 *
7843 * - The process forks.
7844 * - A specified program runs in a shell.
7845 * - A specified program runs with specified arguments.
7846 * - A specified program runs with specified arguments and a specified +argv0+.
7847 *
7848 * Each of these is detailed below.
7849 *
7850 * The optional hash argument +env+ specifies name/value pairs that are to be added
7851 * to the environment variables for the subprocess:
7852 *
7853 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7854 * pipe.puts 'puts ENV["FOO"]'
7855 * pipe.close_write
7856 * pipe.gets
7857 * end => "bar\n"
7858 *
7859 * Optional keyword arguments +opts+ specify:
7860 *
7861 * - {Open options}[rdoc-ref:IO@Open+Options].
7862 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7863 * - Options for Kernel#spawn.
7864 *
7865 * <b>Forked Process</b>
7866 *
7867 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7868 * IO.popen('-') do |pipe|
7869 * if pipe
7870 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7871 * else
7872 * $stderr.puts "In child, pid is #{$$}\n"
7873 * end
7874 * end
7875 *
7876 * Output:
7877 *
7878 * In parent, child pid is 26253
7879 * In child, pid is 26253
7880 *
7881 * Note that this is not supported on all platforms.
7882 *
7883 * <b>Shell Subprocess</b>
7884 *
7885 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7886 * the program named +cmd+ is run as a shell command:
7887 *
7888 * IO.popen('uname') do |pipe|
7889 * pipe.readlines
7890 * end
7891 *
7892 * Output:
7893 *
7894 * ["Linux\n"]
7895 *
7896 * Another example:
7897 *
7898 * IO.popen('/bin/sh', 'r+') do |pipe|
7899 * pipe.puts('ls')
7900 * pipe.close_write
7901 * $stderr.puts pipe.readlines.size
7902 * end
7903 *
7904 * Output:
7905 *
7906 * 213
7907 *
7908 * <b>Program Subprocess</b>
7909 *
7910 * When argument +cmd+ is an array of strings,
7911 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7912 *
7913 * IO.popen(['du', '..', '.']) do |pipe|
7914 * $stderr.puts pipe.readlines.size
7915 * end
7916 *
7917 * Output:
7918 *
7919 * 1111
7920 *
7921 * <b>Program Subprocess with <tt>argv0</tt></b>
7922 *
7923 * When argument +cmd+ is an array whose first element is a 2-element string array
7924 * and whose remaining elements (if any) are strings:
7925 *
7926 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7927 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7928 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7929 *
7930 * Example (sets <tt>$0</tt> to 'foo'):
7931 *
7932 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7933 *
7934 * <b>Some Special Examples</b>
7935 *
7936 * # Set IO encoding.
7937 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7938 * euc_jp_string = nkf_io.read
7939 * }
7940 *
7941 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7942 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7943 * ls_result_with_error = io.read
7944 * end
7945 *
7946 * # Use mixture of spawn options and IO options.
7947 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7948 * ls_result_with_error = io.read
7949 * end
7950 *
7951 * f = IO.popen("uname")
7952 * p f.readlines
7953 * f.close
7954 * puts "Parent is #{Process.pid}"
7955 * IO.popen("date") {|f| puts f.gets }
7956 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7957 * p $?
7958 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7959 * f.puts "bar"; f.close_write; puts f.gets
7960 * }
7961 *
7962 * Output (from last section):
7963 *
7964 * ["Linux\n"]
7965 * Parent is 21346
7966 * Thu Jan 15 22:41:19 JST 2009
7967 * 21346 is here, f is #<IO:fd 3>
7968 * 21352 is here, f is nil
7969 * #<Process::Status: pid 21352 exit 0>
7970 * <foo>bar;zot;
7971 *
7972 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7973 *
7974 */
7975
7976static VALUE
7977rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7978{
7979 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7980
7981 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7982 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7983 switch (argc) {
7984 case 2:
7985 pmode = argv[1];
7986 case 1:
7987 pname = argv[0];
7988 break;
7989 default:
7990 {
7991 int ex = !NIL_P(opt);
7992 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7993 }
7994 }
7995 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7996}
7997
7998VALUE
7999rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8000{
8001 const char *modestr;
8002 VALUE tmp, execarg_obj = Qnil;
8003 int oflags, fmode;
8004 struct rb_io_encoding convconfig;
8005
8006 tmp = rb_check_array_type(pname);
8007 if (!NIL_P(tmp)) {
8008 long len = RARRAY_LEN(tmp);
8009#if SIZEOF_LONG > SIZEOF_INT
8010 if (len > INT_MAX) {
8011 rb_raise(rb_eArgError, "too many arguments");
8012 }
8013#endif
8014 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8015 RB_GC_GUARD(tmp);
8016 }
8017 else {
8018 StringValue(pname);
8019 execarg_obj = Qnil;
8020 if (!is_popen_fork(pname))
8021 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8022 }
8023 if (!NIL_P(execarg_obj)) {
8024 if (!NIL_P(opt))
8025 opt = rb_execarg_extract_options(execarg_obj, opt);
8026 if (!NIL_P(env))
8027 rb_execarg_setenv(execarg_obj, env);
8028 }
8029 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8030 modestr = rb_io_oflags_modestr(oflags);
8031
8032 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8033}
8034
8035static VALUE
8036popen_finish(VALUE port, VALUE klass)
8037{
8038 if (NIL_P(port)) {
8039 /* child */
8040 if (rb_block_given_p()) {
8041 rb_protect(rb_yield, Qnil, NULL);
8042 rb_io_flush(rb_ractor_stdout());
8043 rb_io_flush(rb_ractor_stderr());
8044 _exit(0);
8045 }
8046 return Qnil;
8047 }
8048 RBASIC_SET_CLASS(port, klass);
8049 if (rb_block_given_p()) {
8050 return rb_ensure(rb_yield, port, pipe_close, port);
8051 }
8052 return port;
8053}
8054
8055#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8056struct popen_writer_arg {
8057 char *const *argv;
8058 struct popen_arg popen;
8059};
8060
8061static int
8062exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8063{
8064 struct popen_writer_arg *pw = arg;
8065 pw->popen.modef = FMODE_WRITABLE;
8066 popen_redirect(&pw->popen);
8067 execv(pw->argv[0], pw->argv);
8068 strlcpy(errmsg, strerror(errno), buflen);
8069 return -1;
8070}
8071#endif
8072
8073FILE *
8074ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8075{
8076#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8077# ifdef HAVE_WORKING_FORK
8078 struct popen_writer_arg pw;
8079 int *const write_pair = pw.popen.pair;
8080# else
8081 int write_pair[2];
8082# endif
8083
8084 int result = rb_cloexec_pipe(write_pair);
8085 *pid = -1;
8086 if (result == 0) {
8087# ifdef HAVE_WORKING_FORK
8088 pw.argv = argv;
8089 int status;
8090 char errmsg[80] = {'\0'};
8091 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8092# else
8093 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8094 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8095# endif
8096 close(write_pair[0]);
8097 if (*pid < 0) {
8098 close(write_pair[1]);
8099 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8100 }
8101 else {
8102 return fdopen(write_pair[1], "w");
8103 }
8104 }
8105#endif
8106 return NULL;
8107}
8108
8109static VALUE
8110rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8111{
8112 struct rb_io_encoding convconfig;
8113 int oflags, fmode;
8114 mode_t perm;
8115
8116 FilePathValue(fname);
8117
8118 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8119 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8120
8121 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8122
8123 return io;
8124}
8125
8126/*
8127 * Document-method: File::open
8128 *
8129 * call-seq:
8130 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8131 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8132 *
8133 * Creates a new File object, via File.new with the given arguments.
8134 *
8135 * With no block given, returns the File object.
8136 *
8137 * With a block given, calls the block with the File object
8138 * and returns the block's value.
8139 *
8140 */
8141
8142/*
8143 * Document-method: IO::open
8144 *
8145 * call-seq:
8146 * IO.open(fd, mode = 'r', **opts) -> io
8147 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8148 *
8149 * Creates a new \IO object, via IO.new with the given arguments.
8150 *
8151 * With no block given, returns the \IO object.
8152 *
8153 * With a block given, calls the block with the \IO object
8154 * and returns the block's value.
8155 *
8156 */
8157
8158static VALUE
8159rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8160{
8162
8163 if (rb_block_given_p()) {
8164 return rb_ensure(rb_yield, io, io_close, io);
8165 }
8166
8167 return io;
8168}
8169
8170/*
8171 * call-seq:
8172 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8173 *
8174 * Opens the file at the given path with the given mode and permissions;
8175 * returns the integer file descriptor.
8176 *
8177 * If the file is to be readable, it must exist;
8178 * if the file is to be writable and does not exist,
8179 * it is created with the given permissions:
8180 *
8181 * File.write('t.tmp', '') # => 0
8182 * IO.sysopen('t.tmp') # => 8
8183 * IO.sysopen('t.tmp', 'w') # => 9
8184 *
8185 *
8186 */
8187
8188static VALUE
8189rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8190{
8191 VALUE fname, vmode, vperm;
8192 VALUE intmode;
8193 int oflags, fd;
8194 mode_t perm;
8195
8196 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8197 FilePathValue(fname);
8198
8199 if (NIL_P(vmode))
8200 oflags = O_RDONLY;
8201 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8202 oflags = NUM2INT(intmode);
8203 else {
8204 StringValue(vmode);
8205 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8206 }
8207 if (NIL_P(vperm)) perm = 0666;
8208 else perm = NUM2MODET(vperm);
8209
8210 RB_GC_GUARD(fname) = rb_str_new4(fname);
8211 fd = rb_sysopen(fname, oflags, perm);
8212 return INT2NUM(fd);
8213}
8214
8215static VALUE
8216check_pipe_command(VALUE filename_or_command)
8217{
8218 char *s = RSTRING_PTR(filename_or_command);
8219 long l = RSTRING_LEN(filename_or_command);
8220 char *e = s + l;
8221 int chlen;
8222
8223 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8224 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8225 return cmd;
8226 }
8227 return Qnil;
8228}
8229
8230/*
8231 * call-seq:
8232 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8233 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8234 *
8235 * Creates an IO object connected to the given file.
8236 *
8237 * This method has potential security vulnerabilities if called with untrusted input;
8238 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8239 *
8240 * With no block given, file stream is returned:
8241 *
8242 * open('t.txt') # => #<File:t.txt>
8243 *
8244 * With a block given, calls the block with the open file stream,
8245 * then closes the stream:
8246 *
8247 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8248 *
8249 * Output:
8250 *
8251 * #<File:t.txt>
8252 *
8253 * See File.open for details.
8254 *
8255 */
8256
8257static VALUE
8258rb_f_open(int argc, VALUE *argv, VALUE _)
8259{
8260 ID to_open = 0;
8261 int redirect = FALSE;
8262
8263 if (argc >= 1) {
8264 CONST_ID(to_open, "to_open");
8265 if (rb_respond_to(argv[0], to_open)) {
8266 redirect = TRUE;
8267 }
8268 else {
8269 VALUE tmp = argv[0];
8270 FilePathValue(tmp);
8271 if (NIL_P(tmp)) {
8272 redirect = TRUE;
8273 }
8274 else {
8275 VALUE cmd = check_pipe_command(tmp);
8276 if (!NIL_P(cmd)) {
8277 // TODO: when removed in 4.0, update command_injection.rdoc
8278 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8279 argv[0] = cmd;
8280 return rb_io_s_popen(argc, argv, rb_cIO);
8281 }
8282 }
8283 }
8284 }
8285 if (redirect) {
8286 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8287
8288 if (rb_block_given_p()) {
8289 return rb_ensure(rb_yield, io, io_close, io);
8290 }
8291 return io;
8292 }
8293 return rb_io_s_open(argc, argv, rb_cFile);
8294}
8295
8296static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const struct rb_io_encoding *, mode_t);
8297
8298static VALUE
8299rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8300{
8301 int oflags, fmode;
8302 struct rb_io_encoding convconfig;
8303 mode_t perm;
8304
8305 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8306 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8307 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8308}
8309
8310static VALUE
8311rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8312 const struct rb_io_encoding *convconfig, mode_t perm)
8313{
8314 VALUE cmd;
8315 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8316 // TODO: when removed in 4.0, update command_injection.rdoc
8317 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8318 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8319 }
8320 else {
8321 return rb_file_open_generic(io_alloc(klass), filename,
8322 oflags, fmode, convconfig, perm);
8323 }
8324}
8325
8326static VALUE
8327io_reopen(VALUE io, VALUE nfile)
8328{
8329 rb_io_t *fptr, *orig;
8330 int fd, fd2;
8331 rb_off_t pos = 0;
8332
8333 nfile = rb_io_get_io(nfile);
8334 GetOpenFile(io, fptr);
8335 GetOpenFile(nfile, orig);
8336
8337 if (fptr == orig) return io;
8338 if (RUBY_IO_EXTERNAL_P(fptr)) {
8339 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8340 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8341 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8342 rb_raise(rb_eArgError,
8343 "%s can't change access mode from \"%s\" to \"%s\"",
8344 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8345 rb_io_fmode_modestr(orig->mode));
8346 }
8347 }
8348 if (fptr->mode & FMODE_WRITABLE) {
8349 if (io_fflush(fptr) < 0)
8350 rb_sys_fail_on_write(fptr);
8351 }
8352 else {
8353 flush_before_seek(fptr, true);
8354 }
8355 if (orig->mode & FMODE_READABLE) {
8356 pos = io_tell(orig);
8357 }
8358 if (orig->mode & FMODE_WRITABLE) {
8359 if (io_fflush(orig) < 0)
8360 rb_sys_fail_on_write(fptr);
8361 }
8362
8363 /* copy rb_io_t structure */
8364 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8365 fptr->encs = orig->encs;
8366 fptr->pid = orig->pid;
8367 fptr->lineno = orig->lineno;
8368 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8369 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8370 fptr_copy_finalizer(fptr, orig);
8371
8372 fd = fptr->fd;
8373 fd2 = orig->fd;
8374 if (fd != fd2) {
8375 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8376 /* need to keep FILE objects of stdin, stdout and stderr */
8377 if (rb_cloexec_dup2(fd2, fd) < 0)
8378 rb_sys_fail_path(orig->pathv);
8379 rb_update_max_fd(fd);
8380 }
8381 else {
8382 fclose(fptr->stdio_file);
8383 fptr->stdio_file = 0;
8384 fptr->fd = -1;
8385 if (rb_cloexec_dup2(fd2, fd) < 0)
8386 rb_sys_fail_path(orig->pathv);
8387 rb_update_max_fd(fd);
8388 fptr->fd = fd;
8389 }
8391 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8392 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8393 rb_sys_fail_path(fptr->pathv);
8394 }
8395 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8396 rb_sys_fail_path(orig->pathv);
8397 }
8398 }
8399 }
8400
8401 if (fptr->mode & FMODE_BINMODE) {
8402 rb_io_binmode(io);
8403 }
8404
8405 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8406 return io;
8407}
8408
8409#ifdef _WIN32
8410int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8411#else
8412static int
8413rb_freopen(VALUE fname, const char *mode, FILE *fp)
8414{
8415 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8416 RB_GC_GUARD(fname);
8417 return errno;
8418 }
8419 return 0;
8420}
8421#endif
8422
8423/*
8424 * call-seq:
8425 * reopen(other_io) -> self
8426 * reopen(path, mode = 'r', **opts) -> self
8427 *
8428 * Reassociates the stream with another stream,
8429 * which may be of a different class.
8430 * This method may be used to redirect an existing stream
8431 * to a new destination.
8432 *
8433 * With argument +other_io+ given, reassociates with that stream:
8434 *
8435 * # Redirect $stdin from a file.
8436 * f = File.open('t.txt')
8437 * $stdin.reopen(f)
8438 * f.close
8439 *
8440 * # Redirect $stdout to a file.
8441 * f = File.open('t.tmp', 'w')
8442 * $stdout.reopen(f)
8443 * f.close
8444 *
8445 * With argument +path+ given, reassociates with a new stream to that file path:
8446 *
8447 * $stdin.reopen('t.txt')
8448 * $stdout.reopen('t.tmp', 'w')
8449 *
8450 * Optional keyword arguments +opts+ specify:
8451 *
8452 * - {Open Options}[rdoc-ref:IO@Open+Options].
8453 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8454 *
8455 */
8456
8457static VALUE
8458rb_io_reopen(int argc, VALUE *argv, VALUE file)
8459{
8460 VALUE fname, nmode, opt;
8461 int oflags;
8462 rb_io_t *fptr;
8463
8464 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8465 VALUE tmp = rb_io_check_io(fname);
8466 if (!NIL_P(tmp)) {
8467 return io_reopen(file, tmp);
8468 }
8469 }
8470
8471 FilePathValue(fname);
8472 rb_io_taint_check(file);
8473 fptr = RFILE(file)->fptr;
8474 if (!fptr) {
8475 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8476 }
8477
8478 if (!NIL_P(nmode) || !NIL_P(opt)) {
8479 int fmode;
8480 struct rb_io_encoding convconfig;
8481
8482 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8483 if (RUBY_IO_EXTERNAL_P(fptr) &&
8484 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8485 (fptr->mode & FMODE_READWRITE)) {
8486 rb_raise(rb_eArgError,
8487 "%s can't change access mode from \"%s\" to \"%s\"",
8488 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8489 rb_io_fmode_modestr(fmode));
8490 }
8491 fptr->mode = fmode;
8492 fptr->encs = convconfig;
8493 }
8494 else {
8495 oflags = rb_io_fmode_oflags(fptr->mode);
8496 }
8497
8498 fptr->pathv = fname;
8499 if (fptr->fd < 0) {
8500 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8501 fptr->stdio_file = 0;
8502 return file;
8503 }
8504
8505 if (fptr->mode & FMODE_WRITABLE) {
8506 if (io_fflush(fptr) < 0)
8507 rb_sys_fail_on_write(fptr);
8508 }
8509 fptr->rbuf.off = fptr->rbuf.len = 0;
8510
8511 if (fptr->stdio_file) {
8512 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8513 rb_io_oflags_modestr(oflags),
8514 fptr->stdio_file);
8515 if (e) rb_syserr_fail_path(e, fptr->pathv);
8516 fptr->fd = fileno(fptr->stdio_file);
8517 rb_fd_fix_cloexec(fptr->fd);
8518#ifdef USE_SETVBUF
8519 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8520 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8521#endif
8522 if (fptr->stdio_file == stderr) {
8523 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8524 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8525 }
8526 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8527 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8528 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8529 }
8530 }
8531 else {
8532 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8533 int err = 0;
8534 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8535 err = errno;
8536 (void)close(tmpfd);
8537 if (err) {
8538 rb_syserr_fail_path(err, fptr->pathv);
8539 }
8540 }
8541
8542 return file;
8543}
8544
8545/* :nodoc: */
8546static VALUE
8547rb_io_init_copy(VALUE dest, VALUE io)
8548{
8549 rb_io_t *fptr, *orig;
8550 int fd;
8551 VALUE write_io;
8552 rb_off_t pos;
8553
8554 io = rb_io_get_io(io);
8555 if (!OBJ_INIT_COPY(dest, io)) return dest;
8556 GetOpenFile(io, orig);
8557 MakeOpenFile(dest, fptr);
8558
8559 rb_io_flush(io);
8560
8561 /* copy rb_io_t structure */
8562 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8563 fptr->encs = orig->encs;
8564 fptr->pid = orig->pid;
8565 fptr->lineno = orig->lineno;
8566 fptr->timeout = orig->timeout;
8567 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8568 fptr_copy_finalizer(fptr, orig);
8569
8570 fd = ruby_dup(orig->fd);
8571 fptr->fd = fd;
8572 pos = io_tell(orig);
8573 if (0 <= pos)
8574 io_seek(fptr, pos, SEEK_SET);
8575 if (fptr->mode & FMODE_BINMODE) {
8576 rb_io_binmode(dest);
8577 }
8578
8579 write_io = GetWriteIO(io);
8580 if (io != write_io) {
8581 write_io = rb_obj_dup(write_io);
8582 fptr->tied_io_for_writing = write_io;
8583 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8584 }
8585
8586 return dest;
8587}
8588
8589/*
8590 * call-seq:
8591 * printf(format_string, *objects) -> nil
8592 *
8593 * Formats and writes +objects+ to the stream.
8594 *
8595 * For details on +format_string+, see
8596 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8597 *
8598 */
8599
8600VALUE
8601rb_io_printf(int argc, const VALUE *argv, VALUE out)
8602{
8603 rb_io_write(out, rb_f_sprintf(argc, argv));
8604 return Qnil;
8605}
8606
8607/*
8608 * call-seq:
8609 * printf(format_string, *objects) -> nil
8610 * printf(io, format_string, *objects) -> nil
8611 *
8612 * Equivalent to:
8613 *
8614 * io.write(sprintf(format_string, *objects))
8615 *
8616 * For details on +format_string+, see
8617 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8618 *
8619 * With the single argument +format_string+, formats +objects+ into the string,
8620 * then writes the formatted string to $stdout:
8621 *
8622 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8623 *
8624 * Output (on $stdout):
8625 *
8626 * 0024 24 24.00#
8627 *
8628 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8629 * then writes the formatted string to +io+:
8630 *
8631 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8632 *
8633 * Output (on $stderr):
8634 *
8635 * 0024 24 24.00# => nil
8636 *
8637 * With no arguments, does nothing.
8638 *
8639 */
8640
8641static VALUE
8642rb_f_printf(int argc, VALUE *argv, VALUE _)
8643{
8644 VALUE out;
8645
8646 if (argc == 0) return Qnil;
8647 if (RB_TYPE_P(argv[0], T_STRING)) {
8648 out = rb_ractor_stdout();
8649 }
8650 else {
8651 out = argv[0];
8652 argv++;
8653 argc--;
8654 }
8655 rb_io_write(out, rb_f_sprintf(argc, argv));
8656
8657 return Qnil;
8658}
8659
8660static void
8661deprecated_str_setter(VALUE val, ID id, VALUE *var)
8662{
8663 rb_str_setter(val, id, &val);
8664 if (!NIL_P(val)) {
8665 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8666 }
8667 *var = val;
8668}
8669
8670/*
8671 * call-seq:
8672 * print(*objects) -> nil
8673 *
8674 * Writes the given objects to the stream; returns +nil+.
8675 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8676 * (<tt>$\</tt>), if it is not +nil+.
8677 * See {Line IO}[rdoc-ref:IO@Line+IO].
8678 *
8679 * With argument +objects+ given, for each object:
8680 *
8681 * - Converts via its method +to_s+ if not a string.
8682 * - Writes to the stream.
8683 * - If not the last object, writes the output field separator
8684 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8685 *
8686 * With default separators:
8687 *
8688 * f = File.open('t.tmp', 'w+')
8689 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8690 * p $OUTPUT_RECORD_SEPARATOR
8691 * p $OUTPUT_FIELD_SEPARATOR
8692 * f.print(*objects)
8693 * f.rewind
8694 * p f.read
8695 * f.close
8696 *
8697 * Output:
8698 *
8699 * nil
8700 * nil
8701 * "00.00/10+0izerozero"
8702 *
8703 * With specified separators:
8704 *
8705 * $\ = "\n"
8706 * $, = ','
8707 * f.rewind
8708 * f.print(*objects)
8709 * f.rewind
8710 * p f.read
8711 *
8712 * Output:
8713 *
8714 * "0,0.0,0/1,0+0i,zero,zero\n"
8715 *
8716 * With no argument given, writes the content of <tt>$_</tt>
8717 * (which is usually the most recent user input):
8718 *
8719 * f = File.open('t.tmp', 'w+')
8720 * gets # Sets $_ to the most recent user input.
8721 * f.print
8722 * f.close
8723 *
8724 */
8725
8726VALUE
8727rb_io_print(int argc, const VALUE *argv, VALUE out)
8728{
8729 int i;
8730 VALUE line;
8731
8732 /* if no argument given, print `$_' */
8733 if (argc == 0) {
8734 argc = 1;
8735 line = rb_lastline_get();
8736 argv = &line;
8737 }
8738 if (argc > 1 && !NIL_P(rb_output_fs)) {
8739 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8740 }
8741 for (i=0; i<argc; i++) {
8742 if (!NIL_P(rb_output_fs) && i>0) {
8743 rb_io_write(out, rb_output_fs);
8744 }
8745 rb_io_write(out, argv[i]);
8746 }
8747 if (argc > 0 && !NIL_P(rb_output_rs)) {
8748 rb_io_write(out, rb_output_rs);
8749 }
8750
8751 return Qnil;
8752}
8753
8754/*
8755 * call-seq:
8756 * print(*objects) -> nil
8757 *
8758 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8759 * this method is the straightforward way to write to <tt>$stdout</tt>.
8760 *
8761 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8762 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8763 * <tt>$\</tt>), if it is not +nil+.
8764 *
8765 * With argument +objects+ given, for each object:
8766 *
8767 * - Converts via its method +to_s+ if not a string.
8768 * - Writes to <tt>stdout</tt>.
8769 * - If not the last object, writes the output field separator
8770 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8771 *
8772 * With default separators:
8773 *
8774 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8775 * $OUTPUT_RECORD_SEPARATOR
8776 * $OUTPUT_FIELD_SEPARATOR
8777 * print(*objects)
8778 *
8779 * Output:
8780 *
8781 * nil
8782 * nil
8783 * 00.00/10+0izerozero
8784 *
8785 * With specified separators:
8786 *
8787 * $OUTPUT_RECORD_SEPARATOR = "\n"
8788 * $OUTPUT_FIELD_SEPARATOR = ','
8789 * print(*objects)
8790 *
8791 * Output:
8792 *
8793 * 0,0.0,0/1,0+0i,zero,zero
8794 *
8795 * With no argument given, writes the content of <tt>$_</tt>
8796 * (which is usually the most recent user input):
8797 *
8798 * gets # Sets $_ to the most recent user input.
8799 * print # Prints $_.
8800 *
8801 */
8802
8803static VALUE
8804rb_f_print(int argc, const VALUE *argv, VALUE _)
8805{
8806 rb_io_print(argc, argv, rb_ractor_stdout());
8807 return Qnil;
8808}
8809
8810/*
8811 * call-seq:
8812 * putc(object) -> object
8813 *
8814 * Writes a character to the stream.
8815 * See {Character IO}[rdoc-ref:IO@Character+IO].
8816 *
8817 * If +object+ is numeric, converts to integer if necessary,
8818 * then writes the character whose code is the
8819 * least significant byte;
8820 * if +object+ is a string, writes the first character:
8821 *
8822 * $stdout.putc "A"
8823 * $stdout.putc 65
8824 *
8825 * Output:
8826 *
8827 * AA
8828 *
8829 */
8830
8831static VALUE
8832rb_io_putc(VALUE io, VALUE ch)
8833{
8834 VALUE str;
8835 if (RB_TYPE_P(ch, T_STRING)) {
8836 str = rb_str_substr(ch, 0, 1);
8837 }
8838 else {
8839 char c = NUM2CHR(ch);
8840 str = rb_str_new(&c, 1);
8841 }
8842 rb_io_write(io, str);
8843 return ch;
8844}
8845
8846#define forward(obj, id, argc, argv) \
8847 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8848#define forward_public(obj, id, argc, argv) \
8849 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8850#define forward_current(id, argc, argv) \
8851 forward_public(ARGF.current_file, id, argc, argv)
8852
8853/*
8854 * call-seq:
8855 * putc(int) -> int
8856 *
8857 * Equivalent to:
8858 *
8859 * $stdout.putc(int)
8860 *
8861 * See IO#putc for important information regarding multi-byte characters.
8862 *
8863 */
8864
8865static VALUE
8866rb_f_putc(VALUE recv, VALUE ch)
8867{
8868 VALUE r_stdout = rb_ractor_stdout();
8869 if (recv == r_stdout) {
8870 return rb_io_putc(recv, ch);
8871 }
8872 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8873}
8874
8875
8876int
8877rb_str_end_with_asciichar(VALUE str, int c)
8878{
8879 long len = RSTRING_LEN(str);
8880 const char *ptr = RSTRING_PTR(str);
8881 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8882 int n;
8883
8884 if (len == 0) return 0;
8885 if ((n = rb_enc_mbminlen(enc)) == 1) {
8886 return ptr[len - 1] == c;
8887 }
8888 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8889}
8890
8891static VALUE
8892io_puts_ary(VALUE ary, VALUE out, int recur)
8893{
8894 VALUE tmp;
8895 long i;
8896
8897 if (recur) {
8898 tmp = rb_str_new2("[...]");
8899 rb_io_puts(1, &tmp, out);
8900 return Qtrue;
8901 }
8902 ary = rb_check_array_type(ary);
8903 if (NIL_P(ary)) return Qfalse;
8904 for (i=0; i<RARRAY_LEN(ary); i++) {
8905 tmp = RARRAY_AREF(ary, i);
8906 rb_io_puts(1, &tmp, out);
8907 }
8908 return Qtrue;
8909}
8910
8911/*
8912 * call-seq:
8913 * puts(*objects) -> nil
8914 *
8915 * Writes the given +objects+ to the stream, which must be open for writing;
8916 * returns +nil+.\
8917 * Writes a newline after each that does not already end with a newline sequence.
8918 * If called without arguments, writes a newline.
8919 * See {Line IO}[rdoc-ref:IO@Line+IO].
8920 *
8921 * Note that each added newline is the character <tt>"\n"<//tt>,
8922 * not the output record separator (<tt>$\</tt>).
8923 *
8924 * Treatment for each object:
8925 *
8926 * - String: writes the string.
8927 * - Neither string nor array: writes <tt>object.to_s</tt>.
8928 * - Array: writes each element of the array; arrays may be nested.
8929 *
8930 * To keep these examples brief, we define this helper method:
8931 *
8932 * def show(*objects)
8933 * # Puts objects to file.
8934 * f = File.new('t.tmp', 'w+')
8935 * f.puts(objects)
8936 * # Return file content.
8937 * f.rewind
8938 * p f.read
8939 * f.close
8940 * end
8941 *
8942 * # Strings without newlines.
8943 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8944 * # Strings, some with newlines.
8945 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8946 *
8947 * # Neither strings nor arrays:
8948 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8949 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8950 *
8951 * # Array of strings.
8952 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8953 * # Nested arrays.
8954 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8955 *
8956 */
8957
8958VALUE
8959rb_io_puts(int argc, const VALUE *argv, VALUE out)
8960{
8961 VALUE line, args[2];
8962
8963 /* if no argument given, print newline. */
8964 if (argc == 0) {
8965 rb_io_write(out, rb_default_rs);
8966 return Qnil;
8967 }
8968 for (int i = 0; i < argc; i++) {
8969 // Convert the argument to a string:
8970 if (RB_TYPE_P(argv[i], T_STRING)) {
8971 line = argv[i];
8972 }
8973 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8974 continue;
8975 }
8976 else {
8977 line = rb_obj_as_string(argv[i]);
8978 }
8979
8980 // Write the line:
8981 int n = 0;
8982 if (RSTRING_LEN(line) == 0) {
8983 args[n++] = rb_default_rs;
8984 }
8985 else {
8986 args[n++] = line;
8987 if (!rb_str_end_with_asciichar(line, '\n')) {
8988 args[n++] = rb_default_rs;
8989 }
8990 }
8991
8992 rb_io_writev(out, n, args);
8993 }
8994
8995 return Qnil;
8996}
8997
8998/*
8999 * call-seq:
9000 * puts(*objects) -> nil
9001 *
9002 * Equivalent to
9003 *
9004 * $stdout.puts(objects)
9005 */
9006
9007static VALUE
9008rb_f_puts(int argc, VALUE *argv, VALUE recv)
9009{
9010 VALUE r_stdout = rb_ractor_stdout();
9011 if (recv == r_stdout) {
9012 return rb_io_puts(argc, argv, recv);
9013 }
9014 return forward(r_stdout, rb_intern("puts"), argc, argv);
9015}
9016
9017static VALUE
9018rb_p_write(VALUE str)
9019{
9020 VALUE args[2];
9021 args[0] = str;
9022 args[1] = rb_default_rs;
9023 VALUE r_stdout = rb_ractor_stdout();
9024 if (RB_TYPE_P(r_stdout, T_FILE) &&
9025 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9026 io_writev(2, args, r_stdout);
9027 }
9028 else {
9029 rb_io_writev(r_stdout, 2, args);
9030 }
9031 return Qnil;
9032}
9033
9034void
9035rb_p(VALUE obj) /* for debug print within C code */
9036{
9037 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9038}
9039
9040static VALUE
9041rb_p_result(int argc, const VALUE *argv)
9042{
9043 VALUE ret = Qnil;
9044
9045 if (argc == 1) {
9046 ret = argv[0];
9047 }
9048 else if (argc > 1) {
9049 ret = rb_ary_new4(argc, argv);
9050 }
9051 VALUE r_stdout = rb_ractor_stdout();
9052 if (RB_TYPE_P(r_stdout, T_FILE)) {
9053 rb_uninterruptible(rb_io_flush, r_stdout);
9054 }
9055 return ret;
9056}
9057
9058/*
9059 * call-seq:
9060 * p(object) -> obj
9061 * p(*objects) -> array of objects
9062 * p -> nil
9063 *
9064 * For each object +obj+, executes:
9065 *
9066 * $stdout.write(obj.inspect, "\n")
9067 *
9068 * With one object given, returns the object;
9069 * with multiple objects given, returns an array containing the objects;
9070 * with no object given, returns +nil+.
9071 *
9072 * Examples:
9073 *
9074 * r = Range.new(0, 4)
9075 * p r # => 0..4
9076 * p [r, r, r] # => [0..4, 0..4, 0..4]
9077 * p # => nil
9078 *
9079 * Output:
9080 *
9081 * 0..4
9082 * [0..4, 0..4, 0..4]
9083 *
9084 * Kernel#p is designed for debugging purposes.
9085 * Ruby implementations may define Kernel#p to be uninterruptible
9086 * in whole or in part.
9087 * On CRuby, Kernel#p's writing of data is uninterruptible.
9088 */
9089
9090static VALUE
9091rb_f_p(int argc, VALUE *argv, VALUE self)
9092{
9093 int i;
9094 for (i=0; i<argc; i++) {
9095 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9096 rb_uninterruptible(rb_p_write, inspected);
9097 }
9098 return rb_p_result(argc, argv);
9099}
9100
9101/*
9102 * call-seq:
9103 * display(port = $>) -> nil
9104 *
9105 * Writes +self+ on the given port:
9106 *
9107 * 1.display
9108 * "cat".display
9109 * [ 4, 5, 6 ].display
9110 * puts
9111 *
9112 * Output:
9113 *
9114 * 1cat[4, 5, 6]
9115 *
9116 */
9117
9118static VALUE
9119rb_obj_display(int argc, VALUE *argv, VALUE self)
9120{
9121 VALUE out;
9122
9123 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9124 rb_io_write(out, self);
9125
9126 return Qnil;
9127}
9128
9129static int
9130rb_stderr_to_original_p(VALUE err)
9131{
9132 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9133}
9134
9135void
9136rb_write_error2(const char *mesg, long len)
9137{
9138 VALUE out = rb_ractor_stderr();
9139 if (rb_stderr_to_original_p(out)) {
9140#ifdef _WIN32
9141 if (isatty(fileno(stderr))) {
9142 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9143 }
9144#endif
9145 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9146 /* failed to write to stderr, what can we do? */
9147 return;
9148 }
9149 }
9150 else {
9151 rb_io_write(out, rb_str_new(mesg, len));
9152 }
9153}
9154
9155void
9156rb_write_error(const char *mesg)
9157{
9158 rb_write_error2(mesg, strlen(mesg));
9159}
9160
9161void
9162rb_write_error_str(VALUE mesg)
9163{
9164 VALUE out = rb_ractor_stderr();
9165 /* a stopgap measure for the time being */
9166 if (rb_stderr_to_original_p(out)) {
9167 size_t len = (size_t)RSTRING_LEN(mesg);
9168#ifdef _WIN32
9169 if (isatty(fileno(stderr))) {
9170 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9171 }
9172#endif
9173 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9174 RB_GC_GUARD(mesg);
9175 return;
9176 }
9177 }
9178 else {
9179 /* may unlock GVL, and */
9180 rb_io_write(out, mesg);
9181 }
9182}
9183
9184int
9185rb_stderr_tty_p(void)
9186{
9187 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9188 return isatty(fileno(stderr));
9189 return 0;
9190}
9191
9192static void
9193must_respond_to(ID mid, VALUE val, ID id)
9194{
9195 if (!rb_respond_to(val, mid)) {
9196 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9197 rb_id2str(id), rb_id2str(mid),
9198 rb_obj_class(val));
9199 }
9200}
9201
9202static void
9203stdin_setter(VALUE val, ID id, VALUE *ptr)
9204{
9206}
9207
9208static VALUE
9209stdin_getter(ID id, VALUE *ptr)
9210{
9211 return rb_ractor_stdin();
9212}
9213
9214static void
9215stdout_setter(VALUE val, ID id, VALUE *ptr)
9216{
9217 must_respond_to(id_write, val, id);
9219}
9220
9221static VALUE
9222stdout_getter(ID id, VALUE *ptr)
9223{
9224 return rb_ractor_stdout();
9225}
9226
9227static void
9228stderr_setter(VALUE val, ID id, VALUE *ptr)
9229{
9230 must_respond_to(id_write, val, id);
9232}
9233
9234static VALUE
9235stderr_getter(ID id, VALUE *ptr)
9236{
9237 return rb_ractor_stderr();
9238}
9239
9240static VALUE
9241allocate_and_open_new_file(VALUE klass)
9242{
9243 VALUE self = io_alloc(klass);
9244 rb_io_make_open_file(self);
9245 return self;
9246}
9247
9248VALUE
9249rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9250{
9251 int state;
9252 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9253 if (state) {
9254 /* if we raised an exception allocating an IO object, but the caller
9255 intended to transfer ownership of this FD to us, close the fd before
9256 raising the exception. Otherwise, we would leak a FD - the caller
9257 expects GC to close the file, but we never got around to assigning
9258 it to a rb_io. */
9259 if (!(mode & FMODE_EXTERNAL)) {
9260 maygvl_close(descriptor, 0);
9261 }
9262 rb_jump_tag(state);
9263 }
9264
9265
9266 rb_io_t *io = RFILE(self)->fptr;
9267 io->self = self;
9268 io->fd = descriptor;
9269 io->mode = mode;
9270
9271 /* At this point, Ruby fully owns the descriptor, and will close it when
9272 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9273 in the rest of this method. */
9274
9275 if (NIL_P(path)) {
9276 io->pathv = Qnil;
9277 }
9278 else {
9279 StringValue(path);
9280 io->pathv = rb_str_new_frozen(path);
9281 }
9282
9283 io->timeout = timeout;
9284
9285 if (encoding) {
9286 io->encs = *encoding;
9287 }
9288
9289 rb_update_max_fd(descriptor);
9290
9291 return self;
9292}
9293
9294static VALUE
9295prep_io(int fd, int fmode, VALUE klass, const char *path)
9296{
9297 VALUE path_value = Qnil;
9298 rb_encoding *e;
9299 struct rb_io_encoding convconfig;
9300
9301 if (path) {
9302 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9303 }
9304
9305 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9306 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9307 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9310#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9311 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9312 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9313 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9314#endif
9315 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9316 convconfig.ecopts = Qnil;
9317
9318 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9319 rb_io_t*io = RFILE(self)->fptr;
9320
9321 if (!io_check_tty(io)) {
9322#ifdef __CYGWIN__
9323 io->mode |= FMODE_BINMODE;
9324 setmode(fd, O_BINARY);
9325#endif
9326 }
9327
9328 return self;
9329}
9330
9331VALUE
9332rb_io_fdopen(int fd, int oflags, const char *path)
9333{
9334 VALUE klass = rb_cIO;
9335
9336 if (path && strcmp(path, "-")) klass = rb_cFile;
9337 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9338}
9339
9340static VALUE
9341prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9342{
9343 rb_io_t *fptr;
9344 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9345
9346 GetOpenFile(io, fptr);
9348#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9349 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9350 if (fmode & FMODE_READABLE) {
9352 }
9353#endif
9354 fptr->stdio_file = f;
9355
9356 return io;
9357}
9358
9359VALUE
9360rb_io_prep_stdin(void)
9361{
9362 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9363}
9364
9365VALUE
9366rb_io_prep_stdout(void)
9367{
9368 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9369}
9370
9371VALUE
9372rb_io_prep_stderr(void)
9373{
9374 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9375}
9376
9377FILE *
9379{
9380 if (!fptr->stdio_file) {
9381 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9382 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9383 }
9384 return fptr->stdio_file;
9385}
9386
9387static inline void
9388rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9389{
9390 buf->ptr = NULL;
9391 buf->off = 0;
9392 buf->len = 0;
9393 buf->capa = 0;
9394}
9395
9396static inline rb_io_t *
9397rb_io_fptr_new(void)
9398{
9399 rb_io_t *fp = ALLOC(rb_io_t);
9400 fp->self = Qnil;
9401 fp->fd = -1;
9402 fp->stdio_file = NULL;
9403 fp->mode = 0;
9404 fp->pid = 0;
9405 fp->lineno = 0;
9406 fp->pathv = Qnil;
9407 fp->finalize = 0;
9408 rb_io_buffer_init(&fp->wbuf);
9409 rb_io_buffer_init(&fp->rbuf);
9410 rb_io_buffer_init(&fp->cbuf);
9411 fp->readconv = NULL;
9412 fp->writeconv = NULL;
9414 fp->writeconv_pre_ecflags = 0;
9416 fp->writeconv_initialized = 0;
9417 fp->tied_io_for_writing = 0;
9418 fp->encs.enc = NULL;
9419 fp->encs.enc2 = NULL;
9420 fp->encs.ecflags = 0;
9421 fp->encs.ecopts = Qnil;
9422 fp->write_lock = Qnil;
9423 fp->timeout = Qnil;
9424 return fp;
9425}
9426
9427rb_io_t *
9428rb_io_make_open_file(VALUE obj)
9429{
9430 rb_io_t *fp = 0;
9431
9432 Check_Type(obj, T_FILE);
9433 if (RFILE(obj)->fptr) {
9434 rb_io_close(obj);
9435 rb_io_fptr_finalize(RFILE(obj)->fptr);
9436 RFILE(obj)->fptr = 0;
9437 }
9438 fp = rb_io_fptr_new();
9439 fp->self = obj;
9440 RFILE(obj)->fptr = fp;
9441 return fp;
9442}
9443
9444static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9445
9446/*
9447 * call-seq:
9448 * IO.new(fd, mode = 'r', **opts) -> io
9449 *
9450 * Creates and returns a new \IO object (file stream) from a file descriptor.
9451 *
9452 * \IO.new may be useful for interaction with low-level libraries.
9453 * For higher-level interactions, it may be simpler to create
9454 * the file stream using File.open.
9455 *
9456 * Argument +fd+ must be a valid file descriptor (integer):
9457 *
9458 * path = 't.tmp'
9459 * fd = IO.sysopen(path) # => 3
9460 * IO.new(fd) # => #<IO:fd 3>
9461 *
9462 * The new \IO object does not inherit encoding
9463 * (because the integer file descriptor does not have an encoding):
9464 *
9465 * fd = IO.sysopen('t.rus', 'rb')
9466 * io = IO.new(fd)
9467 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9468 *
9469 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9470 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9471 *
9472 * IO.new(fd, 'w') # => #<IO:fd 3>
9473 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9474 *
9475 * Optional keyword arguments +opts+ specify:
9476 *
9477 * - {Open Options}[rdoc-ref:IO@Open+Options].
9478 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9479 *
9480 * Examples:
9481 *
9482 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9483 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9484 *
9485 */
9486
9487static VALUE
9488rb_io_initialize(int argc, VALUE *argv, VALUE io)
9489{
9490 VALUE fnum, vmode;
9491 VALUE opt;
9492
9493 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9494 return io_initialize(io, fnum, vmode, opt);
9495}
9496
9497static VALUE
9498io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9499{
9500 rb_io_t *fp;
9501 int fd, fmode, oflags = O_RDONLY;
9502 struct rb_io_encoding convconfig;
9503#if defined(HAVE_FCNTL) && defined(F_GETFL)
9504 int ofmode;
9505#else
9506 struct stat st;
9507#endif
9508
9509 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9510
9511 fd = NUM2INT(fnum);
9512 if (rb_reserved_fd_p(fd)) {
9513 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9514 }
9515#if defined(HAVE_FCNTL) && defined(F_GETFL)
9516 oflags = fcntl(fd, F_GETFL);
9517 if (oflags == -1) rb_sys_fail(0);
9518#else
9519 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9520#endif
9521 rb_update_max_fd(fd);
9522#if defined(HAVE_FCNTL) && defined(F_GETFL)
9523 ofmode = rb_io_oflags_fmode(oflags);
9524 if (NIL_P(vmode)) {
9525 fmode = ofmode;
9526 }
9527 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9528 VALUE error = INT2FIX(EINVAL);
9530 }
9531#endif
9532 VALUE path = Qnil;
9533
9534 if (!NIL_P(opt)) {
9535 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9536 fmode |= FMODE_EXTERNAL;
9537 }
9538
9539 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9540 if (!NIL_P(path)) {
9541 StringValue(path);
9542 path = rb_str_new_frozen(path);
9543 }
9544 }
9545
9546 MakeOpenFile(io, fp);
9547 fp->self = io;
9548 fp->fd = fd;
9549 fp->mode = fmode;
9550 fp->encs = convconfig;
9551 fp->pathv = path;
9552 fp->timeout = Qnil;
9553 clear_codeconv(fp);
9554 io_check_tty(fp);
9555 if (fileno(stdin) == fd)
9556 fp->stdio_file = stdin;
9557 else if (fileno(stdout) == fd)
9558 fp->stdio_file = stdout;
9559 else if (fileno(stderr) == fd)
9560 fp->stdio_file = stderr;
9561
9562 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9563 return io;
9564}
9565
9566/*
9567 * call-seq:
9568 * set_encoding_by_bom -> encoding or nil
9569 *
9570 * If the stream begins with a BOM
9571 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9572 * consumes the BOM and sets the external encoding accordingly;
9573 * returns the result encoding if found, or +nil+ otherwise:
9574 *
9575 * File.write('t.tmp', "\u{FEFF}abc")
9576 * io = File.open('t.tmp', 'rb')
9577 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9578 * io.close
9579 *
9580 * File.write('t.tmp', 'abc')
9581 * io = File.open('t.tmp', 'rb')
9582 * io.set_encoding_by_bom # => nil
9583 * io.close
9584 *
9585 * Raises an exception if the stream is not binmode
9586 * or its encoding has already been set.
9587 *
9588 */
9589
9590static VALUE
9591rb_io_set_encoding_by_bom(VALUE io)
9592{
9593 rb_io_t *fptr;
9594
9595 GetOpenFile(io, fptr);
9596 if (!(fptr->mode & FMODE_BINMODE)) {
9597 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9598 }
9599 if (fptr->encs.enc2) {
9600 rb_raise(rb_eArgError, "encoding conversion is set");
9601 }
9602 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9603 rb_raise(rb_eArgError, "encoding is set to %s already",
9604 rb_enc_name(fptr->encs.enc));
9605 }
9606 if (!io_set_encoding_by_bom(io)) return Qnil;
9607 return rb_enc_from_encoding(fptr->encs.enc);
9608}
9609
9610/*
9611 * call-seq:
9612 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9613 *
9614 * Opens the file at the given +path+ according to the given +mode+;
9615 * creates and returns a new File object for that file.
9616 *
9617 * The new File object is buffered mode (or non-sync mode), unless
9618 * +filename+ is a tty.
9619 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9620 *
9621 * Argument +path+ must be a valid file path:
9622 *
9623 * f = File.new('/etc/fstab')
9624 * f.close
9625 * f = File.new('t.txt')
9626 * f.close
9627 *
9628 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9629 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9630 *
9631 * f = File.new('t.tmp', 'w')
9632 * f.close
9633 * f = File.new('t.tmp', File::RDONLY)
9634 * f.close
9635 *
9636 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9637 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9638 *
9639 * f = File.new('t.tmp', File::CREAT, 0644)
9640 * f.close
9641 * f = File.new('t.tmp', File::CREAT, 0444)
9642 * f.close
9643 *
9644 * Optional keyword arguments +opts+ specify:
9645 *
9646 * - {Open Options}[rdoc-ref:IO@Open+Options].
9647 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9648 *
9649 */
9650
9651static VALUE
9652rb_file_initialize(int argc, VALUE *argv, VALUE io)
9653{
9654 if (RFILE(io)->fptr) {
9655 rb_raise(rb_eRuntimeError, "reinitializing File");
9656 }
9657 VALUE fname, vmode, vperm, opt;
9658 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9659 if (posargc < 3) { /* perm is File only */
9660 VALUE fd = rb_check_to_int(fname);
9661
9662 if (!NIL_P(fd)) {
9663 return io_initialize(io, fd, vmode, opt);
9664 }
9665 }
9666 return rb_open_file(io, fname, vmode, vperm, opt);
9667}
9668
9669/* :nodoc: */
9670static VALUE
9671rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9672{
9673 if (rb_block_given_p()) {
9674 VALUE cname = rb_obj_as_string(klass);
9675
9676 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9677 cname, cname);
9678 }
9679 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9680}
9681
9682
9683/*
9684 * call-seq:
9685 * IO.for_fd(fd, mode = 'r', **opts) -> io
9686 *
9687 * Synonym for IO.new.
9688 *
9689 */
9690
9691static VALUE
9692rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9693{
9694 VALUE io = rb_obj_alloc(klass);
9695 rb_io_initialize(argc, argv, io);
9696 return io;
9697}
9698
9699/*
9700 * call-seq:
9701 * ios.autoclose? -> true or false
9702 *
9703 * Returns +true+ if the underlying file descriptor of _ios_ will be
9704 * closed at its finalization or at calling #close, otherwise +false+.
9705 */
9706
9707static VALUE
9708rb_io_autoclose_p(VALUE io)
9709{
9710 rb_io_t *fptr = RFILE(io)->fptr;
9711 rb_io_check_closed(fptr);
9712 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9713}
9714
9715/*
9716 * call-seq:
9717 * io.autoclose = bool -> true or false
9718 *
9719 * Sets auto-close flag.
9720 *
9721 * f = File.open(File::NULL)
9722 * IO.for_fd(f.fileno).close
9723 * f.gets # raises Errno::EBADF
9724 *
9725 * f = File.open(File::NULL)
9726 * g = IO.for_fd(f.fileno)
9727 * g.autoclose = false
9728 * g.close
9729 * f.gets # won't cause Errno::EBADF
9730 */
9731
9732static VALUE
9733rb_io_set_autoclose(VALUE io, VALUE autoclose)
9734{
9735 rb_io_t *fptr;
9736 GetOpenFile(io, fptr);
9737 if (!RTEST(autoclose))
9738 fptr->mode |= FMODE_EXTERNAL;
9739 else
9740 fptr->mode &= ~FMODE_EXTERNAL;
9741 return autoclose;
9742}
9743
9744static VALUE
9745io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9746{
9747 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9748
9749 if (!RB_TEST(result)) {
9750 return Qnil;
9751 }
9752
9753 int mask = RB_NUM2INT(result);
9754
9755 if (mask & event) {
9756 if (return_io)
9757 return io;
9758 else
9759 return result;
9760 }
9761 else {
9762 return Qfalse;
9763 }
9764}
9765
9766/*
9767 * call-seq:
9768 * io.wait_readable -> truthy or falsy
9769 * io.wait_readable(timeout) -> truthy or falsy
9770 *
9771 * Waits until IO is readable and returns a truthy value, or a falsy
9772 * value when times out. Returns a truthy value immediately when
9773 * buffered data is available.
9774 */
9775
9776static VALUE
9777io_wait_readable(int argc, VALUE *argv, VALUE io)
9778{
9779 rb_io_t *fptr;
9780
9781 RB_IO_POINTER(io, fptr);
9783
9784 if (rb_io_read_pending(fptr)) return Qtrue;
9785
9786 rb_check_arity(argc, 0, 1);
9787 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9788
9789 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9790}
9791
9792/*
9793 * call-seq:
9794 * io.wait_writable -> truthy or falsy
9795 * io.wait_writable(timeout) -> truthy or falsy
9796 *
9797 * Waits until IO is writable and returns a truthy value or a falsy
9798 * value when times out.
9799 */
9800static VALUE
9801io_wait_writable(int argc, VALUE *argv, VALUE io)
9802{
9803 rb_io_t *fptr;
9804
9805 RB_IO_POINTER(io, fptr);
9807
9808 rb_check_arity(argc, 0, 1);
9809 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9810
9811 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9812}
9813
9814/*
9815 * call-seq:
9816 * io.wait_priority -> truthy or falsy
9817 * io.wait_priority(timeout) -> truthy or falsy
9818 *
9819 * Waits until IO is priority and returns a truthy value or a falsy
9820 * value when times out. Priority data is sent and received using
9821 * the Socket::MSG_OOB flag and is typically limited to streams.
9822 */
9823static VALUE
9824io_wait_priority(int argc, VALUE *argv, VALUE io)
9825{
9826 rb_io_t *fptr = NULL;
9827
9828 RB_IO_POINTER(io, fptr);
9830
9831 if (rb_io_read_pending(fptr)) return Qtrue;
9832
9833 rb_check_arity(argc, 0, 1);
9834 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9835
9836 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9837}
9838
9839static int
9840wait_mode_sym(VALUE mode)
9841{
9842 if (mode == ID2SYM(rb_intern("r"))) {
9843 return RB_WAITFD_IN;
9844 }
9845 if (mode == ID2SYM(rb_intern("read"))) {
9846 return RB_WAITFD_IN;
9847 }
9848 if (mode == ID2SYM(rb_intern("readable"))) {
9849 return RB_WAITFD_IN;
9850 }
9851 if (mode == ID2SYM(rb_intern("w"))) {
9852 return RB_WAITFD_OUT;
9853 }
9854 if (mode == ID2SYM(rb_intern("write"))) {
9855 return RB_WAITFD_OUT;
9856 }
9857 if (mode == ID2SYM(rb_intern("writable"))) {
9858 return RB_WAITFD_OUT;
9859 }
9860 if (mode == ID2SYM(rb_intern("rw"))) {
9861 return RB_WAITFD_IN|RB_WAITFD_OUT;
9862 }
9863 if (mode == ID2SYM(rb_intern("read_write"))) {
9864 return RB_WAITFD_IN|RB_WAITFD_OUT;
9865 }
9866 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9867 return RB_WAITFD_IN|RB_WAITFD_OUT;
9868 }
9869
9870 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9871}
9872
9873static inline enum rb_io_event
9874io_event_from_value(VALUE value)
9875{
9876 int events = RB_NUM2INT(value);
9877
9878 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9879
9880 return events;
9881}
9882
9883/*
9884 * call-seq:
9885 * io.wait(events, timeout) -> event mask, false or nil
9886 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9887 *
9888 * Waits until the IO becomes ready for the specified events and returns the
9889 * subset of events that become ready, or a falsy value when times out.
9890 *
9891 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9892 * +IO::PRIORITY+.
9893 *
9894 * Returns an event mask (truthy value) immediately when buffered data is available.
9895 *
9896 * Optional parameter +mode+ is one of +:read+, +:write+, or
9897 * +:read_write+.
9898 */
9899
9900static VALUE
9901io_wait(int argc, VALUE *argv, VALUE io)
9902{
9903 VALUE timeout = Qundef;
9904 enum rb_io_event events = 0;
9905 int return_io = 0;
9906
9907 // The documented signature for this method is actually incorrect.
9908 // A single timeout is allowed in any position, and multiple symbols can be given.
9909 // Whether this is intentional or not, I don't know, and as such I consider this to
9910 // be a legacy/slow path.
9911 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9912 // We'd prefer to return the actual mask, but this form would return the io itself:
9913 return_io = 1;
9914
9915 // Slow/messy path:
9916 for (int i = 0; i < argc; i += 1) {
9917 if (RB_SYMBOL_P(argv[i])) {
9918 events |= wait_mode_sym(argv[i]);
9919 }
9920 else if (UNDEF_P(timeout)) {
9921 rb_time_interval(timeout = argv[i]);
9922 }
9923 else {
9924 rb_raise(rb_eArgError, "timeout given more than once");
9925 }
9926 }
9927
9928 if (UNDEF_P(timeout)) timeout = Qnil;
9929
9930 if (events == 0) {
9931 events = RUBY_IO_READABLE;
9932 }
9933 }
9934 else /* argc == 2 and neither are symbols */ {
9935 // This is the fast path:
9936 events = io_event_from_value(argv[0]);
9937 timeout = argv[1];
9938 }
9939
9940 if (events & RUBY_IO_READABLE) {
9941 rb_io_t *fptr = NULL;
9942 RB_IO_POINTER(io, fptr);
9943
9944 if (rb_io_read_pending(fptr)) {
9945 // This was the original behaviour:
9946 if (return_io) return Qtrue;
9947 // New behaviour always returns an event mask:
9948 else return RB_INT2NUM(RUBY_IO_READABLE);
9949 }
9950 }
9951
9952 return io_wait_event(io, events, timeout, return_io);
9953}
9954
9955static void
9956argf_mark(void *ptr)
9957{
9958 struct argf *p = ptr;
9959 rb_gc_mark(p->filename);
9960 rb_gc_mark(p->current_file);
9961 rb_gc_mark(p->argv);
9962 rb_gc_mark(p->inplace);
9963 rb_gc_mark(p->encs.ecopts);
9964}
9965
9966static size_t
9967argf_memsize(const void *ptr)
9968{
9969 const struct argf *p = ptr;
9970 size_t size = sizeof(*p);
9971 return size;
9972}
9973
9974static const rb_data_type_t argf_type = {
9975 "ARGF",
9976 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9977 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9978};
9979
9980static inline void
9981argf_init(struct argf *p, VALUE v)
9982{
9983 p->filename = Qnil;
9984 p->current_file = Qnil;
9985 p->lineno = 0;
9986 p->argv = v;
9987}
9988
9989static VALUE
9990argf_alloc(VALUE klass)
9991{
9992 struct argf *p;
9993 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9994
9995 argf_init(p, Qnil);
9996 return argf;
9997}
9998
9999#undef rb_argv
10000
10001/* :nodoc: */
10002static VALUE
10003argf_initialize(VALUE argf, VALUE argv)
10004{
10005 memset(&ARGF, 0, sizeof(ARGF));
10006 argf_init(&ARGF, argv);
10007
10008 return argf;
10009}
10010
10011/* :nodoc: */
10012static VALUE
10013argf_initialize_copy(VALUE argf, VALUE orig)
10014{
10015 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10016 ARGF = argf_of(orig);
10017 ARGF.argv = rb_obj_dup(ARGF.argv);
10018 return argf;
10019}
10020
10021/*
10022 * call-seq:
10023 * ARGF.lineno = integer -> integer
10024 *
10025 * Sets the line number of ARGF as a whole to the given Integer.
10026 *
10027 * ARGF sets the line number automatically as you read data, so normally
10028 * you will not need to set it explicitly. To access the current line number
10029 * use ARGF.lineno.
10030 *
10031 * For example:
10032 *
10033 * ARGF.lineno #=> 0
10034 * ARGF.readline #=> "This is line 1\n"
10035 * ARGF.lineno #=> 1
10036 * ARGF.lineno = 0 #=> 0
10037 * ARGF.lineno #=> 0
10038 */
10039static VALUE
10040argf_set_lineno(VALUE argf, VALUE val)
10041{
10042 ARGF.lineno = NUM2INT(val);
10043 ARGF.last_lineno = ARGF.lineno;
10044 return val;
10045}
10046
10047/*
10048 * call-seq:
10049 * ARGF.lineno -> integer
10050 *
10051 * Returns the current line number of ARGF as a whole. This value
10052 * can be set manually with ARGF.lineno=.
10053 *
10054 * For example:
10055 *
10056 * ARGF.lineno #=> 0
10057 * ARGF.readline #=> "This is line 1\n"
10058 * ARGF.lineno #=> 1
10059 */
10060static VALUE
10061argf_lineno(VALUE argf)
10062{
10063 return INT2FIX(ARGF.lineno);
10064}
10065
10066static VALUE
10067argf_forward(int argc, VALUE *argv, VALUE argf)
10068{
10069 return forward_current(rb_frame_this_func(), argc, argv);
10070}
10071
10072#define next_argv() argf_next_argv(argf)
10073#define ARGF_GENERIC_INPUT_P() \
10074 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10075#define ARGF_FORWARD(argc, argv) do {\
10076 if (ARGF_GENERIC_INPUT_P())\
10077 return argf_forward((argc), (argv), argf);\
10078} while (0)
10079#define NEXT_ARGF_FORWARD(argc, argv) do {\
10080 if (!next_argv()) return Qnil;\
10081 ARGF_FORWARD((argc), (argv));\
10082} while (0)
10083
10084static void
10085argf_close(VALUE argf)
10086{
10087 VALUE file = ARGF.current_file;
10088 if (file == rb_stdin) return;
10089 if (RB_TYPE_P(file, T_FILE)) {
10090 rb_io_set_write_io(file, Qnil);
10091 }
10092 io_close(file);
10093 ARGF.init_p = -1;
10094}
10095
10096static int
10097argf_next_argv(VALUE argf)
10098{
10099 char *fn;
10100 rb_io_t *fptr;
10101 int stdout_binmode = 0;
10102 int fmode;
10103
10104 VALUE r_stdout = rb_ractor_stdout();
10105
10106 if (RB_TYPE_P(r_stdout, T_FILE)) {
10107 GetOpenFile(r_stdout, fptr);
10108 if (fptr->mode & FMODE_BINMODE)
10109 stdout_binmode = 1;
10110 }
10111
10112 if (ARGF.init_p == 0) {
10113 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10114 ARGF.next_p = 1;
10115 }
10116 else {
10117 ARGF.next_p = -1;
10118 }
10119 ARGF.init_p = 1;
10120 }
10121 else {
10122 if (NIL_P(ARGF.argv)) {
10123 ARGF.next_p = -1;
10124 }
10125 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10126 ARGF.next_p = 1;
10127 }
10128 }
10129
10130 if (ARGF.next_p == 1) {
10131 if (ARGF.init_p == 1) argf_close(argf);
10132 retry:
10133 if (RARRAY_LEN(ARGF.argv) > 0) {
10134 VALUE filename = rb_ary_shift(ARGF.argv);
10135 FilePathValue(filename);
10136 ARGF.filename = filename;
10137 filename = rb_str_encode_ospath(filename);
10138 fn = StringValueCStr(filename);
10139 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10140 ARGF.current_file = rb_stdin;
10141 if (ARGF.inplace) {
10142 rb_warn("Can't do inplace edit for stdio; skipping");
10143 goto retry;
10144 }
10145 }
10146 else {
10147 VALUE write_io = Qnil;
10148 int fr = rb_sysopen(filename, O_RDONLY, 0);
10149
10150 if (ARGF.inplace) {
10151 struct stat st;
10152#ifndef NO_SAFE_RENAME
10153 struct stat st2;
10154#endif
10155 VALUE str;
10156 int fw;
10157
10158 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10159 rb_io_close(r_stdout);
10160 }
10161 fstat(fr, &st);
10162 str = filename;
10163 if (!NIL_P(ARGF.inplace)) {
10164 VALUE suffix = ARGF.inplace;
10165 str = rb_str_dup(str);
10166 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10167 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10168 rb_enc_get(suffix), 0, Qnil))) {
10169 rb_str_append(str, suffix);
10170 }
10171#ifdef NO_SAFE_RENAME
10172 (void)close(fr);
10173 (void)unlink(RSTRING_PTR(str));
10174 if (rename(fn, RSTRING_PTR(str)) < 0) {
10175 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10176 filename, str, strerror(errno));
10177 goto retry;
10178 }
10179 fr = rb_sysopen(str, O_RDONLY, 0);
10180#else
10181 if (rename(fn, RSTRING_PTR(str)) < 0) {
10182 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10183 filename, str, strerror(errno));
10184 close(fr);
10185 goto retry;
10186 }
10187#endif
10188 }
10189 else {
10190#ifdef NO_SAFE_RENAME
10191 rb_fatal("Can't do inplace edit without backup");
10192#else
10193 if (unlink(fn) < 0) {
10194 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10195 filename, strerror(errno));
10196 close(fr);
10197 goto retry;
10198 }
10199#endif
10200 }
10201 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10202#ifndef NO_SAFE_RENAME
10203 fstat(fw, &st2);
10204#ifdef HAVE_FCHMOD
10205 fchmod(fw, st.st_mode);
10206#else
10207 chmod(fn, st.st_mode);
10208#endif
10209 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10210 int err;
10211#ifdef HAVE_FCHOWN
10212 err = fchown(fw, st.st_uid, st.st_gid);
10213#else
10214 err = chown(fn, st.st_uid, st.st_gid);
10215#endif
10216 if (err && getuid() == 0 && st2.st_uid == 0) {
10217 const char *wkfn = RSTRING_PTR(filename);
10218 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10219 filename, str, strerror(errno));
10220 (void)close(fr);
10221 (void)close(fw);
10222 (void)unlink(wkfn);
10223 goto retry;
10224 }
10225 }
10226#endif
10227 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10228 rb_ractor_stdout_set(write_io);
10229 if (stdout_binmode) rb_io_binmode(rb_stdout);
10230 }
10231 fmode = FMODE_READABLE;
10232 if (!ARGF.binmode) {
10233 fmode |= DEFAULT_TEXTMODE;
10234 }
10235 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10236 if (!NIL_P(write_io)) {
10237 rb_io_set_write_io(ARGF.current_file, write_io);
10238 }
10239 RB_GC_GUARD(filename);
10240 }
10241 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10242 GetOpenFile(ARGF.current_file, fptr);
10243 if (ARGF.encs.enc) {
10244 fptr->encs = ARGF.encs;
10245 clear_codeconv(fptr);
10246 }
10247 else {
10248 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10249 if (!ARGF.binmode) {
10251#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10252 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10253#endif
10254 }
10255 }
10256 ARGF.next_p = 0;
10257 }
10258 else {
10259 ARGF.next_p = 1;
10260 return FALSE;
10261 }
10262 }
10263 else if (ARGF.next_p == -1) {
10264 ARGF.current_file = rb_stdin;
10265 ARGF.filename = rb_str_new2("-");
10266 if (ARGF.inplace) {
10267 rb_warn("Can't do inplace edit for stdio");
10268 rb_ractor_stdout_set(orig_stdout);
10269 }
10270 }
10271 if (ARGF.init_p == -1) ARGF.init_p = 1;
10272 return TRUE;
10273}
10274
10275static VALUE
10276argf_getline(int argc, VALUE *argv, VALUE argf)
10277{
10278 VALUE line;
10279 long lineno = ARGF.lineno;
10280
10281 retry:
10282 if (!next_argv()) return Qnil;
10283 if (ARGF_GENERIC_INPUT_P()) {
10284 line = forward_current(idGets, argc, argv);
10285 }
10286 else {
10287 if (argc == 0 && rb_rs == rb_default_rs) {
10288 line = rb_io_gets(ARGF.current_file);
10289 }
10290 else {
10291 line = rb_io_getline(argc, argv, ARGF.current_file);
10292 }
10293 if (NIL_P(line) && ARGF.next_p != -1) {
10294 argf_close(argf);
10295 ARGF.next_p = 1;
10296 goto retry;
10297 }
10298 }
10299 if (!NIL_P(line)) {
10300 ARGF.lineno = ++lineno;
10301 ARGF.last_lineno = ARGF.lineno;
10302 }
10303 return line;
10304}
10305
10306static VALUE
10307argf_lineno_getter(ID id, VALUE *var)
10308{
10309 VALUE argf = *var;
10310 return INT2FIX(ARGF.last_lineno);
10311}
10312
10313static void
10314argf_lineno_setter(VALUE val, ID id, VALUE *var)
10315{
10316 VALUE argf = *var;
10317 int n = NUM2INT(val);
10318 ARGF.last_lineno = ARGF.lineno = n;
10319}
10320
10321void
10322rb_reset_argf_lineno(long n)
10323{
10324 ARGF.last_lineno = ARGF.lineno = n;
10325}
10326
10327static VALUE argf_gets(int, VALUE *, VALUE);
10328
10329/*
10330 * call-seq:
10331 * gets(sep=$/ [, getline_args]) -> string or nil
10332 * gets(limit [, getline_args]) -> string or nil
10333 * gets(sep, limit [, getline_args]) -> string or nil
10334 *
10335 * Returns (and assigns to <code>$_</code>) the next line from the list
10336 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10337 * no files are present on the command line. Returns +nil+ at end of
10338 * file. The optional argument specifies the record separator. The
10339 * separator is included with the contents of each record. A separator
10340 * of +nil+ reads the entire contents, and a zero-length separator
10341 * reads the input one paragraph at a time, where paragraphs are
10342 * divided by two consecutive newlines. If the first argument is an
10343 * integer, or optional second argument is given, the returning string
10344 * would not be longer than the given value in bytes. If multiple
10345 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10346 * the contents one file at a time.
10347 *
10348 * ARGV << "testfile"
10349 * print while gets
10350 *
10351 * <em>produces:</em>
10352 *
10353 * This is line one
10354 * This is line two
10355 * This is line three
10356 * And so on...
10357 *
10358 * The style of programming using <code>$_</code> as an implicit
10359 * parameter is gradually losing favor in the Ruby community.
10360 */
10361
10362static VALUE
10363rb_f_gets(int argc, VALUE *argv, VALUE recv)
10364{
10365 if (recv == argf) {
10366 return argf_gets(argc, argv, argf);
10367 }
10368 return forward(argf, idGets, argc, argv);
10369}
10370
10371/*
10372 * call-seq:
10373 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10374 * ARGF.gets(limit [, getline_args]) -> string or nil
10375 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10376 *
10377 * Returns the next line from the current file in ARGF.
10378 *
10379 * By default lines are assumed to be separated by <code>$/</code>;
10380 * to use a different character as a separator, supply it as a String
10381 * for the _sep_ argument.
10382 *
10383 * The optional _limit_ argument specifies how many characters of each line
10384 * to return. By default all characters are returned.
10385 *
10386 * See IO.readlines for details about getline_args.
10387 *
10388 */
10389static VALUE
10390argf_gets(int argc, VALUE *argv, VALUE argf)
10391{
10392 VALUE line;
10393
10394 line = argf_getline(argc, argv, argf);
10395 rb_lastline_set(line);
10396
10397 return line;
10398}
10399
10400VALUE
10402{
10403 VALUE line;
10404
10405 if (rb_rs != rb_default_rs) {
10406 return rb_f_gets(0, 0, argf);
10407 }
10408
10409 retry:
10410 if (!next_argv()) return Qnil;
10411 line = rb_io_gets(ARGF.current_file);
10412 if (NIL_P(line) && ARGF.next_p != -1) {
10413 rb_io_close(ARGF.current_file);
10414 ARGF.next_p = 1;
10415 goto retry;
10416 }
10417 rb_lastline_set(line);
10418 if (!NIL_P(line)) {
10419 ARGF.lineno++;
10420 ARGF.last_lineno = ARGF.lineno;
10421 }
10422
10423 return line;
10424}
10425
10426static VALUE argf_readline(int, VALUE *, VALUE);
10427
10428/*
10429 * call-seq:
10430 * readline(sep = $/, chomp: false) -> string
10431 * readline(limit, chomp: false) -> string
10432 * readline(sep, limit, chomp: false) -> string
10433 *
10434 * Equivalent to method Kernel#gets, except that it raises an exception
10435 * if called at end-of-stream:
10436 *
10437 * $ cat t.txt | ruby -e "p readlines; readline"
10438 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10439 * in `readline': end of file reached (EOFError)
10440 *
10441 * Optional keyword argument +chomp+ specifies whether line separators
10442 * are to be omitted.
10443 */
10444
10445static VALUE
10446rb_f_readline(int argc, VALUE *argv, VALUE recv)
10447{
10448 if (recv == argf) {
10449 return argf_readline(argc, argv, argf);
10450 }
10451 return forward(argf, rb_intern("readline"), argc, argv);
10452}
10453
10454
10455/*
10456 * call-seq:
10457 * ARGF.readline(sep=$/) -> string
10458 * ARGF.readline(limit) -> string
10459 * ARGF.readline(sep, limit) -> string
10460 *
10461 * Returns the next line from the current file in ARGF.
10462 *
10463 * By default lines are assumed to be separated by <code>$/</code>;
10464 * to use a different character as a separator, supply it as a String
10465 * for the _sep_ argument.
10466 *
10467 * The optional _limit_ argument specifies how many characters of each line
10468 * to return. By default all characters are returned.
10469 *
10470 * An EOFError is raised at the end of the file.
10471 */
10472static VALUE
10473argf_readline(int argc, VALUE *argv, VALUE argf)
10474{
10475 VALUE line;
10476
10477 if (!next_argv()) rb_eof_error();
10478 ARGF_FORWARD(argc, argv);
10479 line = argf_gets(argc, argv, argf);
10480 if (NIL_P(line)) {
10481 rb_eof_error();
10482 }
10483
10484 return line;
10485}
10486
10487static VALUE argf_readlines(int, VALUE *, VALUE);
10488
10489/*
10490 * call-seq:
10491 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10492 * readlines(limit, chomp: false, **enc_opts) -> array
10493 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10494 *
10495 * Returns an array containing the lines returned by calling
10496 * Kernel#gets until the end-of-stream is reached;
10497 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10498 *
10499 * With only string argument +sep+ given,
10500 * returns the remaining lines as determined by line separator +sep+,
10501 * or +nil+ if none;
10502 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10503 *
10504 * # Default separator.
10505 * $ cat t.txt | ruby -e "p readlines"
10506 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10507 *
10508 * # Specified separator.
10509 * $ cat t.txt | ruby -e "p readlines 'li'"
10510 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10511 *
10512 * # Get-all separator.
10513 * $ cat t.txt | ruby -e "p readlines nil"
10514 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10515 *
10516 * # Get-paragraph separator.
10517 * $ cat t.txt | ruby -e "p readlines ''"
10518 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10519 *
10520 * With only integer argument +limit+ given,
10521 * limits the number of bytes in the line;
10522 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10523 *
10524 * $cat t.txt | ruby -e "p readlines 10"
10525 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10526 *
10527 * $cat t.txt | ruby -e "p readlines 11"
10528 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10529 *
10530 * $cat t.txt | ruby -e "p readlines 12"
10531 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10532 *
10533 * With arguments +sep+ and +limit+ given,
10534 * combines the two behaviors
10535 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10536 *
10537 * Optional keyword argument +chomp+ specifies whether line separators
10538 * are to be omitted:
10539 *
10540 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10541 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10542 *
10543 * Optional keyword arguments +enc_opts+ specify encoding options;
10544 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10545 *
10546 */
10547
10548static VALUE
10549rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10550{
10551 if (recv == argf) {
10552 return argf_readlines(argc, argv, argf);
10553 }
10554 return forward(argf, rb_intern("readlines"), argc, argv);
10555}
10556
10557/*
10558 * call-seq:
10559 * ARGF.readlines(sep = $/, chomp: false) -> array
10560 * ARGF.readlines(limit, chomp: false) -> array
10561 * ARGF.readlines(sep, limit, chomp: false) -> array
10562 *
10563 * ARGF.to_a(sep = $/, chomp: false) -> array
10564 * ARGF.to_a(limit, chomp: false) -> array
10565 * ARGF.to_a(sep, limit, chomp: false) -> array
10566 *
10567 * Reads each file in ARGF in its entirety, returning an Array containing
10568 * lines from the files. Lines are assumed to be separated by _sep_.
10569 *
10570 * lines = ARGF.readlines
10571 * lines[0] #=> "This is line one\n"
10572 *
10573 * See +IO.readlines+ for a full description of all options.
10574 */
10575static VALUE
10576argf_readlines(int argc, VALUE *argv, VALUE argf)
10577{
10578 long lineno = ARGF.lineno;
10579 VALUE lines, ary;
10580
10581 ary = rb_ary_new();
10582 while (next_argv()) {
10583 if (ARGF_GENERIC_INPUT_P()) {
10584 lines = forward_current(rb_intern("readlines"), argc, argv);
10585 }
10586 else {
10587 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10588 argf_close(argf);
10589 }
10590 ARGF.next_p = 1;
10591 rb_ary_concat(ary, lines);
10592 ARGF.lineno = lineno + RARRAY_LEN(ary);
10593 ARGF.last_lineno = ARGF.lineno;
10594 }
10595 ARGF.init_p = 0;
10596 return ary;
10597}
10598
10599/*
10600 * call-seq:
10601 * `command` -> string
10602 *
10603 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10604 * sets global variable <tt>$?</tt> to the process status.
10605 *
10606 * This method has potential security vulnerabilities if called with untrusted input;
10607 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10608 *
10609 * Examples:
10610 *
10611 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10612 * $ `echo oops && exit 99` # => "oops\n"
10613 * $ $? # => #<Process::Status: pid 17088 exit 99>
10614 * $ $?.status # => 99>
10615 *
10616 * The built-in syntax <tt>%x{...}</tt> uses this method.
10617 *
10618 */
10619
10620static VALUE
10621rb_f_backquote(VALUE obj, VALUE str)
10622{
10623 VALUE port;
10624 VALUE result;
10625 rb_io_t *fptr;
10626
10627 StringValue(str);
10628 rb_last_status_clear();
10629 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10630 if (NIL_P(port)) return rb_str_new(0,0);
10631
10632 GetOpenFile(port, fptr);
10633 result = read_all(fptr, remain_size(fptr), Qnil);
10634 rb_io_close(port);
10635 rb_io_fptr_cleanup_all(fptr);
10636 RB_GC_GUARD(port);
10637
10638 return result;
10639}
10640
10641#ifdef HAVE_SYS_SELECT_H
10642#include <sys/select.h>
10643#endif
10644
10645static VALUE
10646select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10647{
10648 VALUE res, list;
10649 rb_fdset_t *rp, *wp, *ep;
10650 rb_io_t *fptr;
10651 long i;
10652 int max = 0, n;
10653 int pending = 0;
10654 struct timeval timerec;
10655
10656 if (!NIL_P(read)) {
10657 Check_Type(read, T_ARRAY);
10658 for (i=0; i<RARRAY_LEN(read); i++) {
10659 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10660 rb_fd_set(fptr->fd, &fds[0]);
10661 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10662 pending++;
10663 rb_fd_set(fptr->fd, &fds[3]);
10664 }
10665 if (max < fptr->fd) max = fptr->fd;
10666 }
10667 if (pending) { /* no blocking if there's buffered data */
10668 timerec.tv_sec = timerec.tv_usec = 0;
10669 tp = &timerec;
10670 }
10671 rp = &fds[0];
10672 }
10673 else
10674 rp = 0;
10675
10676 if (!NIL_P(write)) {
10677 Check_Type(write, T_ARRAY);
10678 for (i=0; i<RARRAY_LEN(write); i++) {
10679 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10680 GetOpenFile(write_io, fptr);
10681 rb_fd_set(fptr->fd, &fds[1]);
10682 if (max < fptr->fd) max = fptr->fd;
10683 }
10684 wp = &fds[1];
10685 }
10686 else
10687 wp = 0;
10688
10689 if (!NIL_P(except)) {
10690 Check_Type(except, T_ARRAY);
10691 for (i=0; i<RARRAY_LEN(except); i++) {
10692 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10693 VALUE write_io = GetWriteIO(io);
10694 GetOpenFile(io, fptr);
10695 rb_fd_set(fptr->fd, &fds[2]);
10696 if (max < fptr->fd) max = fptr->fd;
10697 if (io != write_io) {
10698 GetOpenFile(write_io, fptr);
10699 rb_fd_set(fptr->fd, &fds[2]);
10700 if (max < fptr->fd) max = fptr->fd;
10701 }
10702 }
10703 ep = &fds[2];
10704 }
10705 else {
10706 ep = 0;
10707 }
10708
10709 max++;
10710
10711 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10712 if (n < 0) {
10713 rb_sys_fail(0);
10714 }
10715 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10716
10717 res = rb_ary_new2(3);
10718 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10719 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10720 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10721
10722 if (rp) {
10723 list = RARRAY_AREF(res, 0);
10724 for (i=0; i< RARRAY_LEN(read); i++) {
10725 VALUE obj = rb_ary_entry(read, i);
10726 VALUE io = rb_io_get_io(obj);
10727 GetOpenFile(io, fptr);
10728 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10729 rb_fd_isset(fptr->fd, &fds[3])) {
10730 rb_ary_push(list, obj);
10731 }
10732 }
10733 }
10734
10735 if (wp) {
10736 list = RARRAY_AREF(res, 1);
10737 for (i=0; i< RARRAY_LEN(write); i++) {
10738 VALUE obj = rb_ary_entry(write, i);
10739 VALUE io = rb_io_get_io(obj);
10740 VALUE write_io = GetWriteIO(io);
10741 GetOpenFile(write_io, fptr);
10742 if (rb_fd_isset(fptr->fd, &fds[1])) {
10743 rb_ary_push(list, obj);
10744 }
10745 }
10746 }
10747
10748 if (ep) {
10749 list = RARRAY_AREF(res, 2);
10750 for (i=0; i< RARRAY_LEN(except); i++) {
10751 VALUE obj = rb_ary_entry(except, i);
10752 VALUE io = rb_io_get_io(obj);
10753 VALUE write_io = GetWriteIO(io);
10754 GetOpenFile(io, fptr);
10755 if (rb_fd_isset(fptr->fd, &fds[2])) {
10756 rb_ary_push(list, obj);
10757 }
10758 else if (io != write_io) {
10759 GetOpenFile(write_io, fptr);
10760 if (rb_fd_isset(fptr->fd, &fds[2])) {
10761 rb_ary_push(list, obj);
10762 }
10763 }
10764 }
10765 }
10766
10767 return res; /* returns an empty array on interrupt */
10768}
10769
10771 VALUE read, write, except;
10772 struct timeval *timeout;
10773 rb_fdset_t fdsets[4];
10774};
10775
10776static VALUE
10777select_call(VALUE arg)
10778{
10779 struct select_args *p = (struct select_args *)arg;
10780
10781 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10782}
10783
10784static VALUE
10785select_end(VALUE arg)
10786{
10787 struct select_args *p = (struct select_args *)arg;
10788 int i;
10789
10790 for (i = 0; i < numberof(p->fdsets); ++i)
10791 rb_fd_term(&p->fdsets[i]);
10792 return Qnil;
10793}
10794
10795static VALUE sym_normal, sym_sequential, sym_random,
10796 sym_willneed, sym_dontneed, sym_noreuse;
10797
10798#ifdef HAVE_POSIX_FADVISE
10799struct io_advise_struct {
10800 int fd;
10801 int advice;
10802 rb_off_t offset;
10803 rb_off_t len;
10804};
10805
10806static VALUE
10807io_advise_internal(void *arg)
10808{
10809 struct io_advise_struct *ptr = arg;
10810 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10811}
10812
10813static VALUE
10814io_advise_sym_to_const(VALUE sym)
10815{
10816#ifdef POSIX_FADV_NORMAL
10817 if (sym == sym_normal)
10818 return INT2NUM(POSIX_FADV_NORMAL);
10819#endif
10820
10821#ifdef POSIX_FADV_RANDOM
10822 if (sym == sym_random)
10823 return INT2NUM(POSIX_FADV_RANDOM);
10824#endif
10825
10826#ifdef POSIX_FADV_SEQUENTIAL
10827 if (sym == sym_sequential)
10828 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10829#endif
10830
10831#ifdef POSIX_FADV_WILLNEED
10832 if (sym == sym_willneed)
10833 return INT2NUM(POSIX_FADV_WILLNEED);
10834#endif
10835
10836#ifdef POSIX_FADV_DONTNEED
10837 if (sym == sym_dontneed)
10838 return INT2NUM(POSIX_FADV_DONTNEED);
10839#endif
10840
10841#ifdef POSIX_FADV_NOREUSE
10842 if (sym == sym_noreuse)
10843 return INT2NUM(POSIX_FADV_NOREUSE);
10844#endif
10845
10846 return Qnil;
10847}
10848
10849static VALUE
10850do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10851{
10852 int rv;
10853 struct io_advise_struct ias;
10854 VALUE num_adv;
10855
10856 num_adv = io_advise_sym_to_const(advice);
10857
10858 /*
10859 * The platform doesn't support this hint. We don't raise exception, instead
10860 * silently ignore it. Because IO::advise is only hint.
10861 */
10862 if (NIL_P(num_adv))
10863 return Qnil;
10864
10865 ias.fd = fptr->fd;
10866 ias.advice = NUM2INT(num_adv);
10867 ias.offset = offset;
10868 ias.len = len;
10869
10870 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10871 if (rv && rv != ENOSYS) {
10872 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10873 it returns the error code. */
10874 VALUE message = rb_sprintf("%"PRIsVALUE" "
10875 "(%"PRI_OFFT_PREFIX"d, "
10876 "%"PRI_OFFT_PREFIX"d, "
10877 "%"PRIsVALUE")",
10878 fptr->pathv, offset, len, advice);
10879 rb_syserr_fail_str(rv, message);
10880 }
10881
10882 return Qnil;
10883}
10884
10885#endif /* HAVE_POSIX_FADVISE */
10886
10887static void
10888advice_arg_check(VALUE advice)
10889{
10890 if (!SYMBOL_P(advice))
10891 rb_raise(rb_eTypeError, "advice must be a Symbol");
10892
10893 if (advice != sym_normal &&
10894 advice != sym_sequential &&
10895 advice != sym_random &&
10896 advice != sym_willneed &&
10897 advice != sym_dontneed &&
10898 advice != sym_noreuse) {
10899 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10900 }
10901}
10902
10903/*
10904 * call-seq:
10905 * advise(advice, offset = 0, len = 0) -> nil
10906 *
10907 * Invokes Posix system call
10908 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10909 * which announces an intention to access data from the current file
10910 * in a particular manner.
10911 *
10912 * The arguments and results are platform-dependent.
10913 *
10914 * The relevant data is specified by:
10915 *
10916 * - +offset+: The offset of the first byte of data.
10917 * - +len+: The number of bytes to be accessed;
10918 * if +len+ is zero, or is larger than the number of bytes remaining,
10919 * all remaining bytes will be accessed.
10920 *
10921 * Argument +advice+ is one of the following symbols:
10922 *
10923 * - +:normal+: The application has no advice to give
10924 * about its access pattern for the specified data.
10925 * If no advice is given for an open file, this is the default assumption.
10926 * - +:sequential+: The application expects to access the specified data sequentially
10927 * (with lower offsets read before higher ones).
10928 * - +:random+: The specified data will be accessed in random order.
10929 * - +:noreuse+: The specified data will be accessed only once.
10930 * - +:willneed+: The specified data will be accessed in the near future.
10931 * - +:dontneed+: The specified data will not be accessed in the near future.
10932 *
10933 * Not implemented on all platforms.
10934 *
10935 */
10936static VALUE
10937rb_io_advise(int argc, VALUE *argv, VALUE io)
10938{
10939 VALUE advice, offset, len;
10940 rb_off_t off, l;
10941 rb_io_t *fptr;
10942
10943 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10944 advice_arg_check(advice);
10945
10946 io = GetWriteIO(io);
10947 GetOpenFile(io, fptr);
10948
10949 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10950 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10951
10952#ifdef HAVE_POSIX_FADVISE
10953 return do_io_advise(fptr, advice, off, l);
10954#else
10955 ((void)off, (void)l); /* Ignore all hint */
10956 return Qnil;
10957#endif
10958}
10959
10960/*
10961 * call-seq:
10962 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10963 *
10964 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10965 * which monitors multiple file descriptors,
10966 * waiting until one or more of the file descriptors
10967 * becomes ready for some class of I/O operation.
10968 *
10969 * Not implemented on all platforms.
10970 *
10971 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10972 * is an array of IO objects.
10973 *
10974 * Argument +timeout+ is a numeric value (such as integer or float) timeout
10975 * interval in seconds.
10976 *
10977 * The method monitors the \IO objects given in all three arrays,
10978 * waiting for some to be ready;
10979 * returns a 3-element array whose elements are:
10980 *
10981 * - An array of the objects in +read_ios+ that are ready for reading.
10982 * - An array of the objects in +write_ios+ that are ready for writing.
10983 * - An array of the objects in +error_ios+ have pending exceptions.
10984 *
10985 * If no object becomes ready within the given +timeout+, +nil+ is returned.
10986 *
10987 * \IO.select peeks the buffer of \IO objects for testing readability.
10988 * If the \IO buffer is not empty, \IO.select immediately notifies
10989 * readability. This "peek" only happens for \IO objects. It does not
10990 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10991 *
10992 * The best way to use \IO.select is invoking it after non-blocking
10993 * methods such as #read_nonblock, #write_nonblock, etc. The methods
10994 * raise an exception which is extended by IO::WaitReadable or
10995 * IO::WaitWritable. The modules notify how the caller should wait
10996 * with \IO.select. If IO::WaitReadable is raised, the caller should
10997 * wait for reading. If IO::WaitWritable is raised, the caller should
10998 * wait for writing.
10999 *
11000 * So, blocking read (#readpartial) can be emulated using
11001 * #read_nonblock and \IO.select as follows:
11002 *
11003 * begin
11004 * result = io_like.read_nonblock(maxlen)
11005 * rescue IO::WaitReadable
11006 * IO.select([io_like])
11007 * retry
11008 * rescue IO::WaitWritable
11009 * IO.select(nil, [io_like])
11010 * retry
11011 * end
11012 *
11013 * Especially, the combination of non-blocking methods and \IO.select is
11014 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11015 * has #to_io method to return underlying IO object. IO.select calls
11016 * #to_io to obtain the file descriptor to wait.
11017 *
11018 * This means that readability notified by \IO.select doesn't mean
11019 * readability from OpenSSL::SSL::SSLSocket object.
11020 *
11021 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11022 * some data. \IO.select doesn't see the buffer. So \IO.select can
11023 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11024 *
11025 * However, several more complicated situations exist.
11026 *
11027 * SSL is a protocol which is sequence of records.
11028 * The record consists of multiple bytes.
11029 * So, the remote side of SSL sends a partial record, IO.select
11030 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11031 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11032 *
11033 * Also, the remote side can request SSL renegotiation which forces
11034 * the local SSL engine to write some data.
11035 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11036 * system call and it can block.
11037 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11038 * IO::WaitWritable instead of blocking.
11039 * So, the caller should wait for ready for writability as above
11040 * example.
11041 *
11042 * The combination of non-blocking methods and \IO.select is also useful
11043 * for streams such as tty, pipe socket socket when multiple processes
11044 * read from a stream.
11045 *
11046 * Finally, Linux kernel developers don't guarantee that
11047 * readability of select(2) means readability of following read(2) even
11048 * for a single process;
11049 * see {select(2)}[https://linux.die.net/man/2/select]
11050 *
11051 * Invoking \IO.select before IO#readpartial works well as usual.
11052 * However it is not the best way to use \IO.select.
11053 *
11054 * The writability notified by select(2) doesn't show
11055 * how many bytes are writable.
11056 * IO#write method blocks until given whole string is written.
11057 * So, <tt>IO#write(two or more bytes)</tt> can block after
11058 * writability is notified by \IO.select. IO#write_nonblock is required
11059 * to avoid the blocking.
11060 *
11061 * Blocking write (#write) can be emulated using #write_nonblock and
11062 * IO.select as follows: IO::WaitReadable should also be rescued for
11063 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11064 *
11065 * while 0 < string.bytesize
11066 * begin
11067 * written = io_like.write_nonblock(string)
11068 * rescue IO::WaitReadable
11069 * IO.select([io_like])
11070 * retry
11071 * rescue IO::WaitWritable
11072 * IO.select(nil, [io_like])
11073 * retry
11074 * end
11075 * string = string.byteslice(written..-1)
11076 * end
11077 *
11078 * Example:
11079 *
11080 * rp, wp = IO.pipe
11081 * mesg = "ping "
11082 * 100.times {
11083 * # IO.select follows IO#read. Not the best way to use IO.select.
11084 * rs, ws, = IO.select([rp], [wp])
11085 * if r = rs[0]
11086 * ret = r.read(5)
11087 * print ret
11088 * case ret
11089 * when /ping/
11090 * mesg = "pong\n"
11091 * when /pong/
11092 * mesg = "ping "
11093 * end
11094 * end
11095 * if w = ws[0]
11096 * w.write(mesg)
11097 * end
11098 * }
11099 *
11100 * Output:
11101 *
11102 * ping pong
11103 * ping pong
11104 * ping pong
11105 * (snipped)
11106 * ping
11107 *
11108 */
11109
11110static VALUE
11111rb_f_select(int argc, VALUE *argv, VALUE obj)
11112{
11113 VALUE scheduler = rb_fiber_scheduler_current();
11114 if (scheduler != Qnil) {
11115 // It's optionally supported.
11116 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11117 if (!UNDEF_P(result)) return result;
11118 }
11119
11120 VALUE timeout;
11121 struct select_args args;
11122 struct timeval timerec;
11123 int i;
11124
11125 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11126 if (NIL_P(timeout)) {
11127 args.timeout = 0;
11128 }
11129 else {
11130 timerec = rb_time_interval(timeout);
11131 args.timeout = &timerec;
11132 }
11133
11134 for (i = 0; i < numberof(args.fdsets); ++i)
11135 rb_fd_init(&args.fdsets[i]);
11136
11137 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11138}
11139
11140#ifdef IOCTL_REQ_TYPE
11141 typedef IOCTL_REQ_TYPE ioctl_req_t;
11142#else
11143 typedef int ioctl_req_t;
11144# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11145#endif
11146
11147#ifdef HAVE_IOCTL
11148struct ioctl_arg {
11149 int fd;
11150 ioctl_req_t cmd;
11151 long narg;
11152};
11153
11154static VALUE
11155nogvl_ioctl(void *ptr)
11156{
11157 struct ioctl_arg *arg = ptr;
11158
11159 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11160}
11161
11162static int
11163do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11164{
11165 int retval;
11166 struct ioctl_arg arg;
11167
11168 arg.fd = io->fd;
11169 arg.cmd = cmd;
11170 arg.narg = narg;
11171
11172 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11173
11174 return retval;
11175}
11176#endif
11177
11178#define DEFAULT_IOCTL_NARG_LEN (256)
11179
11180#if defined(__linux__) && defined(_IOC_SIZE)
11181static long
11182linux_iocparm_len(ioctl_req_t cmd)
11183{
11184 long len;
11185
11186 if ((cmd & 0xFFFF0000) == 0) {
11187 /* legacy and unstructured ioctl number. */
11188 return DEFAULT_IOCTL_NARG_LEN;
11189 }
11190
11191 len = _IOC_SIZE(cmd);
11192
11193 /* paranoia check for silly drivers which don't keep ioctl convention */
11194 if (len < DEFAULT_IOCTL_NARG_LEN)
11195 len = DEFAULT_IOCTL_NARG_LEN;
11196
11197 return len;
11198}
11199#endif
11200
11201#ifdef HAVE_IOCTL
11202static long
11203ioctl_narg_len(ioctl_req_t cmd)
11204{
11205 long len;
11206
11207#ifdef IOCPARM_MASK
11208#ifndef IOCPARM_LEN
11209#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11210#endif
11211#endif
11212#ifdef IOCPARM_LEN
11213 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11214#elif defined(__linux__) && defined(_IOC_SIZE)
11215 len = linux_iocparm_len(cmd);
11216#else
11217 /* otherwise guess at what's safe */
11218 len = DEFAULT_IOCTL_NARG_LEN;
11219#endif
11220
11221 return len;
11222}
11223#endif
11224
11225#ifdef HAVE_FCNTL
11226#ifdef __linux__
11227typedef long fcntl_arg_t;
11228#else
11229/* posix */
11230typedef int fcntl_arg_t;
11231#endif
11232
11233static long
11234fcntl_narg_len(ioctl_req_t cmd)
11235{
11236 long len;
11237
11238 switch (cmd) {
11239#ifdef F_DUPFD
11240 case F_DUPFD:
11241 len = sizeof(fcntl_arg_t);
11242 break;
11243#endif
11244#ifdef F_DUP2FD /* bsd specific */
11245 case F_DUP2FD:
11246 len = sizeof(int);
11247 break;
11248#endif
11249#ifdef F_DUPFD_CLOEXEC /* linux specific */
11250 case F_DUPFD_CLOEXEC:
11251 len = sizeof(fcntl_arg_t);
11252 break;
11253#endif
11254#ifdef F_GETFD
11255 case F_GETFD:
11256 len = 1;
11257 break;
11258#endif
11259#ifdef F_SETFD
11260 case F_SETFD:
11261 len = sizeof(fcntl_arg_t);
11262 break;
11263#endif
11264#ifdef F_GETFL
11265 case F_GETFL:
11266 len = 1;
11267 break;
11268#endif
11269#ifdef F_SETFL
11270 case F_SETFL:
11271 len = sizeof(fcntl_arg_t);
11272 break;
11273#endif
11274#ifdef F_GETOWN
11275 case F_GETOWN:
11276 len = 1;
11277 break;
11278#endif
11279#ifdef F_SETOWN
11280 case F_SETOWN:
11281 len = sizeof(fcntl_arg_t);
11282 break;
11283#endif
11284#ifdef F_GETOWN_EX /* linux specific */
11285 case F_GETOWN_EX:
11286 len = sizeof(struct f_owner_ex);
11287 break;
11288#endif
11289#ifdef F_SETOWN_EX /* linux specific */
11290 case F_SETOWN_EX:
11291 len = sizeof(struct f_owner_ex);
11292 break;
11293#endif
11294#ifdef F_GETLK
11295 case F_GETLK:
11296 len = sizeof(struct flock);
11297 break;
11298#endif
11299#ifdef F_SETLK
11300 case F_SETLK:
11301 len = sizeof(struct flock);
11302 break;
11303#endif
11304#ifdef F_SETLKW
11305 case F_SETLKW:
11306 len = sizeof(struct flock);
11307 break;
11308#endif
11309#ifdef F_READAHEAD /* bsd specific */
11310 case F_READAHEAD:
11311 len = sizeof(int);
11312 break;
11313#endif
11314#ifdef F_RDAHEAD /* Darwin specific */
11315 case F_RDAHEAD:
11316 len = sizeof(int);
11317 break;
11318#endif
11319#ifdef F_GETSIG /* linux specific */
11320 case F_GETSIG:
11321 len = 1;
11322 break;
11323#endif
11324#ifdef F_SETSIG /* linux specific */
11325 case F_SETSIG:
11326 len = sizeof(fcntl_arg_t);
11327 break;
11328#endif
11329#ifdef F_GETLEASE /* linux specific */
11330 case F_GETLEASE:
11331 len = 1;
11332 break;
11333#endif
11334#ifdef F_SETLEASE /* linux specific */
11335 case F_SETLEASE:
11336 len = sizeof(fcntl_arg_t);
11337 break;
11338#endif
11339#ifdef F_NOTIFY /* linux specific */
11340 case F_NOTIFY:
11341 len = sizeof(fcntl_arg_t);
11342 break;
11343#endif
11344
11345 default:
11346 len = 256;
11347 break;
11348 }
11349
11350 return len;
11351}
11352#else /* HAVE_FCNTL */
11353static long
11354fcntl_narg_len(ioctl_req_t cmd)
11355{
11356 return 0;
11357}
11358#endif /* HAVE_FCNTL */
11359
11360#define NARG_SENTINEL 17
11361
11362static long
11363setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11364{
11365 long narg = 0;
11366 VALUE arg = *argp;
11367
11368 if (!RTEST(arg)) {
11369 narg = 0;
11370 }
11371 else if (FIXNUM_P(arg)) {
11372 narg = FIX2LONG(arg);
11373 }
11374 else if (arg == Qtrue) {
11375 narg = 1;
11376 }
11377 else {
11378 VALUE tmp = rb_check_string_type(arg);
11379
11380 if (NIL_P(tmp)) {
11381 narg = NUM2LONG(arg);
11382 }
11383 else {
11384 char *ptr;
11385 long len, slen;
11386
11387 *argp = arg = tmp;
11388 len = narg_len(cmd);
11389 rb_str_modify(arg);
11390
11391 slen = RSTRING_LEN(arg);
11392 /* expand for data + sentinel. */
11393 if (slen < len+1) {
11394 rb_str_resize(arg, len+1);
11395 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11396 slen = len+1;
11397 }
11398 /* a little sanity check here */
11399 ptr = RSTRING_PTR(arg);
11400 ptr[slen - 1] = NARG_SENTINEL;
11401 narg = (long)(SIGNED_VALUE)ptr;
11402 }
11403 }
11404
11405 return narg;
11406}
11407
11408static VALUE
11409finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11410{
11411 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11412 if (RB_TYPE_P(arg, T_STRING)) {
11413 char *ptr;
11414 long slen;
11415 RSTRING_GETMEM(arg, ptr, slen);
11416 if (ptr[slen-1] != NARG_SENTINEL)
11417 rb_raise(rb_eArgError, "return value overflowed string");
11418 ptr[slen-1] = '\0';
11419 }
11420
11421 return INT2NUM(retval);
11422}
11423
11424#ifdef HAVE_IOCTL
11425static VALUE
11426rb_ioctl(VALUE io, VALUE req, VALUE arg)
11427{
11428 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11429 rb_io_t *fptr;
11430 long narg;
11431 int retval;
11432
11433 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11434 GetOpenFile(io, fptr);
11435 retval = do_ioctl(fptr, cmd, narg);
11436 return finish_narg(retval, arg, fptr);
11437}
11438
11439/*
11440 * call-seq:
11441 * ioctl(integer_cmd, argument) -> integer
11442 *
11443 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11444 * which issues a low-level command to an I/O device.
11445 *
11446 * Issues a low-level command to an I/O device.
11447 * The arguments and returned value are platform-dependent.
11448 * The effect of the call is platform-dependent.
11449 *
11450 * If argument +argument+ is an integer, it is passed directly;
11451 * if it is a string, it is interpreted as a binary sequence of bytes.
11452 *
11453 * Not implemented on all platforms.
11454 *
11455 */
11456
11457static VALUE
11458rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11459{
11460 VALUE req, arg;
11461
11462 rb_scan_args(argc, argv, "11", &req, &arg);
11463 return rb_ioctl(io, req, arg);
11464}
11465#else
11466#define rb_io_ioctl rb_f_notimplement
11467#endif
11468
11469#ifdef HAVE_FCNTL
11470struct fcntl_arg {
11471 int fd;
11472 int cmd;
11473 long narg;
11474};
11475
11476static VALUE
11477nogvl_fcntl(void *ptr)
11478{
11479 struct fcntl_arg *arg = ptr;
11480
11481#if defined(F_DUPFD)
11482 if (arg->cmd == F_DUPFD)
11483 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11484#endif
11485 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11486}
11487
11488static int
11489do_fcntl(struct rb_io *io, int cmd, long narg)
11490{
11491 int retval;
11492 struct fcntl_arg arg;
11493
11494 arg.fd = io->fd;
11495 arg.cmd = cmd;
11496 arg.narg = narg;
11497
11498 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11499 if (retval != -1) {
11500 switch (cmd) {
11501#if defined(F_DUPFD)
11502 case F_DUPFD:
11503#endif
11504#if defined(F_DUPFD_CLOEXEC)
11505 case F_DUPFD_CLOEXEC:
11506#endif
11507 rb_update_max_fd(retval);
11508 }
11509 }
11510
11511 return retval;
11512}
11513
11514static VALUE
11515rb_fcntl(VALUE io, VALUE req, VALUE arg)
11516{
11517 int cmd = NUM2INT(req);
11518 rb_io_t *fptr;
11519 long narg;
11520 int retval;
11521
11522 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11523 GetOpenFile(io, fptr);
11524 retval = do_fcntl(fptr, cmd, narg);
11525 return finish_narg(retval, arg, fptr);
11526}
11527
11528/*
11529 * call-seq:
11530 * fcntl(integer_cmd, argument) -> integer
11531 *
11532 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11533 * which provides a mechanism for issuing low-level commands to control or query
11534 * a file-oriented I/O stream. Arguments and results are platform
11535 * dependent.
11536 *
11537 * If +argument+ is a number, its value is passed directly;
11538 * if it is a string, it is interpreted as a binary sequence of bytes.
11539 * (Array#pack might be a useful way to build this string.)
11540 *
11541 * Not implemented on all platforms.
11542 *
11543 */
11544
11545static VALUE
11546rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11547{
11548 VALUE req, arg;
11549
11550 rb_scan_args(argc, argv, "11", &req, &arg);
11551 return rb_fcntl(io, req, arg);
11552}
11553#else
11554#define rb_io_fcntl rb_f_notimplement
11555#endif
11556
11557#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11558/*
11559 * call-seq:
11560 * syscall(integer_callno, *arguments) -> integer
11561 *
11562 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11563 * which calls a specified function.
11564 *
11565 * Calls the operating system function identified by +integer_callno+;
11566 * returns the result of the function or raises SystemCallError if it failed.
11567 * The effect of the call is platform-dependent.
11568 * The arguments and returned value are platform-dependent.
11569 *
11570 * For each of +arguments+: if it is an integer, it is passed directly;
11571 * if it is a string, it is interpreted as a binary sequence of bytes.
11572 * There may be as many as nine such arguments.
11573 *
11574 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11575 * are platform-dependent.
11576 *
11577 * Note: Method +syscall+ is essentially unsafe and unportable.
11578 * The DL (Fiddle) library is preferred for safer and a bit
11579 * more portable programming.
11580 *
11581 * Not implemented on all platforms.
11582 *
11583 */
11584
11585static VALUE
11586rb_f_syscall(int argc, VALUE *argv, VALUE _)
11587{
11588 VALUE arg[8];
11589#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11590# define SYSCALL __syscall
11591# define NUM2SYSCALLID(x) NUM2LONG(x)
11592# define RETVAL2NUM(x) LONG2NUM(x)
11593# if SIZEOF_LONG == 8
11594 long num, retval = -1;
11595# elif SIZEOF_LONG_LONG == 8
11596 long long num, retval = -1;
11597# else
11598# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11599# endif
11600#elif defined(__linux__)
11601# define SYSCALL syscall
11602# define NUM2SYSCALLID(x) NUM2LONG(x)
11603# define RETVAL2NUM(x) LONG2NUM(x)
11604 /*
11605 * Linux man page says, syscall(2) function prototype is below.
11606 *
11607 * int syscall(int number, ...);
11608 *
11609 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11610 */
11611 long num, retval = -1;
11612#else
11613# define SYSCALL syscall
11614# define NUM2SYSCALLID(x) NUM2INT(x)
11615# define RETVAL2NUM(x) INT2NUM(x)
11616 int num, retval = -1;
11617#endif
11618 int i;
11619
11620 if (RTEST(ruby_verbose)) {
11622 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11623 }
11624
11625 if (argc == 0)
11626 rb_raise(rb_eArgError, "too few arguments for syscall");
11627 if (argc > numberof(arg))
11628 rb_raise(rb_eArgError, "too many arguments for syscall");
11629 num = NUM2SYSCALLID(argv[0]); ++argv;
11630 for (i = argc - 1; i--; ) {
11631 VALUE v = rb_check_string_type(argv[i]);
11632
11633 if (!NIL_P(v)) {
11634 StringValue(v);
11635 rb_str_modify(v);
11636 arg[i] = (VALUE)StringValueCStr(v);
11637 }
11638 else {
11639 arg[i] = (VALUE)NUM2LONG(argv[i]);
11640 }
11641 }
11642
11643 switch (argc) {
11644 case 1:
11645 retval = SYSCALL(num);
11646 break;
11647 case 2:
11648 retval = SYSCALL(num, arg[0]);
11649 break;
11650 case 3:
11651 retval = SYSCALL(num, arg[0],arg[1]);
11652 break;
11653 case 4:
11654 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11655 break;
11656 case 5:
11657 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11658 break;
11659 case 6:
11660 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11661 break;
11662 case 7:
11663 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11664 break;
11665 case 8:
11666 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11667 break;
11668 }
11669
11670 if (retval == -1)
11671 rb_sys_fail(0);
11672 return RETVAL2NUM(retval);
11673#undef SYSCALL
11674#undef NUM2SYSCALLID
11675#undef RETVAL2NUM
11676}
11677#else
11678#define rb_f_syscall rb_f_notimplement
11679#endif
11680
11681static VALUE
11682io_new_instance(VALUE args)
11683{
11684 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11685}
11686
11687static rb_encoding *
11688find_encoding(VALUE v)
11689{
11690 rb_encoding *enc = rb_find_encoding(v);
11691 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11692 return enc;
11693}
11694
11695static void
11696io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11697{
11698 rb_encoding *enc, *enc2;
11699 int ecflags = fptr->encs.ecflags;
11700 VALUE ecopts, tmp;
11701
11702 if (!NIL_P(v2)) {
11703 enc2 = find_encoding(v1);
11704 tmp = rb_check_string_type(v2);
11705 if (!NIL_P(tmp)) {
11706 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11707 /* Special case - "-" => no transcoding */
11708 enc = enc2;
11709 enc2 = NULL;
11710 }
11711 else
11712 enc = find_encoding(v2);
11713 if (enc == enc2) {
11714 /* Special case - "-" => no transcoding */
11715 enc2 = NULL;
11716 }
11717 }
11718 else {
11719 enc = find_encoding(v2);
11720 if (enc == enc2) {
11721 /* Special case - "-" => no transcoding */
11722 enc2 = NULL;
11723 }
11724 }
11725 if (enc2 == rb_ascii8bit_encoding()) {
11726 /* If external is ASCII-8BIT, no transcoding */
11727 enc = enc2;
11728 enc2 = NULL;
11729 }
11730 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11731 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11732 }
11733 else {
11734 if (NIL_P(v1)) {
11735 /* Set to default encodings */
11736 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11737 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11738 ecopts = Qnil;
11739 }
11740 else {
11741 tmp = rb_check_string_type(v1);
11742 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11743 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11744 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11745 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11746 }
11747 else {
11748 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11749 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11750 ecopts = Qnil;
11751 }
11752 }
11753 }
11754 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11755 fptr->encs.enc = enc;
11756 fptr->encs.enc2 = enc2;
11757 fptr->encs.ecflags = ecflags;
11758 fptr->encs.ecopts = ecopts;
11759 clear_codeconv(fptr);
11760
11761}
11762
11764 rb_io_t *fptr;
11765 VALUE v1;
11766 VALUE v2;
11767 VALUE opt;
11768};
11769
11770static VALUE
11771io_encoding_set_v(VALUE v)
11772{
11773 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11774 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11775 return Qnil;
11776}
11777
11778static VALUE
11779pipe_pair_close(VALUE rw)
11780{
11781 VALUE *rwp = (VALUE *)rw;
11782 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11783}
11784
11785/*
11786 * call-seq:
11787 * IO.pipe(**opts) -> [read_io, write_io]
11788 * IO.pipe(enc, **opts) -> [read_io, write_io]
11789 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11790 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11791 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11792 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11793 *
11794 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11795 * connected to each other.
11796 *
11797 * If argument +enc_string+ is given, it must be a string containing one of:
11798 *
11799 * - The name of the encoding to be used as the external encoding.
11800 * - The colon-separated names of two encodings to be used as the external
11801 * and internal encodings.
11802 *
11803 * If argument +int_enc+ is given, it must be an Encoding object
11804 * or encoding name string that specifies the internal encoding to be used;
11805 * if argument +ext_enc+ is also given, it must be an Encoding object
11806 * or encoding name string that specifies the external encoding to be used.
11807 *
11808 * The string read from +read_io+ is tagged with the external encoding;
11809 * if an internal encoding is also specified, the string is converted
11810 * to, and tagged with, that encoding.
11811 *
11812 * If any encoding is specified,
11813 * optional hash arguments specify the conversion option.
11814 *
11815 * Optional keyword arguments +opts+ specify:
11816 *
11817 * - {Open Options}[rdoc-ref:IO@Open+Options].
11818 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11819 *
11820 * With no block given, returns the two endpoints in an array:
11821 *
11822 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11823 *
11824 * With a block given, calls the block with the two endpoints;
11825 * closes both endpoints and returns the value of the block:
11826 *
11827 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11828 *
11829 * Output:
11830 *
11831 * #<IO:fd 6>
11832 * #<IO:fd 7>
11833 *
11834 * Not available on all platforms.
11835 *
11836 * In the example below, the two processes close the ends of the pipe
11837 * that they are not using. This is not just a cosmetic nicety. The
11838 * read end of a pipe will not generate an end of file condition if
11839 * there are any writers with the pipe still open. In the case of the
11840 * parent process, the <tt>rd.read</tt> will never return if it
11841 * does not first issue a <tt>wr.close</tt>:
11842 *
11843 * rd, wr = IO.pipe
11844 *
11845 * if fork
11846 * wr.close
11847 * puts "Parent got: <#{rd.read}>"
11848 * rd.close
11849 * Process.wait
11850 * else
11851 * rd.close
11852 * puts 'Sending message to parent'
11853 * wr.write "Hi Dad"
11854 * wr.close
11855 * end
11856 *
11857 * <em>produces:</em>
11858 *
11859 * Sending message to parent
11860 * Parent got: <Hi Dad>
11861 *
11862 */
11863
11864static VALUE
11865rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11866{
11867 int pipes[2], state;
11868 VALUE r, w, args[3], v1, v2;
11869 VALUE opt;
11870 rb_io_t *fptr, *fptr2;
11871 struct io_encoding_set_args ies_args;
11872 int fmode = 0;
11873 VALUE ret;
11874
11875 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11876 if (rb_pipe(pipes) < 0)
11877 rb_sys_fail(0);
11878
11879 args[0] = klass;
11880 args[1] = INT2NUM(pipes[0]);
11881 args[2] = INT2FIX(O_RDONLY);
11882 r = rb_protect(io_new_instance, (VALUE)args, &state);
11883 if (state) {
11884 close(pipes[0]);
11885 close(pipes[1]);
11886 rb_jump_tag(state);
11887 }
11888 GetOpenFile(r, fptr);
11889
11890 ies_args.fptr = fptr;
11891 ies_args.v1 = v1;
11892 ies_args.v2 = v2;
11893 ies_args.opt = opt;
11894 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11895 if (state) {
11896 close(pipes[1]);
11897 io_close(r);
11898 rb_jump_tag(state);
11899 }
11900
11901 args[1] = INT2NUM(pipes[1]);
11902 args[2] = INT2FIX(O_WRONLY);
11903 w = rb_protect(io_new_instance, (VALUE)args, &state);
11904 if (state) {
11905 close(pipes[1]);
11906 if (!NIL_P(r)) rb_io_close(r);
11907 rb_jump_tag(state);
11908 }
11909 GetOpenFile(w, fptr2);
11910 rb_io_synchronized(fptr2);
11911
11912 extract_binmode(opt, &fmode);
11913
11914 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11917 }
11918
11919#if DEFAULT_TEXTMODE
11920 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11921 fptr->mode &= ~FMODE_TEXTMODE;
11922 setmode(fptr->fd, O_BINARY);
11923 }
11924#if RUBY_CRLF_ENVIRONMENT
11927 }
11928#endif
11929#endif
11930 fptr->mode |= fmode;
11931#if DEFAULT_TEXTMODE
11932 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11933 fptr2->mode &= ~FMODE_TEXTMODE;
11934 setmode(fptr2->fd, O_BINARY);
11935 }
11936#endif
11937 fptr2->mode |= fmode;
11938
11939 ret = rb_assoc_new(r, w);
11940 if (rb_block_given_p()) {
11941 VALUE rw[2];
11942 rw[0] = r;
11943 rw[1] = w;
11944 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11945 }
11946 return ret;
11947}
11948
11950 int argc;
11951 VALUE *argv;
11952 VALUE io;
11953};
11954
11955static void
11956open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11957{
11958 VALUE path, v;
11959 VALUE vmode = Qnil, vperm = Qnil;
11960
11961 path = *argv++;
11962 argc--;
11963 FilePathValue(path);
11964 arg->io = 0;
11965 arg->argc = argc;
11966 arg->argv = argv;
11967 if (NIL_P(opt)) {
11968 vmode = INT2NUM(O_RDONLY);
11969 vperm = INT2FIX(0666);
11970 }
11971 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11972 int n;
11973
11974 v = rb_to_array_type(v);
11975 n = RARRAY_LENINT(v);
11976 rb_check_arity(n, 0, 3); /* rb_io_open */
11977 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11978 }
11979 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11980}
11981
11982static VALUE
11983io_s_foreach(VALUE v)
11984{
11985 struct getline_arg *arg = (void *)v;
11986 VALUE str;
11987
11988 if (arg->limit == 0)
11989 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
11990 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11991 rb_lastline_set(str);
11992 rb_yield(str);
11993 }
11995 return Qnil;
11996}
11997
11998/*
11999 * call-seq:
12000 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12001 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12002 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12003 * IO.foreach(...) -> an_enumerator
12004 *
12005 * Calls the block with each successive line read from the stream.
12006 *
12007 * When called from class \IO (but not subclasses of \IO),
12008 * this method has potential security vulnerabilities if called with untrusted input;
12009 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12010 *
12011 * The first argument must be a string that is the path to a file.
12012 *
12013 * With only argument +path+ given, parses lines from the file at the given +path+,
12014 * as determined by the default line separator,
12015 * and calls the block with each successive line:
12016 *
12017 * File.foreach('t.txt') {|line| p line }
12018 *
12019 * Output: the same as above.
12020 *
12021 * For both forms, command and path, the remaining arguments are the same.
12022 *
12023 * With argument +sep+ given, parses lines as determined by that line separator
12024 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12025 *
12026 * File.foreach('t.txt', 'li') {|line| p line }
12027 *
12028 * Output:
12029 *
12030 * "First li"
12031 * "ne\nSecond li"
12032 * "ne\n\nThird li"
12033 * "ne\nFourth li"
12034 * "ne\n"
12035 *
12036 * Each paragraph:
12037 *
12038 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12039 *
12040 * Output:
12041 *
12042 * "First line\nSecond line\n\n"
12043 * "Third line\nFourth line\n"
12044 *
12045 * With argument +limit+ given, parses lines as determined by the default
12046 * line separator and the given line-length limit
12047 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12048 *
12049 * File.foreach('t.txt', 7) {|line| p line }
12050 *
12051 * Output:
12052 *
12053 * "First l"
12054 * "ine\n"
12055 * "Second "
12056 * "line\n"
12057 * "\n"
12058 * "Third l"
12059 * "ine\n"
12060 * "Fourth l"
12061 * "line\n"
12062 *
12063 * With arguments +sep+ and +limit+ given,
12064 * combines the two behaviors
12065 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12066 *
12067 * Optional keyword arguments +opts+ specify:
12068 *
12069 * - {Open Options}[rdoc-ref:IO@Open+Options].
12070 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12071 * - {Line Options}[rdoc-ref:IO@Line+IO].
12072 *
12073 * Returns an Enumerator if no block is given.
12074 *
12075 */
12076
12077static VALUE
12078rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12079{
12080 VALUE opt;
12081 int orig_argc = argc;
12082 struct foreach_arg arg;
12083 struct getline_arg garg;
12084
12085 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12086 RETURN_ENUMERATOR(self, orig_argc, argv);
12087 extract_getline_args(argc-1, argv+1, &garg);
12088 open_key_args(self, argc, argv, opt, &arg);
12089 if (NIL_P(arg.io)) return Qnil;
12090 extract_getline_opts(opt, &garg);
12091 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12092 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12093}
12094
12095static VALUE
12096io_s_readlines(VALUE v)
12097{
12098 struct getline_arg *arg = (void *)v;
12099 return io_readlines(arg, arg->io);
12100}
12101
12102/*
12103 * call-seq:
12104 * IO.readlines(path, sep = $/, **opts) -> array
12105 * IO.readlines(path, limit, **opts) -> array
12106 * IO.readlines(path, sep, limit, **opts) -> array
12107 *
12108 * Returns an array of all lines read from the stream.
12109 *
12110 * When called from class \IO (but not subclasses of \IO),
12111 * this method has potential security vulnerabilities if called with untrusted input;
12112 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12113 *
12114 * The first argument must be a string that is the path to a file.
12115 *
12116 * With only argument +path+ given, parses lines from the file at the given +path+,
12117 * as determined by the default line separator,
12118 * and returns those lines in an array:
12119 *
12120 * IO.readlines('t.txt')
12121 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12122 *
12123 * With argument +sep+ given, parses lines as determined by that line separator
12124 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12125 *
12126 * # Ordinary separator.
12127 * IO.readlines('t.txt', 'li')
12128 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12129 * # Get-paragraphs separator.
12130 * IO.readlines('t.txt', '')
12131 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12132 * # Get-all separator.
12133 * IO.readlines('t.txt', nil)
12134 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12135 *
12136 * With argument +limit+ given, parses lines as determined by the default
12137 * line separator and the given line-length limit
12138 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12139 *
12140 * IO.readlines('t.txt', 7)
12141 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12142 *
12143 * With arguments +sep+ and +limit+ given,
12144 * combines the two behaviors
12145 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12146 *
12147 * Optional keyword arguments +opts+ specify:
12148 *
12149 * - {Open Options}[rdoc-ref:IO@Open+Options].
12150 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12151 * - {Line Options}[rdoc-ref:IO@Line+IO].
12152 *
12153 */
12154
12155static VALUE
12156rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12157{
12158 VALUE opt;
12159 struct foreach_arg arg;
12160 struct getline_arg garg;
12161
12162 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12163 extract_getline_args(argc-1, argv+1, &garg);
12164 open_key_args(io, argc, argv, opt, &arg);
12165 if (NIL_P(arg.io)) return Qnil;
12166 extract_getline_opts(opt, &garg);
12167 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12168 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12169}
12170
12171static VALUE
12172io_s_read(VALUE v)
12173{
12174 struct foreach_arg *arg = (void *)v;
12175 return io_read(arg->argc, arg->argv, arg->io);
12176}
12177
12178struct seek_arg {
12179 VALUE io;
12180 VALUE offset;
12181 int mode;
12182};
12183
12184static VALUE
12185seek_before_access(VALUE argp)
12186{
12187 struct seek_arg *arg = (struct seek_arg *)argp;
12188 rb_io_binmode(arg->io);
12189 return rb_io_seek(arg->io, arg->offset, arg->mode);
12190}
12191
12192/*
12193 * call-seq:
12194 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12195 *
12196 * Opens the stream, reads and returns some or all of its content,
12197 * and closes the stream; returns +nil+ if no bytes were read.
12198 *
12199 * When called from class \IO (but not subclasses of \IO),
12200 * this method has potential security vulnerabilities if called with untrusted input;
12201 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12202 *
12203 * The first argument must be a string that is the path to a file.
12204 *
12205 * With only argument +path+ given, reads in text mode and returns the entire content
12206 * of the file at the given path:
12207 *
12208 * IO.read('t.txt')
12209 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12210 *
12211 * On Windows, text mode can terminate reading and leave bytes in the file
12212 * unread when encountering certain special bytes. Consider using
12213 * IO.binread if all bytes in the file should be read.
12214 *
12215 * With argument +length+, returns +length+ bytes if available:
12216 *
12217 * IO.read('t.txt', 7) # => "First l"
12218 * IO.read('t.txt', 700)
12219 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12220 *
12221 * With arguments +length+ and +offset+, returns +length+ bytes
12222 * if available, beginning at the given +offset+:
12223 *
12224 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12225 * IO.read('t.txt', 10, 200) # => nil
12226 *
12227 * Optional keyword arguments +opts+ specify:
12228 *
12229 * - {Open Options}[rdoc-ref:IO@Open+Options].
12230 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12231 *
12232 */
12233
12234static VALUE
12235rb_io_s_read(int argc, VALUE *argv, VALUE io)
12236{
12237 VALUE opt, offset;
12238 long off;
12239 struct foreach_arg arg;
12240
12241 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12242 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12243 rb_raise(rb_eArgError, "negative offset %ld given", off);
12244 }
12245 open_key_args(io, argc, argv, opt, &arg);
12246 if (NIL_P(arg.io)) return Qnil;
12247 if (!NIL_P(offset)) {
12248 struct seek_arg sarg;
12249 int state = 0;
12250 sarg.io = arg.io;
12251 sarg.offset = offset;
12252 sarg.mode = SEEK_SET;
12253 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12254 if (state) {
12255 rb_io_close(arg.io);
12256 rb_jump_tag(state);
12257 }
12258 if (arg.argc == 2) arg.argc = 1;
12259 }
12260 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12261}
12262
12263/*
12264 * call-seq:
12265 * IO.binread(path, length = nil, offset = 0) -> string or nil
12266 *
12267 * Behaves like IO.read, except that the stream is opened in binary mode
12268 * with ASCII-8BIT encoding.
12269 *
12270 * When called from class \IO (but not subclasses of \IO),
12271 * this method has potential security vulnerabilities if called with untrusted input;
12272 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12273 *
12274 */
12275
12276static VALUE
12277rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12278{
12279 VALUE offset;
12280 struct foreach_arg arg;
12281 enum {
12283 oflags = O_RDONLY
12284#ifdef O_BINARY
12285 |O_BINARY
12286#endif
12287 };
12288 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12289
12290 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12291 FilePathValue(argv[0]);
12292 convconfig.enc = rb_ascii8bit_encoding();
12293 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12294 if (NIL_P(arg.io)) return Qnil;
12295 arg.argv = argv+1;
12296 arg.argc = (argc > 1) ? 1 : 0;
12297 if (!NIL_P(offset)) {
12298 struct seek_arg sarg;
12299 int state = 0;
12300 sarg.io = arg.io;
12301 sarg.offset = offset;
12302 sarg.mode = SEEK_SET;
12303 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12304 if (state) {
12305 rb_io_close(arg.io);
12306 rb_jump_tag(state);
12307 }
12308 }
12309 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12310}
12311
12312static VALUE
12313io_s_write0(VALUE v)
12314{
12315 struct write_arg *arg = (void *)v;
12316 return io_write(arg->io,arg->str,arg->nosync);
12317}
12318
12319static VALUE
12320io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12321{
12322 VALUE string, offset, opt;
12323 struct foreach_arg arg;
12324 struct write_arg warg;
12325
12326 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12327
12328 if (NIL_P(opt)) opt = rb_hash_new();
12329 else opt = rb_hash_dup(opt);
12330
12331
12332 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12333 int mode = O_WRONLY|O_CREAT;
12334#ifdef O_BINARY
12335 if (binary) mode |= O_BINARY;
12336#endif
12337 if (NIL_P(offset)) mode |= O_TRUNC;
12338 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12339 }
12340 open_key_args(klass, argc, argv, opt, &arg);
12341
12342#ifndef O_BINARY
12343 if (binary) rb_io_binmode_m(arg.io);
12344#endif
12345
12346 if (NIL_P(arg.io)) return Qnil;
12347 if (!NIL_P(offset)) {
12348 struct seek_arg sarg;
12349 int state = 0;
12350 sarg.io = arg.io;
12351 sarg.offset = offset;
12352 sarg.mode = SEEK_SET;
12353 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12354 if (state) {
12355 rb_io_close(arg.io);
12356 rb_jump_tag(state);
12357 }
12358 }
12359
12360 warg.io = arg.io;
12361 warg.str = string;
12362 warg.nosync = 0;
12363
12364 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12365}
12366
12367/*
12368 * call-seq:
12369 * IO.write(path, data, offset = 0, **opts) -> integer
12370 *
12371 * Opens the stream, writes the given +data+ to it,
12372 * and closes the stream; returns the number of bytes written.
12373 *
12374 * When called from class \IO (but not subclasses of \IO),
12375 * this method has potential security vulnerabilities if called with untrusted input;
12376 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12377 *
12378 * The first argument must be a string that is the path to a file.
12379 *
12380 * With only argument +path+ given, writes the given +data+ to the file at that path:
12381 *
12382 * IO.write('t.tmp', 'abc') # => 3
12383 * File.read('t.tmp') # => "abc"
12384 *
12385 * If +offset+ is zero (the default), the file is overwritten:
12386 *
12387 * IO.write('t.tmp', 'A') # => 1
12388 * File.read('t.tmp') # => "A"
12389 *
12390 * If +offset+ in within the file content, the file is partly overwritten:
12391 *
12392 * IO.write('t.tmp', 'abcdef') # => 3
12393 * File.read('t.tmp') # => "abcdef"
12394 * # Offset within content.
12395 * IO.write('t.tmp', '012', 2) # => 3
12396 * File.read('t.tmp') # => "ab012f"
12397 *
12398 * If +offset+ is outside the file content,
12399 * the file is padded with null characters <tt>"\u0000"</tt>:
12400 *
12401 * IO.write('t.tmp', 'xyz', 10) # => 3
12402 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12403 *
12404 * Optional keyword arguments +opts+ specify:
12405 *
12406 * - {Open Options}[rdoc-ref:IO@Open+Options].
12407 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12408 *
12409 */
12410
12411static VALUE
12412rb_io_s_write(int argc, VALUE *argv, VALUE io)
12413{
12414 return io_s_write(argc, argv, io, 0);
12415}
12416
12417/*
12418 * call-seq:
12419 * IO.binwrite(path, string, offset = 0) -> integer
12420 *
12421 * Behaves like IO.write, except that the stream is opened in binary mode
12422 * with ASCII-8BIT encoding.
12423 *
12424 * When called from class \IO (but not subclasses of \IO),
12425 * this method has potential security vulnerabilities if called with untrusted input;
12426 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12427 *
12428 */
12429
12430static VALUE
12431rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12432{
12433 return io_s_write(argc, argv, io, 1);
12434}
12435
12437 VALUE src;
12438 VALUE dst;
12439 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12440 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12441
12442 rb_io_t *src_fptr;
12443 rb_io_t *dst_fptr;
12444 unsigned close_src : 1;
12445 unsigned close_dst : 1;
12446 int error_no;
12447 rb_off_t total;
12448 const char *syserr;
12449 const char *notimp;
12450 VALUE th;
12451 struct stat src_stat;
12452 struct stat dst_stat;
12453#ifdef HAVE_FCOPYFILE
12454 copyfile_state_t copyfile_state;
12455#endif
12456};
12457
12458static void *
12459exec_interrupts(void *arg)
12460{
12461 VALUE th = (VALUE)arg;
12462 rb_thread_execute_interrupts(th);
12463 return NULL;
12464}
12465
12466/*
12467 * returns TRUE if the preceding system call was interrupted
12468 * so we can continue. If the thread was interrupted, we
12469 * reacquire the GVL to execute interrupts before continuing.
12470 */
12471static int
12472maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12473{
12474 switch (errno) {
12475 case EINTR:
12476#if defined(ERESTART)
12477 case ERESTART:
12478#endif
12479 if (rb_thread_interrupted(stp->th)) {
12480 if (has_gvl)
12481 rb_thread_execute_interrupts(stp->th);
12482 else
12483 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12484 }
12485 return TRUE;
12486 }
12487 return FALSE;
12488}
12489
12491 VALUE scheduler;
12492
12493 rb_io_t *fptr;
12494 short events;
12495
12496 VALUE result;
12497};
12498
12499static void *
12500fiber_scheduler_wait_for(void * _arguments)
12501{
12502 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12503
12504 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12505
12506 return NULL;
12507}
12508
12509#if USE_POLL
12510# define IOWAIT_SYSCALL "poll"
12511STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12512STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12513static int
12514nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12515{
12517 if (scheduler != Qnil) {
12518 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12519 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12520 return RTEST(args.result);
12521 }
12522
12523 int fd = fptr->fd;
12524 if (fd == -1) return 0;
12525
12526 struct pollfd fds;
12527
12528 fds.fd = fd;
12529 fds.events = events;
12530
12531 int timeout_milliseconds = -1;
12532
12533 if (timeout) {
12534 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12535 }
12536
12537 return poll(&fds, 1, timeout_milliseconds);
12538}
12539#else /* !USE_POLL */
12540# define IOWAIT_SYSCALL "select"
12541static int
12542nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12543{
12545 if (scheduler != Qnil) {
12546 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12547 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12548 return RTEST(args.result);
12549 }
12550
12551 int fd = fptr->fd;
12552
12553 if (fd == -1) {
12554 errno = EBADF;
12555 return -1;
12556 }
12557
12558 rb_fdset_t fds;
12559 int ret;
12560
12561 rb_fd_init(&fds);
12562 rb_fd_set(fd, &fds);
12563
12564 switch (events) {
12565 case RB_WAITFD_IN:
12566 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12567 break;
12568 case RB_WAITFD_OUT:
12569 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12570 break;
12571 default:
12572 VM_UNREACHABLE(nogvl_wait_for);
12573 }
12574
12575 rb_fd_term(&fds);
12576
12577 // On timeout, this returns 0.
12578 return ret;
12579}
12580#endif /* !USE_POLL */
12581
12582static int
12583maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12584{
12585 int ret;
12586
12587 do {
12588 if (has_gvl) {
12590 }
12591 else {
12592 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12593 }
12594 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12595
12596 if (ret < 0) {
12597 stp->syserr = IOWAIT_SYSCALL;
12598 stp->error_no = errno;
12599 return ret;
12600 }
12601 return 0;
12602}
12603
12604static int
12605nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12606{
12607 int ret;
12608
12609 do {
12610 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12611 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12612
12613 if (ret < 0) {
12614 stp->syserr = IOWAIT_SYSCALL;
12615 stp->error_no = errno;
12616 return ret;
12617 }
12618 return 0;
12619}
12620
12621#ifdef USE_COPY_FILE_RANGE
12622
12623static ssize_t
12624simple_copy_file_range(int in_fd, rb_off_t *in_offset, int out_fd, rb_off_t *out_offset, size_t count, unsigned int flags)
12625{
12626#ifdef HAVE_COPY_FILE_RANGE
12627 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12628#else
12629 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12630#endif
12631}
12632
12633static int
12634nogvl_copy_file_range(struct copy_stream_struct *stp)
12635{
12636 ssize_t ss;
12637 rb_off_t src_size;
12638 rb_off_t copy_length, src_offset, *src_offset_ptr;
12639
12640 if (!S_ISREG(stp->src_stat.st_mode))
12641 return 0;
12642
12643 src_size = stp->src_stat.st_size;
12644 src_offset = stp->src_offset;
12645 if (src_offset >= (rb_off_t)0) {
12646 src_offset_ptr = &src_offset;
12647 }
12648 else {
12649 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12650 }
12651
12652 copy_length = stp->copy_length;
12653 if (copy_length < (rb_off_t)0) {
12654 if (src_offset < (rb_off_t)0) {
12655 rb_off_t current_offset;
12656 errno = 0;
12657 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12658 if (current_offset < (rb_off_t)0 && errno) {
12659 stp->syserr = "lseek";
12660 stp->error_no = errno;
12661 return (int)current_offset;
12662 }
12663 copy_length = src_size - current_offset;
12664 }
12665 else {
12666 copy_length = src_size - src_offset;
12667 }
12668 }
12669
12670 retry_copy_file_range:
12671# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12672 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12673 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12674# else
12675 ss = (ssize_t)copy_length;
12676# endif
12677 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12678 if (0 < ss) {
12679 stp->total += ss;
12680 copy_length -= ss;
12681 if (0 < copy_length) {
12682 goto retry_copy_file_range;
12683 }
12684 }
12685 if (ss < 0) {
12686 if (maygvl_copy_stream_continue_p(0, stp)) {
12687 goto retry_copy_file_range;
12688 }
12689 switch (errno) {
12690 case EINVAL:
12691 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12692 docker container) */
12693#ifdef ENOSYS
12694 case ENOSYS:
12695#endif
12696#ifdef EXDEV
12697 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12698#endif
12699 return 0;
12700 case EAGAIN:
12701#if EWOULDBLOCK != EAGAIN
12702 case EWOULDBLOCK:
12703#endif
12704 {
12705 int ret = nogvl_copy_stream_wait_write(stp);
12706 if (ret < 0) return ret;
12707 }
12708 goto retry_copy_file_range;
12709 case EBADF:
12710 {
12711 int e = errno;
12712 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12713
12714 if (flags != -1 && flags & O_APPEND) {
12715 return 0;
12716 }
12717 errno = e;
12718 }
12719 }
12720 stp->syserr = "copy_file_range";
12721 stp->error_no = errno;
12722 return (int)ss;
12723 }
12724 return 1;
12725}
12726#endif
12727
12728#ifdef HAVE_FCOPYFILE
12729static int
12730nogvl_fcopyfile(struct copy_stream_struct *stp)
12731{
12732 rb_off_t cur, ss = 0;
12733 const rb_off_t src_offset = stp->src_offset;
12734 int ret;
12735
12736 if (stp->copy_length >= (rb_off_t)0) {
12737 /* copy_length can't be specified in fcopyfile(3) */
12738 return 0;
12739 }
12740
12741 if (!S_ISREG(stp->src_stat.st_mode))
12742 return 0;
12743
12744 if (!S_ISREG(stp->dst_stat.st_mode))
12745 return 0;
12746 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12747 return 0;
12748 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12749 /* fcopyfile(3) appends src IO to dst IO and then truncates
12750 * dst IO to src IO's original size. */
12751 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12752 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12753 if (end > (rb_off_t)0) return 0;
12754 }
12755
12756 if (src_offset > (rb_off_t)0) {
12757 rb_off_t r;
12758
12759 /* get current offset */
12760 errno = 0;
12761 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12762 if (cur < (rb_off_t)0 && errno) {
12763 stp->error_no = errno;
12764 return 1;
12765 }
12766
12767 errno = 0;
12768 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12769 if (r < (rb_off_t)0 && errno) {
12770 stp->error_no = errno;
12771 return 1;
12772 }
12773 }
12774
12775 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12776 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12777 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12778
12779 if (ret == 0) { /* success */
12780 stp->total = ss;
12781 if (src_offset > (rb_off_t)0) {
12782 rb_off_t r;
12783 errno = 0;
12784 /* reset offset */
12785 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12786 if (r < (rb_off_t)0 && errno) {
12787 stp->error_no = errno;
12788 return 1;
12789 }
12790 }
12791 }
12792 else {
12793 switch (errno) {
12794 case ENOTSUP:
12795 case EPERM:
12796 case EINVAL:
12797 return 0;
12798 }
12799 stp->syserr = "fcopyfile";
12800 stp->error_no = errno;
12801 return (int)ret;
12802 }
12803 return 1;
12804}
12805#endif
12806
12807#ifdef HAVE_SENDFILE
12808
12809# ifdef __linux__
12810# define USE_SENDFILE
12811
12812# ifdef HAVE_SYS_SENDFILE_H
12813# include <sys/sendfile.h>
12814# endif
12815
12816static ssize_t
12817simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12818{
12819 return sendfile(out_fd, in_fd, offset, (size_t)count);
12820}
12821
12822# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12823/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12824 * without cpuset -l 0.
12825 */
12826# define USE_SENDFILE
12827
12828static ssize_t
12829simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12830{
12831 int r;
12832 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12833 rb_off_t sbytes;
12834# ifdef __APPLE__
12835 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12836 sbytes = count;
12837# else
12838 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12839# endif
12840 if (r != 0 && sbytes == 0) return r;
12841 if (offset) {
12842 *offset += sbytes;
12843 }
12844 else {
12845 lseek(in_fd, sbytes, SEEK_CUR);
12846 }
12847 return (ssize_t)sbytes;
12848}
12849
12850# endif
12851
12852#endif
12853
12854#ifdef USE_SENDFILE
12855static int
12856nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12857{
12858 ssize_t ss;
12859 rb_off_t src_size;
12860 rb_off_t copy_length;
12861 rb_off_t src_offset;
12862 int use_pread;
12863
12864 if (!S_ISREG(stp->src_stat.st_mode))
12865 return 0;
12866
12867 src_size = stp->src_stat.st_size;
12868#ifndef __linux__
12869 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12870 return 0;
12871#endif
12872
12873 src_offset = stp->src_offset;
12874 use_pread = src_offset >= (rb_off_t)0;
12875
12876 copy_length = stp->copy_length;
12877 if (copy_length < (rb_off_t)0) {
12878 if (use_pread)
12879 copy_length = src_size - src_offset;
12880 else {
12881 rb_off_t cur;
12882 errno = 0;
12883 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12884 if (cur < (rb_off_t)0 && errno) {
12885 stp->syserr = "lseek";
12886 stp->error_no = errno;
12887 return (int)cur;
12888 }
12889 copy_length = src_size - cur;
12890 }
12891 }
12892
12893 retry_sendfile:
12894# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12895 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12896 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12897# else
12898 ss = (ssize_t)copy_length;
12899# endif
12900 if (use_pread) {
12901 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12902 }
12903 else {
12904 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12905 }
12906 if (0 < ss) {
12907 stp->total += ss;
12908 copy_length -= ss;
12909 if (0 < copy_length) {
12910 goto retry_sendfile;
12911 }
12912 }
12913 if (ss < 0) {
12914 if (maygvl_copy_stream_continue_p(0, stp))
12915 goto retry_sendfile;
12916 switch (errno) {
12917 case EINVAL:
12918#ifdef ENOSYS
12919 case ENOSYS:
12920#endif
12921#ifdef EOPNOTSUP
12922 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12923 see also: [Feature #16965] */
12924 case EOPNOTSUP:
12925#endif
12926 return 0;
12927 case EAGAIN:
12928#if EWOULDBLOCK != EAGAIN
12929 case EWOULDBLOCK:
12930#endif
12931 {
12932 int ret;
12933#ifndef __linux__
12934 /*
12935 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12936 * select() reports regular files to always be "ready", so
12937 * there is no need to select() on it.
12938 * Other OSes may have the same limitation for sendfile() which
12939 * allow us to bypass maygvl_copy_stream_wait_read()...
12940 */
12941 ret = maygvl_copy_stream_wait_read(0, stp);
12942 if (ret < 0) return ret;
12943#endif
12944 ret = nogvl_copy_stream_wait_write(stp);
12945 if (ret < 0) return ret;
12946 }
12947 goto retry_sendfile;
12948 }
12949 stp->syserr = "sendfile";
12950 stp->error_no = errno;
12951 return (int)ss;
12952 }
12953 return 1;
12954}
12955#endif
12956
12957static ssize_t
12958maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12959{
12960 if (has_gvl)
12961 return rb_io_read_memory(fptr, buf, count);
12962 else
12963 return read(fptr->fd, buf, count);
12964}
12965
12966static ssize_t
12967maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12968{
12969 ssize_t ss;
12970 retry_read:
12971 if (offset < (rb_off_t)0) {
12972 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12973 }
12974 else {
12975 ss = pread(stp->src_fptr->fd, buf, len, offset);
12976 }
12977 if (ss == 0) {
12978 return 0;
12979 }
12980 if (ss < 0) {
12981 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12982 goto retry_read;
12983 switch (errno) {
12984 case EAGAIN:
12985#if EWOULDBLOCK != EAGAIN
12986 case EWOULDBLOCK:
12987#endif
12988 {
12989 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12990 if (ret < 0) return ret;
12991 }
12992 goto retry_read;
12993#ifdef ENOSYS
12994 case ENOSYS:
12995 stp->notimp = "pread";
12996 return ss;
12997#endif
12998 }
12999 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13000 stp->error_no = errno;
13001 }
13002 return ss;
13003}
13004
13005static int
13006nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13007{
13008 ssize_t ss;
13009 int off = 0;
13010 while (len) {
13011 ss = write(stp->dst_fptr->fd, buf+off, len);
13012 if (ss < 0) {
13013 if (maygvl_copy_stream_continue_p(0, stp))
13014 continue;
13015 if (io_again_p(errno)) {
13016 int ret = nogvl_copy_stream_wait_write(stp);
13017 if (ret < 0) return ret;
13018 continue;
13019 }
13020 stp->syserr = "write";
13021 stp->error_no = errno;
13022 return (int)ss;
13023 }
13024 off += (int)ss;
13025 len -= (int)ss;
13026 stp->total += ss;
13027 }
13028 return 0;
13029}
13030
13031static void
13032nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13033{
13034 char buf[1024*16];
13035 size_t len;
13036 ssize_t ss;
13037 int ret;
13038 rb_off_t copy_length;
13039 rb_off_t src_offset;
13040 int use_eof;
13041 int use_pread;
13042
13043 copy_length = stp->copy_length;
13044 use_eof = copy_length < (rb_off_t)0;
13045 src_offset = stp->src_offset;
13046 use_pread = src_offset >= (rb_off_t)0;
13047
13048 if (use_pread && stp->close_src) {
13049 rb_off_t r;
13050 errno = 0;
13051 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13052 if (r < (rb_off_t)0 && errno) {
13053 stp->syserr = "lseek";
13054 stp->error_no = errno;
13055 return;
13056 }
13057 src_offset = (rb_off_t)-1;
13058 use_pread = 0;
13059 }
13060
13061 while (use_eof || 0 < copy_length) {
13062 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13063 len = (size_t)copy_length;
13064 }
13065 else {
13066 len = sizeof(buf);
13067 }
13068 if (use_pread) {
13069 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13070 if (0 < ss)
13071 src_offset += ss;
13072 }
13073 else {
13074 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13075 }
13076 if (ss <= 0) /* EOF or error */
13077 return;
13078
13079 ret = nogvl_copy_stream_write(stp, buf, ss);
13080 if (ret < 0)
13081 return;
13082
13083 if (!use_eof)
13084 copy_length -= ss;
13085 }
13086}
13087
13088static void *
13089nogvl_copy_stream_func(void *arg)
13090{
13091 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13092#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13093 int ret;
13094#endif
13095
13096#ifdef USE_COPY_FILE_RANGE
13097 ret = nogvl_copy_file_range(stp);
13098 if (ret != 0)
13099 goto finish; /* error or success */
13100#endif
13101
13102#ifdef HAVE_FCOPYFILE
13103 ret = nogvl_fcopyfile(stp);
13104 if (ret != 0)
13105 goto finish; /* error or success */
13106#endif
13107
13108#ifdef USE_SENDFILE
13109 ret = nogvl_copy_stream_sendfile(stp);
13110 if (ret != 0)
13111 goto finish; /* error or success */
13112#endif
13113
13114 nogvl_copy_stream_read_write(stp);
13115
13116#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13117 finish:
13118#endif
13119 return 0;
13120}
13121
13122static VALUE
13123copy_stream_fallback_body(VALUE arg)
13124{
13125 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13126 const int buflen = 16*1024;
13127 VALUE n;
13128 VALUE buf = rb_str_buf_new(buflen);
13129 rb_off_t rest = stp->copy_length;
13130 rb_off_t off = stp->src_offset;
13131 ID read_method = id_readpartial;
13132
13133 if (!stp->src_fptr) {
13134 if (!rb_respond_to(stp->src, read_method)) {
13135 read_method = id_read;
13136 }
13137 }
13138
13139 while (1) {
13140 long numwrote;
13141 long l;
13142 rb_str_make_independent(buf);
13143 if (stp->copy_length < (rb_off_t)0) {
13144 l = buflen;
13145 }
13146 else {
13147 if (rest == 0) {
13148 rb_str_resize(buf, 0);
13149 break;
13150 }
13151 l = buflen < rest ? buflen : (long)rest;
13152 }
13153 if (!stp->src_fptr) {
13154 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13155
13156 if (read_method == id_read && NIL_P(rc))
13157 break;
13158 }
13159 else {
13160 ssize_t ss;
13161 rb_str_resize(buf, buflen);
13162 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13163 rb_str_resize(buf, ss > 0 ? ss : 0);
13164 if (ss < 0)
13165 return Qnil;
13166 if (ss == 0)
13167 rb_eof_error();
13168 if (off >= (rb_off_t)0)
13169 off += ss;
13170 }
13171 n = rb_io_write(stp->dst, buf);
13172 numwrote = NUM2LONG(n);
13173 stp->total += numwrote;
13174 rest -= numwrote;
13175 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13176 break;
13177 }
13178 }
13179
13180 return Qnil;
13181}
13182
13183static VALUE
13184copy_stream_fallback(struct copy_stream_struct *stp)
13185{
13186 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13187 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13188 }
13189 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13190 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13191 rb_eEOFError, (VALUE)0);
13192 return Qnil;
13193}
13194
13195static VALUE
13196copy_stream_body(VALUE arg)
13197{
13198 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13199 VALUE src_io = stp->src, dst_io = stp->dst;
13200 const int common_oflags = 0
13201#ifdef O_NOCTTY
13202 | O_NOCTTY
13203#endif
13204 ;
13205
13206 stp->th = rb_thread_current();
13207
13208 stp->total = 0;
13209
13210 if (src_io == argf ||
13211 !(RB_TYPE_P(src_io, T_FILE) ||
13212 RB_TYPE_P(src_io, T_STRING) ||
13213 rb_respond_to(src_io, rb_intern("to_path")))) {
13214 stp->src_fptr = NULL;
13215 }
13216 else {
13217 int stat_ret;
13218 VALUE tmp_io = rb_io_check_io(src_io);
13219 if (!NIL_P(tmp_io)) {
13220 src_io = tmp_io;
13221 }
13222 else if (!RB_TYPE_P(src_io, T_FILE)) {
13223 VALUE args[2];
13224 FilePathValue(src_io);
13225 args[0] = src_io;
13226 args[1] = INT2NUM(O_RDONLY|common_oflags);
13227 src_io = rb_class_new_instance(2, args, rb_cFile);
13228 stp->src = src_io;
13229 stp->close_src = 1;
13230 }
13231 RB_IO_POINTER(src_io, stp->src_fptr);
13232 rb_io_check_byte_readable(stp->src_fptr);
13233
13234 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13235 if (stat_ret < 0) {
13236 stp->syserr = "fstat";
13237 stp->error_no = errno;
13238 return Qnil;
13239 }
13240 }
13241
13242 if (dst_io == argf ||
13243 !(RB_TYPE_P(dst_io, T_FILE) ||
13244 RB_TYPE_P(dst_io, T_STRING) ||
13245 rb_respond_to(dst_io, rb_intern("to_path")))) {
13246 stp->dst_fptr = NULL;
13247 }
13248 else {
13249 int stat_ret;
13250 VALUE tmp_io = rb_io_check_io(dst_io);
13251 if (!NIL_P(tmp_io)) {
13252 dst_io = GetWriteIO(tmp_io);
13253 }
13254 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13255 VALUE args[3];
13256 FilePathValue(dst_io);
13257 args[0] = dst_io;
13258 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13259 args[2] = INT2FIX(0666);
13260 dst_io = rb_class_new_instance(3, args, rb_cFile);
13261 stp->dst = dst_io;
13262 stp->close_dst = 1;
13263 }
13264 else {
13265 dst_io = GetWriteIO(dst_io);
13266 stp->dst = dst_io;
13267 }
13268 RB_IO_POINTER(dst_io, stp->dst_fptr);
13269 rb_io_check_writable(stp->dst_fptr);
13270
13271 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13272 if (stat_ret < 0) {
13273 stp->syserr = "fstat";
13274 stp->error_no = errno;
13275 return Qnil;
13276 }
13277 }
13278
13279#ifdef O_BINARY
13280 if (stp->src_fptr)
13281 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13282#endif
13283 if (stp->dst_fptr)
13284 io_ascii8bit_binmode(stp->dst_fptr);
13285
13286 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13287 size_t len = stp->src_fptr->rbuf.len;
13288 VALUE str;
13289 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13290 len = (size_t)stp->copy_length;
13291 }
13292 str = rb_str_buf_new(len);
13293 rb_str_resize(str,len);
13294 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13295 if (stp->dst_fptr) { /* IO or filename */
13296 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13297 rb_sys_fail_on_write(stp->dst_fptr);
13298 }
13299 else /* others such as StringIO */
13300 rb_io_write(dst_io, str);
13301 rb_str_resize(str, 0);
13302 stp->total += len;
13303 if (stp->copy_length >= (rb_off_t)0)
13304 stp->copy_length -= len;
13305 }
13306
13307 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13308 rb_raise(rb_eIOError, "flush failed");
13309 }
13310
13311 if (stp->copy_length == 0)
13312 return Qnil;
13313
13314 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13315 return copy_stream_fallback(stp);
13316 }
13317
13318 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13319 return Qnil;
13320}
13321
13322static VALUE
13323copy_stream_finalize(VALUE arg)
13324{
13325 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13326
13327#ifdef HAVE_FCOPYFILE
13328 if (stp->copyfile_state) {
13329 copyfile_state_free(stp->copyfile_state);
13330 }
13331#endif
13332
13333 if (stp->close_src) {
13334 rb_io_close_m(stp->src);
13335 }
13336 if (stp->close_dst) {
13337 rb_io_close_m(stp->dst);
13338 }
13339 if (stp->syserr) {
13340 rb_syserr_fail(stp->error_no, stp->syserr);
13341 }
13342 if (stp->notimp) {
13343 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13344 }
13345 return Qnil;
13346}
13347
13348/*
13349 * call-seq:
13350 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13351 *
13352 * Copies from the given +src+ to the given +dst+,
13353 * returning the number of bytes copied.
13354 *
13355 * - The given +src+ must be one of the following:
13356 *
13357 * - The path to a readable file, from which source data is to be read.
13358 * - An \IO-like object, opened for reading and capable of responding
13359 * to method +:readpartial+ or method +:read+.
13360 *
13361 * - The given +dst+ must be one of the following:
13362 *
13363 * - The path to a writable file, to which data is to be written.
13364 * - An \IO-like object, opened for writing and capable of responding
13365 * to method +:write+.
13366 *
13367 * The examples here use file <tt>t.txt</tt> as source:
13368 *
13369 * File.read('t.txt')
13370 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13371 * File.read('t.txt').size # => 47
13372 *
13373 * If only arguments +src+ and +dst+ are given,
13374 * the entire source stream is copied:
13375 *
13376 * # Paths.
13377 * IO.copy_stream('t.txt', 't.tmp') # => 47
13378 *
13379 * # IOs (recall that a File is also an IO).
13380 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13381 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13382 * IO.copy_stream(src_io, dst_io) # => 47
13383 * src_io.close
13384 * dst_io.close
13385 *
13386 * With argument +src_length+ a non-negative integer,
13387 * no more than that many bytes are copied:
13388 *
13389 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13390 * File.read('t.tmp') # => "First line"
13391 *
13392 * With argument +src_offset+ also given,
13393 * the source stream is read beginning at that offset:
13394 *
13395 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13396 * IO.read('t.tmp') # => "Second line"
13397 *
13398 */
13399static VALUE
13400rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13401{
13402 VALUE src, dst, length, src_offset;
13403 struct copy_stream_struct st;
13404
13405 MEMZERO(&st, struct copy_stream_struct, 1);
13406
13407 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13408
13409 st.src = src;
13410 st.dst = dst;
13411
13412 st.src_fptr = NULL;
13413 st.dst_fptr = NULL;
13414
13415 if (NIL_P(length))
13416 st.copy_length = (rb_off_t)-1;
13417 else
13418 st.copy_length = NUM2OFFT(length);
13419
13420 if (NIL_P(src_offset))
13421 st.src_offset = (rb_off_t)-1;
13422 else
13423 st.src_offset = NUM2OFFT(src_offset);
13424
13425 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13426
13427 return OFFT2NUM(st.total);
13428}
13429
13430/*
13431 * call-seq:
13432 * external_encoding -> encoding or nil
13433 *
13434 * Returns the Encoding object that represents the encoding of the stream,
13435 * or +nil+ if the stream is in write mode and no encoding is specified.
13436 *
13437 * See {Encodings}[rdoc-ref:File@Encodings].
13438 *
13439 */
13440
13441static VALUE
13442rb_io_external_encoding(VALUE io)
13443{
13444 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13445
13446 if (fptr->encs.enc2) {
13447 return rb_enc_from_encoding(fptr->encs.enc2);
13448 }
13449 if (fptr->mode & FMODE_WRITABLE) {
13450 if (fptr->encs.enc)
13451 return rb_enc_from_encoding(fptr->encs.enc);
13452 return Qnil;
13453 }
13454 return rb_enc_from_encoding(io_read_encoding(fptr));
13455}
13456
13457/*
13458 * call-seq:
13459 * internal_encoding -> encoding or nil
13460 *
13461 * Returns the Encoding object that represents the encoding of the internal string,
13462 * if conversion is specified,
13463 * or +nil+ otherwise.
13464 *
13465 * See {Encodings}[rdoc-ref:File@Encodings].
13466 *
13467 */
13468
13469static VALUE
13470rb_io_internal_encoding(VALUE io)
13471{
13472 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13473
13474 if (!fptr->encs.enc2) return Qnil;
13475 return rb_enc_from_encoding(io_read_encoding(fptr));
13476}
13477
13478/*
13479 * call-seq:
13480 * set_encoding(ext_enc) -> self
13481 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13482 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13483 *
13484 * See {Encodings}[rdoc-ref:File@Encodings].
13485 *
13486 * Argument +ext_enc+, if given, must be an Encoding object
13487 * or a String with the encoding name;
13488 * it is assigned as the encoding for the stream.
13489 *
13490 * Argument +int_enc+, if given, must be an Encoding object
13491 * or a String with the encoding name;
13492 * it is assigned as the encoding for the internal string.
13493 *
13494 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13495 * containing two colon-separated encoding names;
13496 * corresponding Encoding objects are assigned as the external
13497 * and internal encodings for the stream.
13498 *
13499 * If the external encoding of a string is binary/ASCII-8BIT,
13500 * the internal encoding of the string is set to nil, since no
13501 * transcoding is needed.
13502 *
13503 * Optional keyword arguments +enc_opts+ specify
13504 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13505 *
13506 */
13507
13508static VALUE
13509rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13510{
13511 rb_io_t *fptr;
13512 VALUE v1, v2, opt;
13513
13514 if (!RB_TYPE_P(io, T_FILE)) {
13515 return forward(io, id_set_encoding, argc, argv);
13516 }
13517
13518 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13519 GetOpenFile(io, fptr);
13520 io_encoding_set(fptr, v1, v2, opt);
13521 return io;
13522}
13523
13524void
13525rb_stdio_set_default_encoding(void)
13526{
13527 VALUE val = Qnil;
13528
13529#ifdef _WIN32
13530 if (isatty(fileno(stdin))) {
13531 rb_encoding *external = rb_locale_encoding();
13532 rb_encoding *internal = rb_default_internal_encoding();
13533 if (!internal) internal = rb_default_external_encoding();
13534 io_encoding_set(RFILE(rb_stdin)->fptr,
13535 rb_enc_from_encoding(external),
13536 rb_enc_from_encoding(internal),
13537 Qnil);
13538 }
13539 else
13540#endif
13541 rb_io_set_encoding(1, &val, rb_stdin);
13542 rb_io_set_encoding(1, &val, rb_stdout);
13543 rb_io_set_encoding(1, &val, rb_stderr);
13544}
13545
13546static inline int
13547global_argf_p(VALUE arg)
13548{
13549 return arg == argf;
13550}
13551
13552typedef VALUE (*argf_encoding_func)(VALUE io);
13553
13554static VALUE
13555argf_encoding(VALUE argf, argf_encoding_func func)
13556{
13557 if (!RTEST(ARGF.current_file)) {
13558 return rb_enc_default_external();
13559 }
13560 return func(rb_io_check_io(ARGF.current_file));
13561}
13562
13563/*
13564 * call-seq:
13565 * ARGF.external_encoding -> encoding
13566 *
13567 * Returns the external encoding for files read from ARGF as an Encoding
13568 * object. The external encoding is the encoding of the text as stored in a
13569 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13570 * represent this text within Ruby.
13571 *
13572 * To set the external encoding use ARGF.set_encoding.
13573 *
13574 * For example:
13575 *
13576 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13577 *
13578 */
13579static VALUE
13580argf_external_encoding(VALUE argf)
13581{
13582 return argf_encoding(argf, rb_io_external_encoding);
13583}
13584
13585/*
13586 * call-seq:
13587 * ARGF.internal_encoding -> encoding
13588 *
13589 * Returns the internal encoding for strings read from ARGF as an
13590 * Encoding object.
13591 *
13592 * If ARGF.set_encoding has been called with two encoding names, the second
13593 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13594 * value is returned. Failing that, if a default external encoding was
13595 * specified on the command-line, that value is used. If the encoding is
13596 * unknown, +nil+ is returned.
13597 */
13598static VALUE
13599argf_internal_encoding(VALUE argf)
13600{
13601 return argf_encoding(argf, rb_io_internal_encoding);
13602}
13603
13604/*
13605 * call-seq:
13606 * ARGF.set_encoding(ext_enc) -> ARGF
13607 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13608 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13609 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13610 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13611 *
13612 * If single argument is specified, strings read from ARGF are tagged with
13613 * the encoding specified.
13614 *
13615 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13616 * the read string is converted from the first encoding (external encoding)
13617 * to the second encoding (internal encoding), then tagged with the second
13618 * encoding.
13619 *
13620 * If two arguments are specified, they must be encoding objects or encoding
13621 * names. Again, the first specifies the external encoding; the second
13622 * specifies the internal encoding.
13623 *
13624 * If the external encoding and the internal encoding are specified, the
13625 * optional Hash argument can be used to adjust the conversion process. The
13626 * structure of this hash is explained in the String#encode documentation.
13627 *
13628 * For example:
13629 *
13630 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13631 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13632 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13633 * # to UTF-8.
13634 */
13635static VALUE
13636argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13637{
13638 rb_io_t *fptr;
13639
13640 if (!next_argv()) {
13641 rb_raise(rb_eArgError, "no stream to set encoding");
13642 }
13643 rb_io_set_encoding(argc, argv, ARGF.current_file);
13644 GetOpenFile(ARGF.current_file, fptr);
13645 ARGF.encs = fptr->encs;
13646 return argf;
13647}
13648
13649/*
13650 * call-seq:
13651 * ARGF.tell -> Integer
13652 * ARGF.pos -> Integer
13653 *
13654 * Returns the current offset (in bytes) of the current file in ARGF.
13655 *
13656 * ARGF.pos #=> 0
13657 * ARGF.gets #=> "This is line one\n"
13658 * ARGF.pos #=> 17
13659 *
13660 */
13661static VALUE
13662argf_tell(VALUE argf)
13663{
13664 if (!next_argv()) {
13665 rb_raise(rb_eArgError, "no stream to tell");
13666 }
13667 ARGF_FORWARD(0, 0);
13668 return rb_io_tell(ARGF.current_file);
13669}
13670
13671/*
13672 * call-seq:
13673 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13674 *
13675 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13676 * the value of _whence_. See IO#seek for further details.
13677 */
13678static VALUE
13679argf_seek_m(int argc, VALUE *argv, VALUE argf)
13680{
13681 if (!next_argv()) {
13682 rb_raise(rb_eArgError, "no stream to seek");
13683 }
13684 ARGF_FORWARD(argc, argv);
13685 return rb_io_seek_m(argc, argv, ARGF.current_file);
13686}
13687
13688/*
13689 * call-seq:
13690 * ARGF.pos = position -> Integer
13691 *
13692 * Seeks to the position given by _position_ (in bytes) in ARGF.
13693 *
13694 * For example:
13695 *
13696 * ARGF.pos = 17
13697 * ARGF.gets #=> "This is line two\n"
13698 */
13699static VALUE
13700argf_set_pos(VALUE argf, VALUE offset)
13701{
13702 if (!next_argv()) {
13703 rb_raise(rb_eArgError, "no stream to set position");
13704 }
13705 ARGF_FORWARD(1, &offset);
13706 return rb_io_set_pos(ARGF.current_file, offset);
13707}
13708
13709/*
13710 * call-seq:
13711 * ARGF.rewind -> 0
13712 *
13713 * Positions the current file to the beginning of input, resetting
13714 * ARGF.lineno to zero.
13715 *
13716 * ARGF.readline #=> "This is line one\n"
13717 * ARGF.rewind #=> 0
13718 * ARGF.lineno #=> 0
13719 * ARGF.readline #=> "This is line one\n"
13720 */
13721static VALUE
13722argf_rewind(VALUE argf)
13723{
13724 VALUE ret;
13725 int old_lineno;
13726
13727 if (!next_argv()) {
13728 rb_raise(rb_eArgError, "no stream to rewind");
13729 }
13730 ARGF_FORWARD(0, 0);
13731 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13732 ret = rb_io_rewind(ARGF.current_file);
13733 if (!global_argf_p(argf)) {
13734 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13735 }
13736 return ret;
13737}
13738
13739/*
13740 * call-seq:
13741 * ARGF.fileno -> integer
13742 * ARGF.to_i -> integer
13743 *
13744 * Returns an integer representing the numeric file descriptor for
13745 * the current file. Raises an ArgumentError if there isn't a current file.
13746 *
13747 * ARGF.fileno #=> 3
13748 */
13749static VALUE
13750argf_fileno(VALUE argf)
13751{
13752 if (!next_argv()) {
13753 rb_raise(rb_eArgError, "no stream");
13754 }
13755 ARGF_FORWARD(0, 0);
13756 return rb_io_fileno(ARGF.current_file);
13757}
13758
13759/*
13760 * call-seq:
13761 * ARGF.to_io -> IO
13762 *
13763 * Returns an IO object representing the current file. This will be a
13764 * File object unless the current file is a stream such as STDIN.
13765 *
13766 * For example:
13767 *
13768 * ARGF.to_io #=> #<File:glark.txt>
13769 * ARGF.to_io #=> #<IO:<STDIN>>
13770 */
13771static VALUE
13772argf_to_io(VALUE argf)
13773{
13774 next_argv();
13775 ARGF_FORWARD(0, 0);
13776 return ARGF.current_file;
13777}
13778
13779/*
13780 * call-seq:
13781 * ARGF.eof? -> true or false
13782 * ARGF.eof -> true or false
13783 *
13784 * Returns true if the current file in ARGF is at end of file, i.e. it has
13785 * no data to read. The stream must be opened for reading or an IOError
13786 * will be raised.
13787 *
13788 * $ echo "eof" | ruby argf.rb
13789 *
13790 * ARGF.eof? #=> false
13791 * 3.times { ARGF.readchar }
13792 * ARGF.eof? #=> false
13793 * ARGF.readchar #=> "\n"
13794 * ARGF.eof? #=> true
13795 */
13796
13797static VALUE
13798argf_eof(VALUE argf)
13799{
13800 next_argv();
13801 if (RTEST(ARGF.current_file)) {
13802 if (ARGF.init_p == 0) return Qtrue;
13803 next_argv();
13804 ARGF_FORWARD(0, 0);
13805 if (rb_io_eof(ARGF.current_file)) {
13806 return Qtrue;
13807 }
13808 }
13809 return Qfalse;
13810}
13811
13812/*
13813 * call-seq:
13814 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13815 *
13816 * Reads _length_ bytes from ARGF. The files named on the command line
13817 * are concatenated and treated as a single file by this method, so when
13818 * called without arguments the contents of this pseudo file are returned in
13819 * their entirety.
13820 *
13821 * _length_ must be a non-negative integer or +nil+.
13822 *
13823 * If _length_ is a positive integer, +read+ tries to read
13824 * _length_ bytes without any conversion (binary mode).
13825 * It returns +nil+ if an EOF is encountered before anything can be read.
13826 * Fewer than _length_ bytes are returned if an EOF is encountered during
13827 * the read.
13828 * In the case of an integer _length_, the resulting string is always
13829 * in ASCII-8BIT encoding.
13830 *
13831 * If _length_ is omitted or is +nil+, it reads until EOF
13832 * and the encoding conversion is applied, if applicable.
13833 * A string is returned even if EOF is encountered before any data is read.
13834 *
13835 * If _length_ is zero, it returns an empty string (<code>""</code>).
13836 *
13837 * If the optional _outbuf_ argument is present,
13838 * it must reference a String, which will receive the data.
13839 * The _outbuf_ will contain only the received data after the method call
13840 * even if it is not empty at the beginning.
13841 *
13842 * For example:
13843 *
13844 * $ echo "small" > small.txt
13845 * $ echo "large" > large.txt
13846 * $ ./glark.rb small.txt large.txt
13847 *
13848 * ARGF.read #=> "small\nlarge"
13849 * ARGF.read(200) #=> "small\nlarge"
13850 * ARGF.read(2) #=> "sm"
13851 * ARGF.read(0) #=> ""
13852 *
13853 * Note that this method behaves like the fread() function in C.
13854 * This means it retries to invoke read(2) system calls to read data
13855 * with the specified length.
13856 * If you need the behavior like a single read(2) system call,
13857 * consider ARGF#readpartial or ARGF#read_nonblock.
13858 */
13859
13860static VALUE
13861argf_read(int argc, VALUE *argv, VALUE argf)
13862{
13863 VALUE tmp, str, length;
13864 long len = 0;
13865
13866 rb_scan_args(argc, argv, "02", &length, &str);
13867 if (!NIL_P(length)) {
13868 len = NUM2LONG(argv[0]);
13869 }
13870 if (!NIL_P(str)) {
13871 StringValue(str);
13872 rb_str_resize(str,0);
13873 argv[1] = Qnil;
13874 }
13875
13876 retry:
13877 if (!next_argv()) {
13878 return str;
13879 }
13880 if (ARGF_GENERIC_INPUT_P()) {
13881 tmp = argf_forward(argc, argv, argf);
13882 }
13883 else {
13884 tmp = io_read(argc, argv, ARGF.current_file);
13885 }
13886 if (NIL_P(str)) str = tmp;
13887 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13888 if (NIL_P(tmp) || NIL_P(length)) {
13889 if (ARGF.next_p != -1) {
13890 argf_close(argf);
13891 ARGF.next_p = 1;
13892 goto retry;
13893 }
13894 }
13895 else if (argc >= 1) {
13896 long slen = RSTRING_LEN(str);
13897 if (slen < len) {
13898 argv[0] = LONG2NUM(len - slen);
13899 goto retry;
13900 }
13901 }
13902 return str;
13903}
13904
13906 int argc;
13907 VALUE *argv;
13908 VALUE argf;
13909};
13910
13911static VALUE
13912argf_forward_call(VALUE arg)
13913{
13914 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13915 argf_forward(p->argc, p->argv, p->argf);
13916 return Qnil;
13917}
13918
13919static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13920 int nonblock);
13921
13922/*
13923 * call-seq:
13924 * ARGF.readpartial(maxlen) -> string
13925 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13926 *
13927 * Reads at most _maxlen_ bytes from the ARGF stream.
13928 *
13929 * If the optional _outbuf_ argument is present,
13930 * it must reference a String, which will receive the data.
13931 * The _outbuf_ will contain only the received data after the method call
13932 * even if it is not empty at the beginning.
13933 *
13934 * It raises EOFError on end of ARGF stream.
13935 * Since ARGF stream is a concatenation of multiple files,
13936 * internally EOF is occur for each file.
13937 * ARGF.readpartial returns empty strings for EOFs except the last one and
13938 * raises EOFError for the last one.
13939 *
13940 */
13941
13942static VALUE
13943argf_readpartial(int argc, VALUE *argv, VALUE argf)
13944{
13945 return argf_getpartial(argc, argv, argf, Qnil, 0);
13946}
13947
13948/*
13949 * call-seq:
13950 * ARGF.read_nonblock(maxlen[, options]) -> string
13951 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13952 *
13953 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13954 */
13955
13956static VALUE
13957argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13958{
13959 VALUE opts;
13960
13961 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13962
13963 if (!NIL_P(opts))
13964 argc--;
13965
13966 return argf_getpartial(argc, argv, argf, opts, 1);
13967}
13968
13969static VALUE
13970argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13971{
13972 VALUE tmp, str, length;
13973 int no_exception;
13974
13975 rb_scan_args(argc, argv, "11", &length, &str);
13976 if (!NIL_P(str)) {
13977 StringValue(str);
13978 argv[1] = str;
13979 }
13980 no_exception = no_exception_p(opts);
13981
13982 if (!next_argv()) {
13983 if (!NIL_P(str)) {
13984 rb_str_resize(str, 0);
13985 }
13986 rb_eof_error();
13987 }
13988 if (ARGF_GENERIC_INPUT_P()) {
13989 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13990 struct argf_call_arg arg;
13991 arg.argc = argc;
13992 arg.argv = argv;
13993 arg.argf = argf;
13994 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
13995 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
13996 }
13997 else {
13998 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13999 }
14000 if (NIL_P(tmp)) {
14001 if (ARGF.next_p == -1) {
14002 return io_nonblock_eof(no_exception);
14003 }
14004 argf_close(argf);
14005 ARGF.next_p = 1;
14006 if (RARRAY_LEN(ARGF.argv) == 0) {
14007 return io_nonblock_eof(no_exception);
14008 }
14009 if (NIL_P(str))
14010 str = rb_str_new(NULL, 0);
14011 return str;
14012 }
14013 return tmp;
14014}
14015
14016/*
14017 * call-seq:
14018 * ARGF.getc -> String or nil
14019 *
14020 * Reads the next character from ARGF and returns it as a String. Returns
14021 * +nil+ at the end of the stream.
14022 *
14023 * ARGF treats the files named on the command line as a single file created
14024 * by concatenating their contents. After returning the last character of the
14025 * first file, it returns the first character of the second file, and so on.
14026 *
14027 * For example:
14028 *
14029 * $ echo "foo" > file
14030 * $ ruby argf.rb file
14031 *
14032 * ARGF.getc #=> "f"
14033 * ARGF.getc #=> "o"
14034 * ARGF.getc #=> "o"
14035 * ARGF.getc #=> "\n"
14036 * ARGF.getc #=> nil
14037 * ARGF.getc #=> nil
14038 */
14039static VALUE
14040argf_getc(VALUE argf)
14041{
14042 VALUE ch;
14043
14044 retry:
14045 if (!next_argv()) return Qnil;
14046 if (ARGF_GENERIC_INPUT_P()) {
14047 ch = forward_current(rb_intern("getc"), 0, 0);
14048 }
14049 else {
14050 ch = rb_io_getc(ARGF.current_file);
14051 }
14052 if (NIL_P(ch) && ARGF.next_p != -1) {
14053 argf_close(argf);
14054 ARGF.next_p = 1;
14055 goto retry;
14056 }
14057
14058 return ch;
14059}
14060
14061/*
14062 * call-seq:
14063 * ARGF.getbyte -> Integer or nil
14064 *
14065 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14066 * the end of the stream.
14067 *
14068 * For example:
14069 *
14070 * $ echo "foo" > file
14071 * $ ruby argf.rb file
14072 *
14073 * ARGF.getbyte #=> 102
14074 * ARGF.getbyte #=> 111
14075 * ARGF.getbyte #=> 111
14076 * ARGF.getbyte #=> 10
14077 * ARGF.getbyte #=> nil
14078 */
14079static VALUE
14080argf_getbyte(VALUE argf)
14081{
14082 VALUE ch;
14083
14084 retry:
14085 if (!next_argv()) return Qnil;
14086 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14087 ch = forward_current(rb_intern("getbyte"), 0, 0);
14088 }
14089 else {
14090 ch = rb_io_getbyte(ARGF.current_file);
14091 }
14092 if (NIL_P(ch) && ARGF.next_p != -1) {
14093 argf_close(argf);
14094 ARGF.next_p = 1;
14095 goto retry;
14096 }
14097
14098 return ch;
14099}
14100
14101/*
14102 * call-seq:
14103 * ARGF.readchar -> String or nil
14104 *
14105 * Reads the next character from ARGF and returns it as a String. Raises
14106 * an EOFError after the last character of the last file has been read.
14107 *
14108 * For example:
14109 *
14110 * $ echo "foo" > file
14111 * $ ruby argf.rb file
14112 *
14113 * ARGF.readchar #=> "f"
14114 * ARGF.readchar #=> "o"
14115 * ARGF.readchar #=> "o"
14116 * ARGF.readchar #=> "\n"
14117 * ARGF.readchar #=> end of file reached (EOFError)
14118 */
14119static VALUE
14120argf_readchar(VALUE argf)
14121{
14122 VALUE ch;
14123
14124 retry:
14125 if (!next_argv()) rb_eof_error();
14126 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14127 ch = forward_current(rb_intern("getc"), 0, 0);
14128 }
14129 else {
14130 ch = rb_io_getc(ARGF.current_file);
14131 }
14132 if (NIL_P(ch) && ARGF.next_p != -1) {
14133 argf_close(argf);
14134 ARGF.next_p = 1;
14135 goto retry;
14136 }
14137
14138 return ch;
14139}
14140
14141/*
14142 * call-seq:
14143 * ARGF.readbyte -> Integer
14144 *
14145 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14146 * an EOFError after the last byte of the last file has been read.
14147 *
14148 * For example:
14149 *
14150 * $ echo "foo" > file
14151 * $ ruby argf.rb file
14152 *
14153 * ARGF.readbyte #=> 102
14154 * ARGF.readbyte #=> 111
14155 * ARGF.readbyte #=> 111
14156 * ARGF.readbyte #=> 10
14157 * ARGF.readbyte #=> end of file reached (EOFError)
14158 */
14159static VALUE
14160argf_readbyte(VALUE argf)
14161{
14162 VALUE c;
14163
14164 NEXT_ARGF_FORWARD(0, 0);
14165 c = argf_getbyte(argf);
14166 if (NIL_P(c)) {
14167 rb_eof_error();
14168 }
14169 return c;
14170}
14171
14172#define FOREACH_ARGF() while (next_argv())
14173
14174static VALUE
14175argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14176{
14177 const VALUE current = ARGF.current_file;
14178 rb_yield_values2(argc, argv);
14179 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14181 }
14182 return Qnil;
14183}
14184
14185#define ARGF_block_call(mid, argc, argv, func, argf) \
14186 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14187 func, argf, rb_keyword_given_p())
14188
14189static void
14190argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14191{
14192 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14193 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14194}
14195
14196static VALUE
14197argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14198{
14199 if (!global_argf_p(argf)) {
14200 ARGF.last_lineno = ++ARGF.lineno;
14201 }
14202 return argf_block_call_i(i, argf, argc, argv, blockarg);
14203}
14204
14205static void
14206argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14207{
14208 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14209 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14210}
14211
14212/*
14213 * call-seq:
14214 * ARGF.each(sep=$/) {|line| block } -> ARGF
14215 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14216 * ARGF.each(...) -> an_enumerator
14217 *
14218 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14219 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14220 * ARGF.each_line(...) -> an_enumerator
14221 *
14222 * Returns an enumerator which iterates over each line (separated by _sep_,
14223 * which defaults to your platform's newline character) of each file in
14224 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14225 * block, otherwise an enumerator is returned.
14226 * The optional _limit_ argument is an Integer specifying the maximum
14227 * length of each line; longer lines will be split according to this limit.
14228 *
14229 * This method allows you to treat the files supplied on the command line as
14230 * a single file consisting of the concatenation of each named file. After
14231 * the last line of the first file has been returned, the first line of the
14232 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14233 * used to determine the filename of the current line and line number of the
14234 * whole input, respectively.
14235 *
14236 * For example, the following code prints out each line of each named file
14237 * prefixed with its line number, displaying the filename once per file:
14238 *
14239 * ARGF.each_line do |line|
14240 * puts ARGF.filename if ARGF.file.lineno == 1
14241 * puts "#{ARGF.file.lineno}: #{line}"
14242 * end
14243 *
14244 * While the following code prints only the first file's name at first, and
14245 * the contents with line number counted through all named files.
14246 *
14247 * ARGF.each_line do |line|
14248 * puts ARGF.filename if ARGF.lineno == 1
14249 * puts "#{ARGF.lineno}: #{line}"
14250 * end
14251 */
14252static VALUE
14253argf_each_line(int argc, VALUE *argv, VALUE argf)
14254{
14255 RETURN_ENUMERATOR(argf, argc, argv);
14256 FOREACH_ARGF() {
14257 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14258 }
14259 return argf;
14260}
14261
14262/*
14263 * call-seq:
14264 * ARGF.each_byte {|byte| block } -> ARGF
14265 * ARGF.each_byte -> an_enumerator
14266 *
14267 * Iterates over each byte of each file in +ARGV+.
14268 * A byte is returned as an Integer in the range 0..255.
14269 *
14270 * This method allows you to treat the files supplied on the command line as
14271 * a single file consisting of the concatenation of each named file. After
14272 * the last byte of the first file has been returned, the first byte of the
14273 * second file is returned. The ARGF.filename method can be used to
14274 * determine the filename of the current byte.
14275 *
14276 * If no block is given, an enumerator is returned instead.
14277 *
14278 * For example:
14279 *
14280 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14281 *
14282 */
14283static VALUE
14284argf_each_byte(VALUE argf)
14285{
14286 RETURN_ENUMERATOR(argf, 0, 0);
14287 FOREACH_ARGF() {
14288 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14289 }
14290 return argf;
14291}
14292
14293/*
14294 * call-seq:
14295 * ARGF.each_char {|char| block } -> ARGF
14296 * ARGF.each_char -> an_enumerator
14297 *
14298 * Iterates over each character of each file in ARGF.
14299 *
14300 * This method allows you to treat the files supplied on the command line as
14301 * a single file consisting of the concatenation of each named file. After
14302 * the last character of the first file has been returned, the first
14303 * character of the second file is returned. The ARGF.filename method can
14304 * be used to determine the name of the file in which the current character
14305 * appears.
14306 *
14307 * If no block is given, an enumerator is returned instead.
14308 */
14309static VALUE
14310argf_each_char(VALUE argf)
14311{
14312 RETURN_ENUMERATOR(argf, 0, 0);
14313 FOREACH_ARGF() {
14314 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14315 }
14316 return argf;
14317}
14318
14319/*
14320 * call-seq:
14321 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14322 * ARGF.each_codepoint -> an_enumerator
14323 *
14324 * Iterates over each codepoint of each file in ARGF.
14325 *
14326 * This method allows you to treat the files supplied on the command line as
14327 * a single file consisting of the concatenation of each named file. After
14328 * the last codepoint of the first file has been returned, the first
14329 * codepoint of the second file is returned. The ARGF.filename method can
14330 * be used to determine the name of the file in which the current codepoint
14331 * appears.
14332 *
14333 * If no block is given, an enumerator is returned instead.
14334 */
14335static VALUE
14336argf_each_codepoint(VALUE argf)
14337{
14338 RETURN_ENUMERATOR(argf, 0, 0);
14339 FOREACH_ARGF() {
14340 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14341 }
14342 return argf;
14343}
14344
14345/*
14346 * call-seq:
14347 * ARGF.filename -> String
14348 * ARGF.path -> String
14349 *
14350 * Returns the current filename. "-" is returned when the current file is
14351 * STDIN.
14352 *
14353 * For example:
14354 *
14355 * $ echo "foo" > foo
14356 * $ echo "bar" > bar
14357 * $ echo "glark" > glark
14358 *
14359 * $ ruby argf.rb foo bar glark
14360 *
14361 * ARGF.filename #=> "foo"
14362 * ARGF.read(5) #=> "foo\nb"
14363 * ARGF.filename #=> "bar"
14364 * ARGF.skip
14365 * ARGF.filename #=> "glark"
14366 */
14367static VALUE
14368argf_filename(VALUE argf)
14369{
14370 next_argv();
14371 return ARGF.filename;
14372}
14373
14374static VALUE
14375argf_filename_getter(ID id, VALUE *var)
14376{
14377 return argf_filename(*var);
14378}
14379
14380/*
14381 * call-seq:
14382 * ARGF.file -> IO or File object
14383 *
14384 * Returns the current file as an IO or File object.
14385 * <code>$stdin</code> is returned when the current file is STDIN.
14386 *
14387 * For example:
14388 *
14389 * $ echo "foo" > foo
14390 * $ echo "bar" > bar
14391 *
14392 * $ ruby argf.rb foo bar
14393 *
14394 * ARGF.file #=> #<File:foo>
14395 * ARGF.read(5) #=> "foo\nb"
14396 * ARGF.file #=> #<File:bar>
14397 */
14398static VALUE
14399argf_file(VALUE argf)
14400{
14401 next_argv();
14402 return ARGF.current_file;
14403}
14404
14405/*
14406 * call-seq:
14407 * ARGF.binmode -> ARGF
14408 *
14409 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14410 * be reset to non-binary mode. This option has the following effects:
14411 *
14412 * * Newline conversion is disabled.
14413 * * Encoding conversion is disabled.
14414 * * Content is treated as ASCII-8BIT.
14415 */
14416static VALUE
14417argf_binmode_m(VALUE argf)
14418{
14419 ARGF.binmode = 1;
14420 next_argv();
14421 ARGF_FORWARD(0, 0);
14422 rb_io_ascii8bit_binmode(ARGF.current_file);
14423 return argf;
14424}
14425
14426/*
14427 * call-seq:
14428 * ARGF.binmode? -> true or false
14429 *
14430 * Returns true if ARGF is being read in binary mode; false otherwise.
14431 * To enable binary mode use ARGF.binmode.
14432 *
14433 * For example:
14434 *
14435 * ARGF.binmode? #=> false
14436 * ARGF.binmode
14437 * ARGF.binmode? #=> true
14438 */
14439static VALUE
14440argf_binmode_p(VALUE argf)
14441{
14442 return RBOOL(ARGF.binmode);
14443}
14444
14445/*
14446 * call-seq:
14447 * ARGF.skip -> ARGF
14448 *
14449 * Sets the current file to the next file in ARGV. If there aren't any more
14450 * files it has no effect.
14451 *
14452 * For example:
14453 *
14454 * $ ruby argf.rb foo bar
14455 * ARGF.filename #=> "foo"
14456 * ARGF.skip
14457 * ARGF.filename #=> "bar"
14458 */
14459static VALUE
14460argf_skip(VALUE argf)
14461{
14462 if (ARGF.init_p && ARGF.next_p == 0) {
14463 argf_close(argf);
14464 ARGF.next_p = 1;
14465 }
14466 return argf;
14467}
14468
14469/*
14470 * call-seq:
14471 * ARGF.close -> ARGF
14472 *
14473 * Closes the current file and skips to the next file in ARGV. If there are
14474 * no more files to open, just closes the current file. STDIN will not be
14475 * closed.
14476 *
14477 * For example:
14478 *
14479 * $ ruby argf.rb foo bar
14480 *
14481 * ARGF.filename #=> "foo"
14482 * ARGF.close
14483 * ARGF.filename #=> "bar"
14484 * ARGF.close
14485 */
14486static VALUE
14487argf_close_m(VALUE argf)
14488{
14489 next_argv();
14490 argf_close(argf);
14491 if (ARGF.next_p != -1) {
14492 ARGF.next_p = 1;
14493 }
14494 ARGF.lineno = 0;
14495 return argf;
14496}
14497
14498/*
14499 * call-seq:
14500 * ARGF.closed? -> true or false
14501 *
14502 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14503 * ARGF.close to actually close the current file.
14504 */
14505static VALUE
14506argf_closed(VALUE argf)
14507{
14508 next_argv();
14509 ARGF_FORWARD(0, 0);
14510 return rb_io_closed_p(ARGF.current_file);
14511}
14512
14513/*
14514 * call-seq:
14515 * ARGF.to_s -> String
14516 *
14517 * Returns "ARGF".
14518 */
14519static VALUE
14520argf_to_s(VALUE argf)
14521{
14522 return rb_str_new2("ARGF");
14523}
14524
14525/*
14526 * call-seq:
14527 * ARGF.inplace_mode -> String
14528 *
14529 * Returns the file extension appended to the names of backup copies of
14530 * modified files under in-place edit mode. This value can be set using
14531 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14532 */
14533static VALUE
14534argf_inplace_mode_get(VALUE argf)
14535{
14536 if (!ARGF.inplace) return Qnil;
14537 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14538 return rb_str_dup(ARGF.inplace);
14539}
14540
14541static VALUE
14542opt_i_get(ID id, VALUE *var)
14543{
14544 return argf_inplace_mode_get(*var);
14545}
14546
14547/*
14548 * call-seq:
14549 * ARGF.inplace_mode = ext -> ARGF
14550 *
14551 * Sets the filename extension for in-place editing mode to the given String.
14552 * The backup copy of each file being edited has this value appended to its
14553 * filename.
14554 *
14555 * For example:
14556 *
14557 * $ ruby argf.rb file.txt
14558 *
14559 * ARGF.inplace_mode = '.bak'
14560 * ARGF.each_line do |line|
14561 * print line.sub("foo","bar")
14562 * end
14563 *
14564 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14565 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14566 * "bar".
14567 */
14568static VALUE
14569argf_inplace_mode_set(VALUE argf, VALUE val)
14570{
14571 if (!RTEST(val)) {
14572 ARGF.inplace = Qfalse;
14573 }
14574 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14575 ARGF.inplace = Qnil;
14576 }
14577 else {
14578 ARGF.inplace = rb_str_new_frozen(val);
14579 }
14580 return argf;
14581}
14582
14583static void
14584opt_i_set(VALUE val, ID id, VALUE *var)
14585{
14586 argf_inplace_mode_set(*var, val);
14587}
14588
14589void
14590ruby_set_inplace_mode(const char *suffix)
14591{
14592 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14593}
14594
14595/*
14596 * call-seq:
14597 * ARGF.argv -> ARGV
14598 *
14599 * Returns the +ARGV+ array, which contains the arguments passed to your
14600 * script, one per element.
14601 *
14602 * For example:
14603 *
14604 * $ ruby argf.rb -v glark.txt
14605 *
14606 * ARGF.argv #=> ["-v", "glark.txt"]
14607 *
14608 */
14609static VALUE
14610argf_argv(VALUE argf)
14611{
14612 return ARGF.argv;
14613}
14614
14615static VALUE
14616argf_argv_getter(ID id, VALUE *var)
14617{
14618 return argf_argv(*var);
14619}
14620
14621VALUE
14623{
14624 return ARGF.argv;
14625}
14626
14627/*
14628 * call-seq:
14629 * ARGF.to_write_io -> io
14630 *
14631 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14632 * enabled.
14633 */
14634static VALUE
14635argf_write_io(VALUE argf)
14636{
14637 if (!RTEST(ARGF.current_file)) {
14638 rb_raise(rb_eIOError, "not opened for writing");
14639 }
14640 return GetWriteIO(ARGF.current_file);
14641}
14642
14643/*
14644 * call-seq:
14645 * ARGF.write(*objects) -> integer
14646 *
14647 * Writes each of the given +objects+ if inplace mode.
14648 */
14649static VALUE
14650argf_write(int argc, VALUE *argv, VALUE argf)
14651{
14652 return rb_io_writev(argf_write_io(argf), argc, argv);
14653}
14654
14655void
14656rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14657{
14658 rb_readwrite_syserr_fail(waiting, errno, mesg);
14659}
14660
14661void
14662rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14663{
14664 VALUE arg, c = Qnil;
14665 arg = mesg ? rb_str_new2(mesg) : Qnil;
14666 switch (waiting) {
14667 case RB_IO_WAIT_WRITABLE:
14668 switch (n) {
14669 case EAGAIN:
14670 c = rb_eEAGAINWaitWritable;
14671 break;
14672#if EAGAIN != EWOULDBLOCK
14673 case EWOULDBLOCK:
14674 c = rb_eEWOULDBLOCKWaitWritable;
14675 break;
14676#endif
14677 case EINPROGRESS:
14678 c = rb_eEINPROGRESSWaitWritable;
14679 break;
14680 default:
14682 }
14683 break;
14684 case RB_IO_WAIT_READABLE:
14685 switch (n) {
14686 case EAGAIN:
14687 c = rb_eEAGAINWaitReadable;
14688 break;
14689#if EAGAIN != EWOULDBLOCK
14690 case EWOULDBLOCK:
14691 c = rb_eEWOULDBLOCKWaitReadable;
14692 break;
14693#endif
14694 case EINPROGRESS:
14695 c = rb_eEINPROGRESSWaitReadable;
14696 break;
14697 default:
14699 }
14700 break;
14701 default:
14702 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14703 }
14705}
14706
14707static VALUE
14708get_LAST_READ_LINE(ID _x, VALUE *_y)
14709{
14710 return rb_lastline_get();
14711}
14712
14713static void
14714set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14715{
14716 rb_lastline_set(val);
14717}
14718
14719/*
14720 * Document-class: IOError
14721 *
14722 * Raised when an IO operation fails.
14723 *
14724 * File.open("/etc/hosts") {|f| f << "example"}
14725 * #=> IOError: not opened for writing
14726 *
14727 * File.open("/etc/hosts") {|f| f.close; f.read }
14728 * #=> IOError: closed stream
14729 *
14730 * Note that some IO failures raise <code>SystemCallError</code>s
14731 * and these are not subclasses of IOError:
14732 *
14733 * File.open("does/not/exist")
14734 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14735 */
14736
14737/*
14738 * Document-class: EOFError
14739 *
14740 * Raised by some IO operations when reaching the end of file. Many IO
14741 * methods exist in two forms,
14742 *
14743 * one that returns +nil+ when the end of file is reached, the other
14744 * raises EOFError.
14745 *
14746 * EOFError is a subclass of IOError.
14747 *
14748 * file = File.open("/etc/hosts")
14749 * file.read
14750 * file.gets #=> nil
14751 * file.readline #=> EOFError: end of file reached
14752 * file.close
14753 */
14754
14755/*
14756 * Document-class: ARGF
14757 *
14758 * == \ARGF and +ARGV+
14759 *
14760 * The \ARGF object works with the array at global variable +ARGV+
14761 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14762 *
14763 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14764 *
14765 * Initially, it contains the command-line arguments and options
14766 * that are passed to the Ruby program;
14767 * the program can modify that array as it likes.
14768 *
14769 * - **ARGF** may be thought of as the <b>argument files</b> object.
14770 *
14771 * It can access file streams and/or the <tt>$stdin</tt> stream,
14772 * based on what it finds in +ARGV+.
14773 * This provides a convenient way for the command line
14774 * to specify streams for a Ruby program to read.
14775 *
14776 * == Reading
14777 *
14778 * \ARGF may read from _source_ streams,
14779 * which at any particular time are determined by the content of +ARGV+.
14780 *
14781 * === Simplest Case
14782 *
14783 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14784 * the source is <tt>$stdin</tt>:
14785 *
14786 * - \File +t.rb+:
14787 *
14788 * p ['ARGV', ARGV]
14789 * p ['ARGF.read', ARGF.read]
14790 *
14791 * - Commands and outputs
14792 * (see below for the content of files +foo.txt+ and +bar.txt+):
14793 *
14794 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14795 * ["ARGV", []]
14796 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14797 *
14798 * $ cat foo.txt bar.txt | ruby t.rb
14799 * ["ARGV", []]
14800 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14801 *
14802 * === About the Examples
14803 *
14804 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14805 *
14806 * $ cat foo.txt
14807 * Foo 0
14808 * Foo 1
14809 * $ cat bar.txt
14810 * Bar 0
14811 * Bar 1
14812 * Bar 2
14813 * Bar 3
14814 *
14815 * === Sources in +ARGV+
14816 *
14817 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14818 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14819 * the sources are found in +ARGV+.
14820 *
14821 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14822 * and is one of:
14823 *
14824 * - The string path to a file that may be opened as a stream.
14825 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14826 *
14827 * Each element that is _not_ one of these
14828 * should be removed from +ARGV+ before \ARGF accesses that source.
14829 *
14830 * In the following example:
14831 *
14832 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14833 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14834 *
14835 * Example:
14836 *
14837 * - \File +t.rb+:
14838 *
14839 * # Print arguments (and options, if any) found on command line.
14840 * p ['ARGV', ARGV]
14841 *
14842 * - Command and output:
14843 *
14844 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14845 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14846 *
14847 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14848 *
14849 * - \File +t.rb+:
14850 *
14851 * p "ARGV: #{ARGV}"
14852 * p "Line: #{ARGF.read}" # Read everything from all specified streams.
14853 *
14854 * - Command and output:
14855 *
14856 * $ ruby t.rb foo.txt bar.txt
14857 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14858 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14859 *
14860 * Because the value at +ARGV+ is an ordinary array,
14861 * you can manipulate it to control which sources \ARGF considers:
14862 *
14863 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14864 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14865 *
14866 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14867 * when all sources have been accessed, the array is empty:
14868 *
14869 * - \File +t.rb+:
14870 *
14871 * until ARGV.empty? && ARGF.eof?
14872 * p "ARGV: #{ARGV}"
14873 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14874 * end
14875 *
14876 * - Command and output:
14877 *
14878 * $ ruby t.rb foo.txt bar.txt
14879 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14880 * "Line: Foo 0\n"
14881 * "ARGV: [\"bar.txt\"]"
14882 * "Line: Foo 1\n"
14883 * "ARGV: [\"bar.txt\"]"
14884 * "Line: Bar 0\n"
14885 * "ARGV: []"
14886 * "Line: Bar 1\n"
14887 * "ARGV: []"
14888 * "Line: Bar 2\n"
14889 * "ARGV: []"
14890 * "Line: Bar 3\n"
14891 *
14892 * ==== Filepaths in +ARGV+
14893 *
14894 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14895 *
14896 * This program prints what it reads from files at the paths specified
14897 * on the command line:
14898 *
14899 * - \File +t.rb+:
14900 *
14901 * p ['ARGV', ARGV]
14902 * # Read and print all content from the specified sources.
14903 * p ['ARGF.read', ARGF.read]
14904 *
14905 * - Command and output:
14906 *
14907 * $ ruby t.rb foo.txt bar.txt
14908 * ["ARGV", [foo.txt, bar.txt]
14909 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14910 *
14911 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14912 *
14913 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14914 *
14915 * - \File +t.rb+:
14916 *
14917 * p ['ARGV', ARGV]
14918 * p ['ARGF.read', ARGF.read]
14919 *
14920 * - Command and output:
14921 *
14922 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14923 * ["ARGV", ["-"]]
14924 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14925 *
14926 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14927 * (exception:
14928 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14929 *
14930 * - Command and output:
14931 *
14932 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14933 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14934 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14935 *
14936 * ==== Mixtures and Repetitions in +ARGV+
14937 *
14938 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14939 * and character <tt>'-'</tt>, including repetitions.
14940 *
14941 * ==== Modifications to +ARGV+
14942 *
14943 * The running Ruby program may make any modifications to the +ARGV+ array;
14944 * the current value of +ARGV+ affects \ARGF reading.
14945 *
14946 * ==== Empty +ARGV+
14947 *
14948 * For an empty +ARGV+, an \ARGF read method either returns +nil+
14949 * or raises an exception, depending on the specific method.
14950 *
14951 * === More Read Methods
14952 *
14953 * As seen above, method ARGF#read reads the content of all sources
14954 * into a single string.
14955 * Other \ARGF methods provide other ways to access that content;
14956 * these include:
14957 *
14958 * - Byte access: #each_byte, #getbyte, #readbyte.
14959 * - Character access: #each_char, #getc, #readchar.
14960 * - Codepoint access: #each_codepoint.
14961 * - Line access: #each_line, #gets, #readline, #readlines.
14962 * - Source access: #read, #read_nonblock, #readpartial.
14963 *
14964 * === About \Enumerable
14965 *
14966 * \ARGF includes module Enumerable.
14967 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
14968 *
14969 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
14970 * _not_ from +ARGV+;
14971 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
14972 * not an array of the strings from +ARGV+:
14973 *
14974 * - \File +t.rb+:
14975 *
14976 * p ['ARGV', ARGV]
14977 * p ['ARGF.entries', ARGF.entries]
14978 *
14979 * - Command and output:
14980 *
14981 * $ ruby t.rb foo.txt bar.txt
14982 * ["ARGV", ["foo.txt", "bar.txt"]]
14983 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
14984 *
14985 * == Writing
14986 *
14987 * If <i>inplace mode</i> is in effect,
14988 * \ARGF may write to target streams,
14989 * which at any particular time are determined by the content of ARGV.
14990 *
14991 * Methods about inplace mode:
14992 *
14993 * - #inplace_mode
14994 * - #inplace_mode=
14995 * - #to_write_io
14996 *
14997 * Methods for writing:
14998 *
14999 * - #print
15000 * - #printf
15001 * - #putc
15002 * - #puts
15003 * - #write
15004 *
15005 */
15006
15007/*
15008 * An instance of class \IO (commonly called a _stream_)
15009 * represents an input/output stream in the underlying operating system.
15010 * Class \IO is the basis for input and output in Ruby.
15011 *
15012 * Class File is the only class in the Ruby core that is a subclass of \IO.
15013 * Some classes in the Ruby standard library are also subclasses of \IO;
15014 * these include TCPSocket and UDPSocket.
15015 *
15016 * The global constant ARGF (also accessible as <tt>$<</tt>)
15017 * provides an IO-like stream that allows access to all file paths
15018 * found in ARGV (or found in STDIN if ARGV is empty).
15019 * ARGF is not itself a subclass of \IO.
15020 *
15021 * Class StringIO provides an IO-like stream that handles a String.
15022 * StringIO is not itself a subclass of \IO.
15023 *
15024 * Important objects based on \IO include:
15025 *
15026 * - $stdin.
15027 * - $stdout.
15028 * - $stderr.
15029 * - Instances of class File.
15030 *
15031 * An instance of \IO may be created using:
15032 *
15033 * - IO.new: returns a new \IO object for the given integer file descriptor.
15034 * - IO.open: passes a new \IO object to the given block.
15035 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15036 * of a newly-launched subprocess.
15037 * - Kernel#open: Returns a new \IO object connected to a given source:
15038 * stream, file, or subprocess.
15039 *
15040 * Like a File stream, an \IO stream has:
15041 *
15042 * - A read/write mode, which may be read-only, write-only, or read/write;
15043 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15044 * - A data mode, which may be text-only or binary;
15045 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15046 * - Internal and external encodings;
15047 * see {Encodings}[rdoc-ref:File@Encodings].
15048 *
15049 * And like other \IO streams, it has:
15050 *
15051 * - A position, which determines where in the stream the next
15052 * read or write is to occur;
15053 * see {Position}[rdoc-ref:IO@Position].
15054 * - A line number, which is a special, line-oriented, "position"
15055 * (different from the position mentioned above);
15056 * see {Line Number}[rdoc-ref:IO@Line+Number].
15057 *
15058 * == Extension <tt>io/console</tt>
15059 *
15060 * Extension <tt>io/console</tt> provides numerous methods
15061 * for interacting with the console;
15062 * requiring it adds numerous methods to class \IO.
15063 *
15064 * == Example Files
15065 *
15066 * Many examples here use these variables:
15067 *
15068 * :include: doc/examples/files.rdoc
15069 *
15070 * == Open Options
15071 *
15072 * A number of \IO methods accept optional keyword arguments
15073 * that determine how a new stream is to be opened:
15074 *
15075 * - +:mode+: Stream mode.
15076 * - +:flags+: Integer file open flags;
15077 * If +mode+ is also given, the two are bitwise-ORed.
15078 * - +:external_encoding+: External encoding for the stream.
15079 * - +:internal_encoding+: Internal encoding for the stream.
15080 * <tt>'-'</tt> is a synonym for the default internal encoding.
15081 * If the value is +nil+ no conversion occurs.
15082 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15083 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15084 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15085 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15086 * when the stream closes; otherwise it remains open.
15087 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15088 * #path method.
15089 *
15090 * Also available are the options offered in String#encode,
15091 * which may control conversion between external and internal encoding.
15092 *
15093 * == Basic \IO
15094 *
15095 * You can perform basic stream \IO with these methods,
15096 * which typically operate on multi-byte strings:
15097 *
15098 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15099 * - IO#write: Writes zero or more strings to the stream;
15100 * each given object that is not already a string is converted via +to_s+.
15101 *
15102 * === Position
15103 *
15104 * An \IO stream has a nonnegative integer _position_,
15105 * which is the byte offset at which the next read or write is to occur.
15106 * A new stream has position zero (and line number zero);
15107 * method +rewind+ resets the position (and line number) to zero.
15108 *
15109 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15110 * Encoding::Converter instances used for that \IO.
15111 *
15112 * The relevant methods:
15113 *
15114 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15115 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15116 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15117 * relative to a given position +whence+
15118 * (indicating the beginning, end, or current position).
15119 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15120 *
15121 * === Open and Closed Streams
15122 *
15123 * A new \IO stream may be open for reading, open for writing, or both.
15124 *
15125 * A stream is automatically closed when claimed by the garbage collector.
15126 *
15127 * Attempted reading or writing on a closed stream raises an exception.
15128 *
15129 * The relevant methods:
15130 *
15131 * - IO#close: Closes the stream for both reading and writing.
15132 * - IO#close_read: Closes the stream for reading.
15133 * - IO#close_write: Closes the stream for writing.
15134 * - IO#closed?: Returns whether the stream is closed.
15135 *
15136 * === End-of-Stream
15137 *
15138 * You can query whether a stream is positioned at its end:
15139 *
15140 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15141 *
15142 * You can reposition to end-of-stream by using method IO#seek:
15143 *
15144 * f = File.new('t.txt')
15145 * f.eof? # => false
15146 * f.seek(0, :END)
15147 * f.eof? # => true
15148 * f.close
15149 *
15150 * Or by reading all stream content (which is slower than using IO#seek):
15151 *
15152 * f.rewind
15153 * f.eof? # => false
15154 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15155 * f.eof? # => true
15156 *
15157 * == Line \IO
15158 *
15159 * Class \IO supports line-oriented
15160 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15161 *
15162 * === Line Input
15163 *
15164 * Class \IO supports line-oriented input for
15165 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15166 *
15167 * ==== \File Line Input
15168 *
15169 * You can read lines from a file using these methods:
15170 *
15171 * - IO.foreach: Reads each line and passes it to the given block.
15172 * - IO.readlines: Reads and returns all lines in an array.
15173 *
15174 * For each of these methods:
15175 *
15176 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15177 * - Line parsing depends on the effective <i>line separator</i>;
15178 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15179 * - The length of each returned line depends on the effective <i>line limit</i>;
15180 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15181 *
15182 * ==== Stream Line Input
15183 *
15184 * You can read lines from an \IO stream using these methods:
15185 *
15186 * - IO#each_line: Reads each remaining line, passing it to the given block.
15187 * - IO#gets: Returns the next line.
15188 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15189 * - IO#readlines: Returns all remaining lines in an array.
15190 *
15191 * For each of these methods:
15192 *
15193 * - Reading may begin mid-line,
15194 * depending on the stream's _position_;
15195 * see {Position}[rdoc-ref:IO@Position].
15196 * - Line parsing depends on the effective <i>line separator</i>;
15197 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15198 * - The length of each returned line depends on the effective <i>line limit</i>;
15199 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15200 *
15201 * ===== Line Separator
15202 *
15203 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15204 * the string that determines what is considered a line;
15205 * it is sometimes called the <i>input record separator</i>.
15206 *
15207 * The default line separator is taken from global variable <tt>$/</tt>,
15208 * whose initial value is <tt>"\n"</tt>.
15209 *
15210 * Generally, the line to be read next is all data
15211 * from the current {position}[rdoc-ref:IO@Position]
15212 * to the next line separator
15213 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15214 *
15215 * f = File.new('t.txt')
15216 * # Method gets with no sep argument returns the next line, according to $/.
15217 * f.gets # => "First line\n"
15218 * f.gets # => "Second line\n"
15219 * f.gets # => "\n"
15220 * f.gets # => "Fourth line\n"
15221 * f.gets # => "Fifth line\n"
15222 * f.close
15223 *
15224 * You can use a different line separator by passing argument +sep+:
15225 *
15226 * f = File.new('t.txt')
15227 * f.gets('l') # => "First l"
15228 * f.gets('li') # => "ine\nSecond li"
15229 * f.gets('lin') # => "ne\n\nFourth lin"
15230 * f.gets # => "e\n"
15231 * f.close
15232 *
15233 * Or by setting global variable <tt>$/</tt>:
15234 *
15235 * f = File.new('t.txt')
15236 * $/ = 'l'
15237 * f.gets # => "First l"
15238 * f.gets # => "ine\nSecond l"
15239 * f.gets # => "ine\n\nFourth l"
15240 * f.close
15241 *
15242 * ===== Special Line Separator Values
15243 *
15244 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15245 * accepts two special values for parameter +sep+:
15246 *
15247 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15248 *
15249 * f = File.new('t.txt')
15250 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15251 * f.close
15252 *
15253 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15254 * (paragraphs being separated by two consecutive line separators):
15255 *
15256 * f = File.new('t.txt')
15257 * f.gets('') # => "First line\nSecond line\n\n"
15258 * f.gets('') # => "Fourth line\nFifth line\n"
15259 * f.close
15260 *
15261 * ===== Line Limit
15262 *
15263 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15264 * uses an integer <i>line limit</i>,
15265 * which restricts the number of bytes that may be returned.
15266 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15267 * than the limit).
15268 *
15269 * The default limit value is <tt>-1</tt>;
15270 * any negative limit value means that there is no limit.
15271 *
15272 * If there is no limit, the line is determined only by +sep+.
15273 *
15274 * # Text with 1-byte characters.
15275 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15276 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15277 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15278 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15279 * # No more than one line.
15280 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15281 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15282 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15283 *
15284 * # Text with 2-byte characters, which will not be split.
15285 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15286 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15287 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15288 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15289 *
15290 * ===== Line Separator and Line Limit
15291 *
15292 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15293 *
15294 * - Returns the next line as determined by line separator +sep+.
15295 * - But returns no more bytes than are allowed by the limit +limit+.
15296 *
15297 * Example:
15298 *
15299 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15300 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15301 *
15302 * ===== Line Number
15303 *
15304 * A readable \IO stream has a non-negative integer <i>line number</i>:
15305 *
15306 * - IO#lineno: Returns the line number.
15307 * - IO#lineno=: Resets and returns the line number.
15308 *
15309 * Unless modified by a call to method IO#lineno=,
15310 * the line number is the number of lines read
15311 * by certain line-oriented methods,
15312 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15313 *
15314 * - IO.foreach: Increments the line number on each call to the block.
15315 * - IO#each_line: Increments the line number on each call to the block.
15316 * - IO#gets: Increments the line number.
15317 * - IO#readline: Increments the line number.
15318 * - IO#readlines: Increments the line number for each line read.
15319 *
15320 * A new stream is initially has line number zero (and position zero);
15321 * method +rewind+ resets the line number (and position) to zero:
15322 *
15323 * f = File.new('t.txt')
15324 * f.lineno # => 0
15325 * f.gets # => "First line\n"
15326 * f.lineno # => 1
15327 * f.rewind
15328 * f.lineno # => 0
15329 * f.close
15330 *
15331 * Reading lines from a stream usually changes its line number:
15332 *
15333 * f = File.new('t.txt', 'r')
15334 * f.lineno # => 0
15335 * f.readline # => "This is line one.\n"
15336 * f.lineno # => 1
15337 * f.readline # => "This is the second line.\n"
15338 * f.lineno # => 2
15339 * f.readline # => "Here's the third line.\n"
15340 * f.lineno # => 3
15341 * f.eof? # => true
15342 * f.close
15343 *
15344 * Iterating over lines in a stream usually changes its line number:
15345 *
15346 * File.open('t.txt') do |f|
15347 * f.each_line do |line|
15348 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15349 * end
15350 * end
15351 *
15352 * Output:
15353 *
15354 * "position=11 eof?=false lineno=1"
15355 * "position=23 eof?=false lineno=2"
15356 * "position=24 eof?=false lineno=3"
15357 * "position=36 eof?=false lineno=4"
15358 * "position=47 eof?=true lineno=5"
15359 *
15360 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15361 * the line number does not affect where the next read or write will occur:
15362 *
15363 * f = File.new('t.txt')
15364 * f.lineno = 1000
15365 * f.lineno # => 1000
15366 * f.gets # => "First line\n"
15367 * f.lineno # => 1001
15368 * f.close
15369 *
15370 * Associated with the line number is the global variable <tt>$.</tt>:
15371 *
15372 * - When a stream is opened, <tt>$.</tt> is not set;
15373 * its value is left over from previous activity in the process:
15374 *
15375 * $. = 41
15376 * f = File.new('t.txt')
15377 * $. = 41
15378 * # => 41
15379 * f.close
15380 *
15381 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15382 *
15383 * f0 = File.new('t.txt')
15384 * f1 = File.new('t.dat')
15385 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15386 * $. # => 5
15387 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15388 * $. # => 1
15389 * f0.close
15390 * f1.close
15391 *
15392 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15393 *
15394 * f = File.new('t.txt')
15395 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15396 * $. # => 5
15397 * f.rewind
15398 * f.seek(0, :SET)
15399 * $. # => 5
15400 * f.close
15401 *
15402 * === Line Output
15403 *
15404 * You can write to an \IO stream line-by-line using this method:
15405 *
15406 * - IO#puts: Writes objects to the stream.
15407 *
15408 * == Character \IO
15409 *
15410 * You can process an \IO stream character-by-character using these methods:
15411 *
15412 * - IO#getc: Reads and returns the next character from the stream.
15413 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15414 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15415 * - IO#putc: Writes a character to the stream.
15416 * - IO#each_char: Reads each remaining character in the stream,
15417 * passing the character to the given block.
15418 *
15419 * == Byte \IO
15420 *
15421 * You can process an \IO stream byte-by-byte using these methods:
15422 *
15423 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15424 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15425 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15426 * - IO#each_byte: Reads each remaining byte in the stream,
15427 * passing the byte to the given block.
15428 *
15429 * == Codepoint \IO
15430 *
15431 * You can process an \IO stream codepoint-by-codepoint:
15432 *
15433 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15434 *
15435 * == What's Here
15436 *
15437 * First, what's elsewhere. Class \IO:
15438 *
15439 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15440 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15441 * which provides dozens of additional methods.
15442 *
15443 * Here, class \IO provides methods that are useful for:
15444 *
15445 * - {Creating}[rdoc-ref:IO@Creating]
15446 * - {Reading}[rdoc-ref:IO@Reading]
15447 * - {Writing}[rdoc-ref:IO@Writing]
15448 * - {Positioning}[rdoc-ref:IO@Positioning]
15449 * - {Iterating}[rdoc-ref:IO@Iterating]
15450 * - {Settings}[rdoc-ref:IO@Settings]
15451 * - {Querying}[rdoc-ref:IO@Querying]
15452 * - {Buffering}[rdoc-ref:IO@Buffering]
15453 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15454 * - {Other}[rdoc-ref:IO@Other]
15455 *
15456 * === Creating
15457 *
15458 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15459 * integer file descriptor.
15460 * - ::open: Creates a new \IO object.
15461 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15462 * - ::popen: Creates an \IO object to interact with a subprocess.
15463 * - ::select: Selects which given \IO instances are ready for reading,
15464 * writing, or have pending exceptions.
15465 *
15466 * === Reading
15467 *
15468 * - ::binread: Returns a binary string with all or a subset of bytes
15469 * from the given file.
15470 * - ::read: Returns a string with all or a subset of bytes from the given file.
15471 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15472 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15473 * - #getc: Returns the next character read from +self+ as a string.
15474 * - #gets: Returns the line read from +self+.
15475 * - #pread: Returns all or the next _n_ bytes read from +self+,
15476 * not updating the receiver's offset.
15477 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15478 * for a given _n_.
15479 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15480 * in non-block mode.
15481 * - #readbyte: Returns the next byte read from +self+;
15482 * same as #getbyte, but raises an exception on end-of-stream.
15483 * - #readchar: Returns the next character read from +self+;
15484 * same as #getc, but raises an exception on end-of-stream.
15485 * - #readline: Returns the next line read from +self+;
15486 * same as #getline, but raises an exception of end-of-stream.
15487 * - #readlines: Returns an array of all lines read read from +self+.
15488 * - #readpartial: Returns up to the given number of bytes from +self+.
15489 *
15490 * === Writing
15491 *
15492 * - ::binwrite: Writes the given string to the file at the given filepath,
15493 * in binary mode.
15494 * - ::write: Writes the given string to +self+.
15495 * - #<<: Appends the given string to +self+.
15496 * - #print: Prints last read line or given objects to +self+.
15497 * - #printf: Writes to +self+ based on the given format string and objects.
15498 * - #putc: Writes a character to +self+.
15499 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15500 * - #pwrite: Writes the given string at the given offset,
15501 * not updating the receiver's offset.
15502 * - #write: Writes one or more given strings to +self+.
15503 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15504 *
15505 * === Positioning
15506 *
15507 * - #lineno: Returns the current line number in +self+.
15508 * - #lineno=: Sets the line number is +self+.
15509 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15510 * - #pos=: Sets the byte offset in +self+.
15511 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15512 * - #rewind: Positions +self+ to the beginning of input.
15513 * - #seek: Sets the offset for +self+ relative to given position.
15514 *
15515 * === Iterating
15516 *
15517 * - ::foreach: Yields each line of given file to the block.
15518 * - #each (aliased as #each_line): Calls the given block
15519 * with each successive line in +self+.
15520 * - #each_byte: Calls the given block with each successive byte in +self+
15521 * as an integer.
15522 * - #each_char: Calls the given block with each successive character in +self+
15523 * as a string.
15524 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15525 * as an integer.
15526 *
15527 * === Settings
15528 *
15529 * - #autoclose=: Sets whether +self+ auto-closes.
15530 * - #binmode: Sets +self+ to binary mode.
15531 * - #close: Closes +self+.
15532 * - #close_on_exec=: Sets the close-on-exec flag.
15533 * - #close_read: Closes +self+ for reading.
15534 * - #close_write: Closes +self+ for writing.
15535 * - #set_encoding: Sets the encoding for +self+.
15536 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15537 * Unicode byte-order-mark.
15538 * - #sync=: Sets the sync-mode to the given value.
15539 *
15540 * === Querying
15541 *
15542 * - #autoclose?: Returns whether +self+ auto-closes.
15543 * - #binmode?: Returns whether +self+ is in binary mode.
15544 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15545 * - #closed?: Returns whether +self+ is closed.
15546 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15547 * - #external_encoding: Returns the external encoding object for +self+.
15548 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15549 * - #internal_encoding: Returns the internal encoding object for +self+.
15550 * - #pid: Returns the process ID of a child process associated with +self+,
15551 * if +self+ was created by ::popen.
15552 * - #stat: Returns the File::Stat object containing status information for +self+.
15553 * - #sync: Returns whether +self+ is in sync-mode.
15554 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15555 *
15556 * === Buffering
15557 *
15558 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15559 * - #flush: Flushes any buffered data within +self+ to the underlying
15560 * operating system.
15561 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15562 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15563 * - #ungetc: Prepends buffer for +self+ with given string.
15564 *
15565 * === Low-Level Access
15566 *
15567 * - ::sysopen: Opens the file given by its path,
15568 * returning the integer file descriptor.
15569 * - #advise: Announces the intention to access data from +self+ in a specific way.
15570 * - #fcntl: Passes a low-level command to the file specified
15571 * by the given file descriptor.
15572 * - #ioctl: Passes a low-level command to the device specified
15573 * by the given file descriptor.
15574 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15575 * - #sysseek: Sets the offset for +self+.
15576 * - #syswrite: Writes the given string to +self+ using a low-level write.
15577 *
15578 * === Other
15579 *
15580 * - ::copy_stream: Copies data from a source to a destination,
15581 * each of which is a filepath or an \IO-like object.
15582 * - ::try_convert: Returns a new \IO object resulting from converting
15583 * the given object.
15584 * - #inspect: Returns the string representation of +self+.
15585 *
15586 */
15587
15588void
15589Init_IO(void)
15590{
15591 VALUE rb_cARGF;
15592#ifdef __CYGWIN__
15593#include <sys/cygwin.h>
15594 static struct __cygwin_perfile pf[] =
15595 {
15596 {"", O_RDONLY | O_BINARY},
15597 {"", O_WRONLY | O_BINARY},
15598 {"", O_RDWR | O_BINARY},
15599 {"", O_APPEND | O_BINARY},
15600 {NULL, 0}
15601 };
15602 cygwin_internal(CW_PERFILE, pf);
15603#endif
15604
15607
15608 id_write = rb_intern_const("write");
15609 id_read = rb_intern_const("read");
15610 id_getc = rb_intern_const("getc");
15611 id_flush = rb_intern_const("flush");
15612 id_readpartial = rb_intern_const("readpartial");
15613 id_set_encoding = rb_intern_const("set_encoding");
15614 id_fileno = rb_intern_const("fileno");
15615
15616 rb_define_global_function("syscall", rb_f_syscall, -1);
15617
15618 rb_define_global_function("open", rb_f_open, -1);
15619 rb_define_global_function("printf", rb_f_printf, -1);
15620 rb_define_global_function("print", rb_f_print, -1);
15621 rb_define_global_function("putc", rb_f_putc, 1);
15622 rb_define_global_function("puts", rb_f_puts, -1);
15623 rb_define_global_function("gets", rb_f_gets, -1);
15624 rb_define_global_function("readline", rb_f_readline, -1);
15625 rb_define_global_function("select", rb_f_select, -1);
15626
15627 rb_define_global_function("readlines", rb_f_readlines, -1);
15628
15629 rb_define_global_function("`", rb_f_backquote, 1);
15630
15631 rb_define_global_function("p", rb_f_p, -1);
15632 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15633
15634 rb_cIO = rb_define_class("IO", rb_cObject);
15636
15637 /* Can be raised by IO operations when IO#timeout= is set. */
15639
15640 /* Readable event mask for IO#wait. */
15641 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15642 /* Writable event mask for IO#wait. */
15643 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15644 /* Priority event mask for IO#wait. */
15645 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15646
15647 /* exception to wait for reading. see IO.select. */
15649 /* exception to wait for writing. see IO.select. */
15651 /* exception to wait for reading by EAGAIN. see IO.select. */
15652 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15653 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15654 /* exception to wait for writing by EAGAIN. see IO.select. */
15655 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15656 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15657#if EAGAIN == EWOULDBLOCK
15658 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15659 /* same as IO::EAGAINWaitReadable */
15660 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15661 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15662 /* same as IO::EAGAINWaitWritable */
15663 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15664#else
15665 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15666 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15667 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15668 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15669 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15670 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15671#endif
15672 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15673 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15674 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15675 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15676 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15677 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15678
15679#if 0
15680 /* This is necessary only for forcing rdoc handle File::open */
15681 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15682#endif
15683
15684 rb_define_alloc_func(rb_cIO, io_alloc);
15685 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15686 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15687 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15688 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15689 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15690 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15691 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15692 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15693 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15694 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15695 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15696 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15697 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15698 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15699 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15700
15701 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15702
15703 rb_output_fs = Qnil;
15704 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15705
15706 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15707 rb_vm_register_global_object(rb_default_rs);
15708 rb_rs = rb_default_rs;
15710 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15711 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15712 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15713
15714 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15715 rb_gvar_ractor_local("$_");
15716
15717 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15718 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15719
15720 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15721 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15722 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15723 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15724
15725 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15726 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15727 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15728 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15729 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15730
15731 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15732 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15733
15734 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15735 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15736
15737 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15738 rb_define_alias(rb_cIO, "to_i", "fileno");
15739 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15740
15741 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15742 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15743
15744 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15745 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15746 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15747 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15748
15749 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15750 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15751
15752 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15753
15754 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15755 rb_define_method(rb_cIO, "read", io_read, -1);
15756 rb_define_method(rb_cIO, "write", io_write_m, -1);
15757 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15758 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15759 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15760 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15761 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15762 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15763 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15765 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15766 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15767 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15768 /* Set I/O position from the beginning */
15769 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15770 /* Set I/O position from the current position */
15771 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15772 /* Set I/O position from the end */
15773 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15774#ifdef SEEK_DATA
15775 /* Set I/O position to the next location containing data */
15776 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15777#endif
15778#ifdef SEEK_HOLE
15779 /* Set I/O position to the next hole */
15780 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15781#endif
15782 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15783 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15784 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15785 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15786 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15787
15788 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15789 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15790
15791 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15792 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15793 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15794 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15795
15796 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15797 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15798 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15799 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15800 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15801 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15802
15803 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15804 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15805 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15806
15807 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15808 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15809
15810 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15811
15812 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15813 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15814 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15815 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15816
15817 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15818 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15819
15820 rb_define_method(rb_cIO, "wait", io_wait, -1);
15821
15822 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15823 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15824 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15825
15826 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15827 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15828 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15829 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15830
15831 rb_gvar_ractor_local("$stdin");
15832 rb_gvar_ractor_local("$stdout");
15833 rb_gvar_ractor_local("$>");
15834 rb_gvar_ractor_local("$stderr");
15835
15837 rb_stdin = rb_io_prep_stdin();
15839 rb_stdout = rb_io_prep_stdout();
15841 rb_stderr = rb_io_prep_stderr();
15842
15843 orig_stdout = rb_stdout;
15844 orig_stderr = rb_stderr;
15845
15846 /* Holds the original stdin */
15848 /* Holds the original stdout */
15850 /* Holds the original stderr */
15852
15853#if 0
15854 /* Hack to get rdoc to regard ARGF as a class: */
15855 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15856#endif
15857
15858 rb_cARGF = rb_class_new(rb_cObject);
15859 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15860 rb_define_alloc_func(rb_cARGF, argf_alloc);
15861
15863
15864 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15865 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15866 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15867 rb_define_alias(rb_cARGF, "inspect", "to_s");
15868 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15869
15870 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15871 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15872 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15873 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15874 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15875 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15876 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15877 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15878 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15879
15880 rb_define_method(rb_cARGF, "read", argf_read, -1);
15881 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15882 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15883 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15884 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15885 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15886 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15887 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15888 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15889 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15890 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15891 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15892 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15893 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15894 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15895 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15896 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15897 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15898 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15899 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15900
15901 rb_define_method(rb_cARGF, "write", argf_write, -1);
15902 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15903 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15904 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15905 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15906
15907 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15908 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15909 rb_define_method(rb_cARGF, "file", argf_file, 0);
15910 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15911 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15912 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15913
15914 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15915 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15916
15917 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15918 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15919
15920 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15921 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15922 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15923
15924 argf = rb_class_new_instance(0, 0, rb_cARGF);
15925
15927 /*
15928 * ARGF is a stream designed for use in scripts that process files given
15929 * as command-line arguments or passed in via STDIN.
15930 *
15931 * See ARGF (the class) for more details.
15932 */
15934
15935 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15936 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15937 ARGF.filename = rb_str_new2("-");
15938
15939 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15940 rb_gvar_ractor_local("$-i");
15941
15942 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15943
15944#if defined (_WIN32) || defined(__CYGWIN__)
15945 atexit(pipe_atexit);
15946#endif
15947
15948 Init_File();
15949
15950 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15951
15952 sym_mode = ID2SYM(rb_intern_const("mode"));
15953 sym_perm = ID2SYM(rb_intern_const("perm"));
15954 sym_flags = ID2SYM(rb_intern_const("flags"));
15955 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15956 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15957 sym_encoding = ID2SYM(rb_id_encoding());
15958 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15959 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15960 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15961 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15962 sym_normal = ID2SYM(rb_intern_const("normal"));
15963 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15964 sym_random = ID2SYM(rb_intern_const("random"));
15965 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15966 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15967 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15968 sym_SET = ID2SYM(rb_intern_const("SET"));
15969 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15970 sym_END = ID2SYM(rb_intern_const("END"));
15971#ifdef SEEK_DATA
15972 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15973#endif
15974#ifdef SEEK_HOLE
15975 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15976#endif
15977 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15978 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15979}
15980
15981#include "io.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:138
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1187
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:980
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:359
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1012
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1119
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2345
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
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
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:936
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2424
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:135
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1677
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3836
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
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
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:675
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3905
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:14662
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
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:3995
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:3911
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14656
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2092
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1450
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:65
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3198
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:669
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2097
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
VALUE rb_cIO
IO class.
Definition io.c:187
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
Definition object.c:2126
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:201
VALUE rb_stderr
STDERR constant.
Definition io.c:201
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:247
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:576
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:680
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:191
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:192
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1260
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
VALUE rb_cFile
File class.
Definition file.c:175
VALUE rb_stdout
STDOUT constant.
Definition io.c:201
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3192
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition encoding.h:571
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1286
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
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:785
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
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_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
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1770
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1814
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_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
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
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
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4272
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4278
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1731
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1781
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1099
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
Defines RBIMPL_HAS_BUILTIN.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:239
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8601
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4297
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:427
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8727
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2344
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9156
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
Definition io.c:5166
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5072
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
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
Definition io.c:9332
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:248
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:328
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:206
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2689
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9136
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
Definition io.c:298
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6378
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6332
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5230
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7379
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10401
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:461
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
Definition io.c:7262
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:367
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7269
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5752
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:207
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:1854
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1848
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:2951
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1167
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:681
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:3677
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
#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
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:955
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1462
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1917
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3445
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3269
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:3619
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2851
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3149
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3252
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:2649
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1644
#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
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1776
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1446
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
Definition io.c:1597
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
Definition thread.c:2702
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1429
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:2979
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1591
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1452
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2943
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:353
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:1844
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:412
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:2953
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
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:3712
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:744
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:270
int rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6464
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:811
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:857
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:781
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1069
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
Definition io.c:6597
#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
int rb_io_mode(VALUE io)
Get the mode of the IO.
Definition io.c:2912
rb_io_event
Type of events that an IO can wait.
Definition io.h:81
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:82
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:84
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:83
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:276
#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
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:402
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:1015
#define FMODE_TTY
The IO is a TTY.
Definition io.h:300
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:323
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1024
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:6746
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition io.c:1585
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
Definition io.c:7079
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2892
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:273
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
Definition io.c:9378
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:315
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:425
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:308
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:287
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1644
int capa
Designed capacity of the buffer.
Definition io.h:11
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:396
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1603
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:294
int off
Offset inside of ptr.
Definition io.h:5
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:2966
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:788
#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
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:351
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
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5860
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:886
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2009
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:996
#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
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:823
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3418
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:6871
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1542
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
Definition io.c:9249
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:834
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1048
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
Definition io.c:1659
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:796
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1508
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7366
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1447
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:2733
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:2793
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:2781
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:2769
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:1899
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:209
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1388
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1354
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:442
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:488
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:79
#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
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14622
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9035
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:228
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
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
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
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
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
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
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:482
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
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
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
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
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:4330
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:236
Definition win32.h:219
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:200
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
Decomposed encoding flags (e.g.
Definition io.h:119
int ecflags
Flags.
Definition io.h:129
VALUE ecopts
Flags as Ruby hash.
Definition io.h:137
rb_encoding * enc2
External encoding.
Definition io.h:123
rb_encoding * enc
Internal encoding.
Definition io.h:121
IO buffers.
Definition io.h:94
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:97
int off
Offset inside of ptr.
Definition io.h:100
int len
Length of the buffer.
Definition io.h:103
int capa
Designed capacity of the buffer.
Definition io.h:106
Ruby's IO, metadata and buffers.
Definition io.h:143
int mode
mode flags: FMODE_XXXs
Definition io.h:158
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:178
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:174
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:200
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:211
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:196
VALUE self
The IO's Ruby level counterpart.
Definition io.h:146
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:248
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:254
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:150
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
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:193
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:224
int fd
file descriptor.
Definition io.h:154
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:185
int lineno
number of lines read
Definition io.h:166
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:220
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:207
rb_pid_t pid
child's pid (for pipes)
Definition io.h:162
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
VALUE pathv
pathname for file
Definition io.h:170
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:307
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:433
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