Ruby 4.1.0dev (2026-05-15 revision a8bcae043f931d9b79f1cb1fe2c021985d07b984)
io.c (a8bcae043f931d9b79f1cb1fe2c021985d07b984)
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
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, enum rb_io_mode 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(io, function, argument, 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#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
504
505#define GetWriteIO(io) rb_io_get_write_io(io)
506
507#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
509#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
510#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
511
512#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
514#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
515
516#if defined(_WIN32)
517#define WAIT_FD_IN_WIN32(fptr) \
518 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
519#else
520#define WAIT_FD_IN_WIN32(fptr)
521#endif
522
523#define READ_CHECK(fptr) do {\
524 if (!READ_DATA_PENDING(fptr)) {\
525 WAIT_FD_IN_WIN32(fptr);\
526 rb_io_check_closed(fptr);\
527 }\
528} while(0)
529
530#ifndef S_ISSOCK
531# ifdef _S_ISSOCK
532# define S_ISSOCK(m) _S_ISSOCK(m)
533# else
534# ifdef _S_IFSOCK
535# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
536# else
537# ifdef S_IFSOCK
538# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
539# endif
540# endif
541# endif
542#endif
543
544static int io_fflush(rb_io_t *);
545static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
546static void clear_codeconv(rb_io_t *fptr);
547
548#define FMODE_SIGNAL_ON_EPIPE (1<<17)
549
550#define fptr_signal_on_epipe(fptr) \
551 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
552
553#define fptr_set_signal_on_epipe(fptr, flag) \
554 ((flag) ? \
555 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
556 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
557
558extern ID ruby_static_id_signo;
559
560NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
561static void
562rb_sys_fail_on_write(rb_io_t *fptr)
563{
564 int e = errno;
565 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
566#if defined EPIPE
567 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
568 const VALUE sig =
569# if defined SIGPIPE
570 INT2FIX(SIGPIPE) - INT2FIX(0) +
571# endif
572 INT2FIX(0);
573 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
574 }
575#endif
576 rb_exc_raise(errinfo);
577}
578
579#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
581#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
582# define RUBY_CRLF_ENVIRONMENT 1
583#else
584# define RUBY_CRLF_ENVIRONMENT 0
585#endif
586
587#if RUBY_CRLF_ENVIRONMENT
588/* Windows */
589# define DEFAULT_TEXTMODE FMODE_TEXTMODE
590# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
591/*
592 * CRLF newline is set as default newline decorator.
593 * If only CRLF newline conversion is needed, we use binary IO process
594 * with OS's text mode for IO performance improvement.
595 * If encoding conversion is needed or a user sets text mode, we use encoding
596 * conversion IO process and universal newline decorator by default.
597 */
598#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
599#define WRITECONV_MASK ( \
600 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
601 ECONV_STATEFUL_DECORATOR_MASK|\
602 0)
603#define NEED_WRITECONV(fptr) ( \
604 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
605 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
606 0)
607#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
608
609#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
610 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
611 if (((fptr)->mode & FMODE_READABLE) &&\
612 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
613 setmode((fptr)->fd, O_BINARY);\
614 }\
615 else {\
616 setmode((fptr)->fd, O_TEXT);\
617 }\
618 }\
619} while(0)
620
621#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
622 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
623 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
624 }\
625} while(0)
626
627/*
628 * IO unread with taking care of removed '\r' in text mode.
629 */
630static void
631io_unread(rb_io_t *fptr, bool discard_rbuf)
632{
633 rb_off_t r, pos;
634 ssize_t read_size;
635 long i;
636 long newlines = 0;
637 long extra_max;
638 char *p;
639 char *buf;
640
641 rb_io_check_closed(fptr);
642 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
643 return;
644 }
645
646 errno = 0;
647 if (!rb_w32_fd_is_text(fptr->fd)) {
648 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
649 if (r < 0 && errno) {
650 if (errno == ESPIPE)
651 fptr->mode |= FMODE_DUPLEX;
652 if (!discard_rbuf) return;
653 }
654
655 goto end;
656 }
657
658 pos = lseek(fptr->fd, 0, SEEK_CUR);
659 if (pos < 0 && errno) {
660 if (errno == ESPIPE)
661 fptr->mode |= FMODE_DUPLEX;
662 if (!discard_rbuf) goto end;
663 }
664
665 /* add extra offset for removed '\r' in rbuf */
666 extra_max = (long)(pos - fptr->rbuf.len);
667 p = fptr->rbuf.ptr + fptr->rbuf.off;
668
669 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
670 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
671 newlines++;
672 }
673
674 for (i = 0; i < fptr->rbuf.len; i++) {
675 if (*p == '\n') newlines++;
676 if (extra_max == newlines) break;
677 p++;
678 }
679
680 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
681 while (newlines >= 0) {
682 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
683 if (newlines == 0) break;
684 if (r < 0) {
685 newlines--;
686 continue;
687 }
688 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
689 if (read_size < 0) {
690 int e = errno;
691 free(buf);
692 rb_syserr_fail_path(e, fptr->pathv);
693 }
694 if (read_size == fptr->rbuf.len) {
695 lseek(fptr->fd, r, SEEK_SET);
696 break;
697 }
698 else {
699 newlines--;
700 }
701 }
702 free(buf);
703 end:
704 fptr->rbuf.off = 0;
705 fptr->rbuf.len = 0;
706 clear_codeconv(fptr);
707 return;
708}
709
710/*
711 * We use io_seek to back cursor position when changing mode from text to binary,
712 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
713 * conversion for working properly with mode change.
714 *
715 * Return previous translation mode.
716 */
717static inline int
718set_binary_mode_with_seek_cur(rb_io_t *fptr)
719{
720 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
721
722 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
723 return setmode(fptr->fd, O_BINARY);
724 }
725 flush_before_seek(fptr, false);
726 return setmode(fptr->fd, O_BINARY);
727}
728#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
729
730#else
731/* Unix */
732# define DEFAULT_TEXTMODE 0
733#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
734#define NEED_WRITECONV(fptr) ( \
735 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
736 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
737 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
738 0)
739#define SET_BINARY_MODE(fptr) (void)(fptr)
740#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
741#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
742#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
743#endif
744
745#if !defined HAVE_SHUTDOWN && !defined shutdown
746#define shutdown(a,b) 0
747#endif
748
749#if defined(_WIN32)
750#define is_socket(fd, path) rb_w32_is_socket(fd)
751#elif !defined(S_ISSOCK)
752#define is_socket(fd, path) 0
753#else
754static int
755is_socket(int fd, VALUE path)
756{
757 struct stat sbuf;
758 if (fstat(fd, &sbuf) < 0)
759 rb_sys_fail_path(path);
760 return S_ISSOCK(sbuf.st_mode);
761}
762#endif
763
764static const char closed_stream[] = "closed stream";
765
766static void
767io_fd_check_closed(int fd)
768{
769 if (fd < 0) {
770 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
771 rb_raise(rb_eIOError, closed_stream);
772 }
773}
774
775void
776rb_eof_error(void)
777{
778 rb_raise(rb_eEOFError, "end of file reached");
779}
780
781VALUE
783{
784 rb_check_frozen(io);
785 return io;
786}
787
788void
790{
791 if (!fptr) {
792 rb_raise(rb_eIOError, "uninitialized stream");
793 }
794}
795
796void
798{
800 io_fd_check_closed(fptr->fd);
801}
802
803static rb_io_t *
804rb_io_get_fptr(VALUE io)
805{
806 rb_io_t *fptr = RFILE(io)->fptr;
808 return fptr;
809}
810
811VALUE
813{
814 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
815}
816
817VALUE
819{
820 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
821}
822
823VALUE
825{
826 VALUE write_io;
827 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
828 if (write_io) {
829 return write_io;
830 }
831 return io;
832}
833
834VALUE
836{
837 VALUE write_io;
838 rb_io_t *fptr = rb_io_get_fptr(io);
839 if (!RTEST(w)) {
840 w = 0;
841 }
842 else {
843 GetWriteIO(w);
844 }
845 write_io = fptr->tied_io_for_writing;
846 fptr->tied_io_for_writing = w;
847 return write_io ? write_io : Qnil;
848}
849
850/*
851 * call-seq:
852 * timeout -> duration or nil
853 *
854 * Get the internal timeout duration or nil if it was not set.
855 *
856 */
857VALUE
859{
860 rb_io_t *fptr = rb_io_get_fptr(self);
861
862 return fptr->timeout;
863}
864
865/*
866 * call-seq:
867 * timeout = duration -> duration
868 * timeout = nil -> nil
869 *
870 * Sets the internal timeout to the specified duration or nil. The timeout
871 * applies to all blocking operations where possible.
872 *
873 * When the operation performs longer than the timeout set, IO::TimeoutError
874 * is raised.
875 *
876 * This affects the following methods (but is not limited to): #gets, #puts,
877 * #read, #write, #wait_readable and #wait_writable. This also affects
878 * blocking socket operations like Socket#accept and Socket#connect.
879 *
880 * Some operations like File#open and IO#close are not affected by the
881 * timeout. A timeout during a write operation may leave the IO in an
882 * inconsistent state, e.g. data was partially written. Generally speaking, a
883 * timeout is a last ditch effort to prevent an application from hanging on
884 * slow I/O operations, such as those that occur during a slowloris attack.
885 */
886VALUE
888{
889 // Validate it:
890 if (RTEST(timeout)) {
891 rb_time_interval(timeout);
892 }
893
894 rb_io_t *fptr = rb_io_get_fptr(self);
895
896 fptr->timeout = timeout;
897
898 return self;
899}
900
901/*
902 * call-seq:
903 * IO.try_convert(object) -> new_io or nil
904 *
905 * Attempts to convert +object+ into an \IO object via method +to_io+;
906 * returns the new \IO object if successful, or +nil+ otherwise:
907 *
908 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
909 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
910 * IO.try_convert('STDOUT') # => nil
911 *
912 */
913static VALUE
914rb_io_s_try_convert(VALUE dummy, VALUE io)
915{
916 return rb_io_check_io(io);
917}
918
919#if !RUBY_CRLF_ENVIRONMENT
920static void
921io_unread(rb_io_t *fptr, bool discard_rbuf)
922{
923 rb_off_t r;
924 rb_io_check_closed(fptr);
925 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
926 return;
927 /* xxx: target position may be negative if buffer is filled by ungetc */
928 errno = 0;
929 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
930 if (r < 0 && errno) {
931 if (errno == ESPIPE)
932 fptr->mode |= FMODE_DUPLEX;
933 if (!discard_rbuf) return;
934 }
935 fptr->rbuf.off = 0;
936 fptr->rbuf.len = 0;
937 clear_codeconv(fptr);
938 return;
939}
940#endif
941
942static rb_encoding *io_input_encoding(rb_io_t *fptr);
943
944static void
945io_ungetbyte(VALUE str, rb_io_t *fptr)
946{
947 long len = RSTRING_LEN(str);
948
949 if (fptr->rbuf.ptr == NULL) {
950 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
951 fptr->rbuf.off = 0;
952 fptr->rbuf.len = 0;
953#if SIZEOF_LONG > SIZEOF_INT
954 if (len > INT_MAX)
955 rb_raise(rb_eIOError, "ungetbyte failed");
956#endif
957 if (len > min_capa)
958 fptr->rbuf.capa = (int)len;
959 else
960 fptr->rbuf.capa = min_capa;
961 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
962 }
963 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
964 rb_raise(rb_eIOError, "ungetbyte failed");
965 }
966 if (fptr->rbuf.off < len) {
967 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
968 fptr->rbuf.ptr+fptr->rbuf.off,
969 char, fptr->rbuf.len);
970 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
971 }
972 fptr->rbuf.off-=(int)len;
973 fptr->rbuf.len+=(int)len;
974 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
975}
976
977static rb_io_t *
978flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
979{
980 if (io_fflush(fptr) < 0)
981 rb_sys_fail_on_write(fptr);
982 io_unread(fptr, discard_rbuf);
983 errno = 0;
984 return fptr;
985}
986
987#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
988#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
989
990#ifndef SEEK_CUR
991# define SEEK_SET 0
992# define SEEK_CUR 1
993# define SEEK_END 2
994#endif
995
996void
998{
999 rb_io_check_closed(fptr);
1000 if (!(fptr->mode & FMODE_READABLE)) {
1001 rb_raise(rb_eIOError, "not opened for reading");
1002 }
1003 if (fptr->wbuf.len) {
1004 if (io_fflush(fptr) < 0)
1005 rb_sys_fail_on_write(fptr);
1006 }
1007 if (fptr->tied_io_for_writing) {
1008 rb_io_t *wfptr;
1009 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1010 if (io_fflush(wfptr) < 0)
1011 rb_sys_fail_on_write(wfptr);
1012 }
1013}
1014
1015void
1017{
1019 if (READ_CHAR_PENDING(fptr)) {
1020 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1021 }
1022}
1023
1024void
1029
1030static rb_encoding*
1031io_read_encoding(rb_io_t *fptr)
1032{
1033 if (fptr->encs.enc) {
1034 return fptr->encs.enc;
1035 }
1036 return rb_default_external_encoding();
1037}
1038
1039static rb_encoding*
1040io_input_encoding(rb_io_t *fptr)
1041{
1042 if (fptr->encs.enc2) {
1043 return fptr->encs.enc2;
1044 }
1045 return io_read_encoding(fptr);
1046}
1047
1048void
1050{
1051 rb_io_check_closed(fptr);
1052 if (!(fptr->mode & FMODE_WRITABLE)) {
1053 rb_raise(rb_eIOError, "not opened for writing");
1054 }
1055 if (fptr->rbuf.len) {
1056 io_unread(fptr, true);
1057 }
1058}
1059
1060int
1061rb_io_read_pending(rb_io_t *fptr)
1062{
1063 /* This function is used for bytes and chars. Confusing. */
1064 if (READ_CHAR_PENDING(fptr))
1065 return 1; /* should raise? */
1066 return READ_DATA_PENDING(fptr);
1067}
1068
1069void
1071{
1072 if (!READ_DATA_PENDING(fptr)) {
1073 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1074 }
1075 return;
1076}
1077
1078int
1079rb_gc_for_fd(int err)
1080{
1081 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1082 rb_gc();
1083 return 1;
1084 }
1085 return 0;
1086}
1087
1088/* try `expr` upto twice while it returns false and `errno`
1089 * is to GC. Each `errno`s are available as `first_errno` and
1090 * `retried_errno` respectively */
1091#define TRY_WITH_GC(expr) \
1092 for (int first_errno, retried_errno = 0, retried = 0; \
1093 (!retried && \
1094 !(expr) && \
1095 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1096 (retried_errno = errno, 1)); \
1097 (void)retried_errno, retried = 1)
1098
1099static int
1100ruby_dup(int orig)
1101{
1102 int fd = -1;
1103
1104 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1105 rb_syserr_fail(first_errno, 0);
1106 }
1107 rb_update_max_fd(fd);
1108 return fd;
1109}
1110
1111static VALUE
1112io_alloc(VALUE klass)
1113{
1114 UNPROTECTED_NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile));
1115
1116 io->fptr = 0;
1117
1118 return (VALUE)io;
1119}
1120
1121#ifndef S_ISREG
1122# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1123#endif
1124
1126 VALUE th;
1127 rb_io_t *fptr;
1128 int nonblock;
1129 int fd;
1130
1131 void *buf;
1132 size_t capa;
1133 struct timeval *timeout;
1134};
1135
1137 VALUE th;
1138 rb_io_t *fptr;
1139 int nonblock;
1140 int fd;
1141
1142 const void *buf;
1143 size_t capa;
1144 struct timeval *timeout;
1145};
1146
1147#ifdef HAVE_WRITEV
1148struct io_internal_writev_struct {
1149 VALUE th;
1150 rb_io_t *fptr;
1151 int nonblock;
1152 int fd;
1153
1154 int iovcnt;
1155 const struct iovec *iov;
1156 struct timeval *timeout;
1157};
1158#endif
1159
1160static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1161
1167static inline int
1168io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1169{
1170 if (!timeout && rb_thread_mn_schedulable(thread)) {
1171 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1172 return -1;
1173 }
1174
1175 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1176
1177 if (ready > 0) {
1178 return ready;
1179 }
1180 else if (ready == 0) {
1181 errno = ETIMEDOUT;
1182 return -1;
1183 }
1184
1185 // If there was an error BEFORE we started waiting, return it:
1186 if (error) {
1187 errno = error;
1188 return -1;
1189 }
1190 else {
1191 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1192 return ready;
1193 }
1194}
1195
1196static VALUE
1197internal_read_func(void *ptr)
1198{
1199 struct io_internal_read_struct *iis = ptr;
1200 ssize_t result;
1201
1202 if (iis->timeout && !iis->nonblock) {
1203 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1204 return -1;
1205 }
1206 }
1207
1208 retry:
1209 result = read(iis->fd, iis->buf, iis->capa);
1210
1211 if (result < 0 && !iis->nonblock) {
1212 if (io_again_p(errno)) {
1213 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1214 return -1;
1215 }
1216 else {
1217 goto retry;
1218 }
1219 }
1220 }
1221
1222 return result;
1223}
1224
1225#if defined __APPLE__
1226# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1227#else
1228# define do_write_retry(code) result = code
1229#endif
1230
1231static VALUE
1232internal_write_func(void *ptr)
1233{
1234 struct io_internal_write_struct *iis = ptr;
1235 ssize_t result;
1236
1237 if (iis->timeout && !iis->nonblock) {
1238 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1239 return -1;
1240 }
1241 }
1242
1243 retry:
1244 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1245
1246 if (result < 0 && !iis->nonblock) {
1247 int e = errno;
1248 if (io_again_p(e)) {
1249 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1250 return -1;
1251 }
1252 else {
1253 goto retry;
1254 }
1255 }
1256 }
1257
1258 return result;
1259}
1260
1261#ifdef HAVE_WRITEV
1262static VALUE
1263internal_writev_func(void *ptr)
1264{
1265 struct io_internal_writev_struct *iis = ptr;
1266 ssize_t result;
1267
1268 if (iis->timeout && !iis->nonblock) {
1269 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1270 return -1;
1271 }
1272 }
1273
1274 retry:
1275 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1276
1277 if (result < 0 && !iis->nonblock) {
1278 if (io_again_p(errno)) {
1279 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1280 return -1;
1281 }
1282 else {
1283 goto retry;
1284 }
1285 }
1286 }
1287
1288 return result;
1289}
1290#endif
1291
1292static ssize_t
1293rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1294{
1295 rb_thread_t *th = GET_THREAD();
1297 if (scheduler != Qnil) {
1298 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1299
1300 if (!UNDEF_P(result)) {
1302 }
1303 }
1304
1305 struct io_internal_read_struct iis = {
1306 .th = th->self,
1307 .fptr = fptr,
1308 .nonblock = 0,
1309 .fd = fptr->fd,
1310
1311 .buf = buf,
1312 .capa = count,
1313 .timeout = NULL,
1314 };
1315
1316 struct timeval timeout_storage;
1317
1318 if (fptr->timeout != Qnil) {
1319 timeout_storage = rb_time_interval(fptr->timeout);
1320 iis.timeout = &timeout_storage;
1321 }
1322
1323 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1324}
1325
1326static ssize_t
1327rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1328{
1329 rb_thread_t *th = GET_THREAD();
1331 if (scheduler != Qnil) {
1332 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1333
1334 if (!UNDEF_P(result)) {
1336 }
1337 }
1338
1339 struct io_internal_write_struct iis = {
1340 .th = th->self,
1341 .fptr = fptr,
1342 .nonblock = 0,
1343 .fd = fptr->fd,
1344
1345 .buf = buf,
1346 .capa = count,
1347 .timeout = NULL
1348 };
1349
1350 struct timeval timeout_storage;
1351
1352 if (fptr->timeout != Qnil) {
1353 timeout_storage = rb_time_interval(fptr->timeout);
1354 iis.timeout = &timeout_storage;
1355 }
1356
1357 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1358}
1359
1360#ifdef HAVE_WRITEV
1361static ssize_t
1362rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1363{
1364 if (!iovcnt) return 0;
1365
1366 rb_thread_t *th = GET_THREAD();
1367
1369 if (scheduler != Qnil) {
1370 // This path assumes at least one `iov`:
1371 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1372
1373 if (!UNDEF_P(result)) {
1375 }
1376 }
1377
1378 struct io_internal_writev_struct iis = {
1379 .th = th->self,
1380 .fptr = fptr,
1381 .nonblock = 0,
1382 .fd = fptr->fd,
1383
1384 .iov = iov,
1385 .iovcnt = iovcnt,
1386 .timeout = NULL
1387 };
1388
1389 struct timeval timeout_storage;
1390
1391 if (fptr->timeout != Qnil) {
1392 timeout_storage = rb_time_interval(fptr->timeout);
1393 iis.timeout = &timeout_storage;
1394 }
1395
1396 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1397}
1398#endif
1399
1400static VALUE
1401io_flush_buffer_sync(void *arg)
1402{
1403 rb_io_t *fptr = arg;
1404 long l = fptr->wbuf.len;
1405 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1406
1407 if (fptr->wbuf.len <= r) {
1408 fptr->wbuf.off = 0;
1409 fptr->wbuf.len = 0;
1410 return 0;
1411 }
1412
1413 if (0 <= r) {
1414 fptr->wbuf.off += (int)r;
1415 fptr->wbuf.len -= (int)r;
1416 errno = EAGAIN;
1417 }
1418
1419 return (VALUE)-1;
1420}
1421
1422static inline VALUE
1423io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
1424{
1425 VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len, 0);
1426 if (!UNDEF_P(ret)) {
1427 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1428 if (result > 0) {
1429 fptr->wbuf.off += result;
1430 fptr->wbuf.len -= result;
1431 }
1432 return result >= 0 ? (VALUE)0 : (VALUE)-1;
1433 }
1434 return ret;
1435}
1436
1437static VALUE
1438io_flush_buffer_async(VALUE arg)
1439{
1440 rb_io_t *fptr = (rb_io_t *)arg;
1441
1442 VALUE scheduler = rb_fiber_scheduler_current();
1443 if (scheduler != Qnil) {
1444 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1445 if (!UNDEF_P(result)) {
1446 return result;
1447 }
1448 }
1449
1450 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1451}
1452
1453static inline int
1454io_flush_buffer(rb_io_t *fptr)
1455{
1456 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1457 return (int)io_flush_buffer_async((VALUE)fptr);
1458 }
1459 else {
1460 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1461 }
1462}
1463
1464static int
1465io_fflush(rb_io_t *fptr)
1466{
1467 rb_io_check_closed(fptr);
1468
1469 if (fptr->wbuf.len == 0)
1470 return 0;
1471
1472 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1473 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1474 return -1;
1475
1476 rb_io_check_closed(fptr);
1477 }
1478
1479 return 0;
1480}
1481
1482VALUE
1483rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1484{
1485 rb_thread_t *th = GET_THREAD();
1487
1488 if (scheduler != Qnil) {
1489 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1490 }
1491
1492 rb_io_t * fptr = NULL;
1493 RB_IO_POINTER(io, fptr);
1494
1495 struct timeval tv_storage;
1496 struct timeval *tv = NULL;
1497
1498 if (NIL_OR_UNDEF_P(timeout)) {
1499 timeout = fptr->timeout;
1500 }
1501
1502 if (timeout != Qnil) {
1503 tv_storage = rb_time_interval(timeout);
1504 tv = &tv_storage;
1505 }
1506
1507 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1508
1509 if (ready < 0) {
1510 rb_sys_fail(0);
1511 }
1512
1513 // Not sure if this is necessary:
1514 rb_io_check_closed(fptr);
1515
1516 if (ready) {
1517 return RB_INT2NUM(ready);
1518 }
1519 else {
1520 return Qfalse;
1521 }
1522}
1523
1524static VALUE
1525io_from_fd(int fd)
1526{
1527 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1528}
1529
1530static int
1531io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1532{
1533 if (scheduler != Qnil) {
1534 return RTEST(
1535 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1536 );
1537 }
1538
1539 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1540}
1541
1542int
1544{
1545 io_fd_check_closed(f);
1546
1547 rb_thread_t *th = GET_THREAD();
1549
1550 switch (errno) {
1551 case EINTR:
1552#if defined(ERESTART)
1553 case ERESTART:
1554#endif
1556 return TRUE;
1557
1558 case EAGAIN:
1559#if EWOULDBLOCK != EAGAIN
1560 case EWOULDBLOCK:
1561#endif
1562 if (scheduler != Qnil) {
1563 return RTEST(
1564 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1565 );
1566 }
1567 else {
1568 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1569 }
1570 return TRUE;
1571
1572 default:
1573 return FALSE;
1574 }
1575}
1576
1577int
1579{
1580 io_fd_check_closed(f);
1581
1582 rb_thread_t *th = GET_THREAD();
1584
1585 switch (errno) {
1586 case EINTR:
1587#if defined(ERESTART)
1588 case ERESTART:
1589#endif
1590 /*
1591 * In old Linux, several special files under /proc and /sys don't handle
1592 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1593 * Otherwise, we face nasty hang up. Sigh.
1594 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1595 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1596 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1597 * Then rb_thread_check_ints() is enough.
1598 */
1600 return TRUE;
1601
1602 case EAGAIN:
1603#if EWOULDBLOCK != EAGAIN
1604 case EWOULDBLOCK:
1605#endif
1606 if (scheduler != Qnil) {
1607 return RTEST(
1608 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1609 );
1610 }
1611 else {
1612 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1613 }
1614 return TRUE;
1615
1616 default:
1617 return FALSE;
1618 }
1619}
1620
1621int
1622rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1623{
1624 rb_thread_t *th = GET_THREAD();
1626 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1627}
1628
1629int
1631{
1632 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1633}
1634
1635int
1637{
1638 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1639}
1640
1641VALUE
1642rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1643{
1644 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1645 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1646 // instead relies on `read(-1) -> -1` which causes this code path. We then
1647 // check here whether the IO was in fact closed. Probably it's better to
1648 // check that `fptr->fd != -1` before using it in syscall.
1649 rb_io_check_closed(RFILE(io)->fptr);
1650
1651 switch (error) {
1652 // In old Linux, several special files under /proc and /sys don't handle
1653 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1654 // Otherwise, we face nasty hang up. Sigh.
1655 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1656 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1657 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1658 // Then rb_thread_check_ints() is enough.
1659 case EINTR:
1660#if defined(ERESTART)
1661 case ERESTART:
1662#endif
1663 // We might have pending interrupts since the previous syscall was interrupted:
1665
1666 // The operation was interrupted, so retry it immediately:
1667 return events;
1668
1669 case EAGAIN:
1670#if EWOULDBLOCK != EAGAIN
1671 case EWOULDBLOCK:
1672#endif
1673 // The operation would block, so wait for the specified events:
1674 return rb_io_wait(io, events, timeout);
1675
1676 default:
1677 // Non-specific error, no event is ready:
1678 return Qnil;
1679 }
1680}
1681
1682int
1684{
1685 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1686
1687 if (RTEST(result)) {
1688 return RB_NUM2INT(result);
1689 }
1690 else if (result == RUBY_Qfalse) {
1691 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1692 }
1693
1694 return 0;
1695}
1696
1697int
1699{
1700 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1701
1702 if (RTEST(result)) {
1703 return RB_NUM2INT(result);
1704 }
1705 else if (result == RUBY_Qfalse) {
1706 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1707 }
1708
1709 return 0;
1710}
1711
1712static void
1713make_writeconv(rb_io_t *fptr)
1714{
1715 if (!fptr->writeconv_initialized) {
1716 const char *senc, *denc;
1717 rb_encoding *enc;
1718 int ecflags;
1719 VALUE ecopts;
1720
1721 fptr->writeconv_initialized = 1;
1722
1723 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1724 ecopts = fptr->encs.ecopts;
1725
1726 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1727 /* no encoding conversion */
1728 fptr->writeconv_pre_ecflags = 0;
1729 fptr->writeconv_pre_ecopts = Qnil;
1730 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1731 if (!fptr->writeconv)
1732 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1734 }
1735 else {
1736 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1737 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1738 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1739 /* single conversion */
1740 fptr->writeconv_pre_ecflags = ecflags;
1741 fptr->writeconv_pre_ecopts = ecopts;
1742 fptr->writeconv = NULL;
1744 }
1745 else {
1746 /* double conversion */
1747 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1748 fptr->writeconv_pre_ecopts = ecopts;
1749 if (senc) {
1750 denc = rb_enc_name(enc);
1751 fptr->writeconv_asciicompat = rb_str_new2(senc);
1752 }
1753 else {
1754 senc = denc = "";
1755 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1756 }
1758 ecopts = fptr->encs.ecopts;
1759 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1760 if (!fptr->writeconv)
1761 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1762 }
1763 }
1764 }
1765}
1766
1767/* writing functions */
1769 rb_io_t *fptr;
1770 const char *ptr;
1771 long length;
1772};
1773
1775 VALUE io;
1776 VALUE str;
1777 int nosync;
1778};
1779
1780#ifdef HAVE_WRITEV
1781static ssize_t
1782io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1783{
1784 if (fptr->wbuf.len) {
1785 struct iovec iov[2];
1786
1787 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1788 iov[0].iov_len = fptr->wbuf.len;
1789 iov[1].iov_base = (void*)ptr;
1790 iov[1].iov_len = length;
1791
1792 ssize_t result = rb_writev_internal(fptr, iov, 2);
1793
1794 if (result < 0)
1795 return result;
1796
1797 if (result >= fptr->wbuf.len) {
1798 // We wrote more than the internal buffer:
1799 result -= fptr->wbuf.len;
1800 fptr->wbuf.off = 0;
1801 fptr->wbuf.len = 0;
1802 }
1803 else {
1804 // We only wrote less data than the internal buffer:
1805 fptr->wbuf.off += (int)result;
1806 fptr->wbuf.len -= (int)result;
1807
1808 result = 0;
1809 }
1810
1811 return result;
1812 }
1813 else {
1814 return rb_io_write_memory(fptr, ptr, length);
1815 }
1816}
1817#else
1818static ssize_t
1819io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1820{
1821 long remaining = length;
1822
1823 if (fptr->wbuf.len) {
1824 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1825 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1826 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1827 fptr->wbuf.off = 0;
1828 }
1829
1830 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1831 fptr->wbuf.len += (int)length;
1832
1833 // We copied the entire incoming data to the internal buffer:
1834 remaining = 0;
1835 }
1836
1837 // Flush the internal buffer:
1838 if (io_fflush(fptr) < 0) {
1839 return -1;
1840 }
1841
1842 // If all the data was buffered, we are done:
1843 if (remaining == 0) {
1844 return length;
1845 }
1846 }
1847
1848 // Otherwise, we should write the data directly:
1849 return rb_io_write_memory(fptr, ptr, length);
1850}
1851#endif
1852
1853static VALUE
1854io_binwrite_string(VALUE arg)
1855{
1856 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1857
1858 const char *ptr = p->ptr;
1859 size_t remaining = p->length;
1860
1861 while (remaining) {
1862 // Write as much as possible:
1863 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1864
1865 if (result == 0) {
1866 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1867 // should try again immediately.
1868 }
1869 else if (result > 0) {
1870 if ((size_t)result == remaining) break;
1871 ptr += result;
1872 remaining -= result;
1873 }
1874 // Wait for it to become writable:
1875 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1876 rb_io_check_closed(p->fptr);
1877 }
1878 else {
1879 // The error was unrelated to waiting for it to become writable, so we fail:
1880 return -1;
1881 }
1882 }
1883
1884 return p->length;
1885}
1886
1887inline static void
1888io_allocate_write_buffer(rb_io_t *fptr, int sync)
1889{
1890 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1891 fptr->wbuf.off = 0;
1892 fptr->wbuf.len = 0;
1893 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1894 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1895 }
1896
1897 if (NIL_P(fptr->write_lock)) {
1898 fptr->write_lock = rb_mutex_new();
1899 rb_mutex_allow_trap(fptr->write_lock, 1);
1900 }
1901}
1902
1903static inline int
1904io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1905{
1906 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1907 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1908 return 1;
1909
1910 // If the amount of data we want to write exceeds the internal buffer:
1911 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1912 return 1;
1913
1914 // Otherwise, we can append to the internal buffer:
1915 return 0;
1916}
1917
1918static long
1919io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1920{
1921 if (len <= 0) return len;
1922
1923 // Don't write anything if current thread has a pending interrupt:
1925
1926 io_allocate_write_buffer(fptr, !nosync);
1927
1928 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1929 struct binwrite_arg arg;
1930
1931 arg.fptr = fptr;
1932 arg.ptr = ptr;
1933 arg.length = len;
1934
1935 if (!NIL_P(fptr->write_lock)) {
1936 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1937 }
1938 else {
1939 return io_binwrite_string((VALUE)&arg);
1940 }
1941 }
1942 else {
1943 if (fptr->wbuf.off) {
1944 if (fptr->wbuf.len)
1945 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1946 fptr->wbuf.off = 0;
1947 }
1948
1949 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1950 fptr->wbuf.len += (int)len;
1951
1952 return len;
1953 }
1954}
1955
1956# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1957 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1958
1959#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1960 MODE_BTMODE(d, e, f) : \
1961 MODE_BTMODE(a, b, c))
1962
1963static VALUE
1964do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1965{
1966 if (NEED_WRITECONV(fptr)) {
1967 VALUE common_encoding = Qnil;
1968 SET_BINARY_MODE(fptr);
1969
1970 make_writeconv(fptr);
1971
1972 if (fptr->writeconv) {
1973#define fmode (fptr->mode)
1974 if (!NIL_P(fptr->writeconv_asciicompat))
1975 common_encoding = fptr->writeconv_asciicompat;
1976 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1977 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1978 rb_enc_name(rb_enc_get(str)));
1979 }
1980#undef fmode
1981 }
1982 else {
1983 if (fptr->encs.enc2)
1984 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1985 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1986 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1987 }
1988
1989 if (!NIL_P(common_encoding)) {
1990 str = rb_str_encode(str, common_encoding,
1992 *converted = 1;
1993 }
1994
1995 if (fptr->writeconv) {
1997 *converted = 1;
1998 }
1999 }
2000#if RUBY_CRLF_ENVIRONMENT
2001#define fmode (fptr->mode)
2002 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2003 if ((fptr->mode & FMODE_READABLE) &&
2005 setmode(fptr->fd, O_BINARY);
2006 }
2007 else {
2008 setmode(fptr->fd, O_TEXT);
2009 }
2010 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2011 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2012 rb_enc_name(rb_enc_get(str)));
2013 }
2014 }
2015#undef fmode
2016#endif
2017 return str;
2018}
2019
2020static long
2021io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
2022{
2023 int converted = 0;
2024 VALUE tmp;
2025 long n, len;
2026 const char *ptr;
2027
2028#ifdef _WIN32
2029 if (fptr->mode & FMODE_TTY) {
2030 long len = rb_w32_write_console(str, fptr->fd);
2031 if (len > 0) return len;
2032 }
2033#endif
2034
2035 str = do_writeconv(str, fptr, &converted);
2036 if (converted)
2037 OBJ_FREEZE(str);
2038
2039 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2040 RSTRING_GETMEM(tmp, ptr, len);
2041 n = io_binwrite(ptr, len, fptr, nosync);
2042 rb_str_tmp_frozen_release(str, tmp);
2043
2044 return n;
2045}
2046
2047ssize_t
2048rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2049{
2050 rb_io_t *fptr;
2051
2052 GetOpenFile(io, fptr);
2054 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2055}
2056
2057static VALUE
2058io_write(VALUE io, VALUE str, int nosync)
2059{
2060 rb_io_t *fptr;
2061 long n;
2062 VALUE tmp;
2063
2064 io = GetWriteIO(io);
2065 str = rb_obj_as_string(str);
2066 tmp = rb_io_check_io(io);
2067
2068 if (NIL_P(tmp)) {
2069 /* port is not IO, call write method for it. */
2070 return rb_funcall(io, id_write, 1, str);
2071 }
2072
2073 io = tmp;
2074 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2075
2076 GetOpenFile(io, fptr);
2078
2079 n = io_fwrite(str, fptr, nosync);
2080 if (n < 0L) rb_sys_fail_on_write(fptr);
2081
2082 return LONG2FIX(n);
2083}
2084
2085#ifdef HAVE_WRITEV
2086struct binwritev_arg {
2087 rb_io_t *fptr;
2088 struct iovec *iov;
2089 int iovcnt;
2090 size_t total;
2091};
2092
2093static VALUE
2094io_binwritev_internal(VALUE arg)
2095{
2096 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2097
2098 size_t remaining = p->total;
2099 size_t offset = 0;
2100
2101 rb_io_t *fptr = p->fptr;
2102 struct iovec *iov = p->iov;
2103 int iovcnt = p->iovcnt;
2104
2105 while (remaining) {
2106 long result = rb_writev_internal(fptr, iov, iovcnt);
2107
2108 if (result >= 0) {
2109 offset += result;
2110 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2111 if (offset < (size_t)fptr->wbuf.len) {
2112 fptr->wbuf.off += result;
2113 fptr->wbuf.len -= result;
2114 }
2115 else {
2116 offset -= (size_t)fptr->wbuf.len;
2117 fptr->wbuf.off = 0;
2118 fptr->wbuf.len = 0;
2119 }
2120 }
2121
2122 if (offset == p->total) {
2123 return p->total;
2124 }
2125
2126 while (result >= (ssize_t)iov->iov_len) {
2127 /* iovcnt > 0 */
2128 result -= iov->iov_len;
2129 iov->iov_len = 0;
2130 iov++;
2131
2132 if (!--iovcnt) {
2133 // I don't believe this code path can ever occur.
2134 return offset;
2135 }
2136 }
2137
2138 iov->iov_base = (char *)iov->iov_base + result;
2139 iov->iov_len -= result;
2140 }
2141 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2142 rb_io_check_closed(fptr);
2143 }
2144 else {
2145 return -1;
2146 }
2147 }
2148
2149 return offset;
2150}
2151
2152static long
2153io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2154{
2155 // Don't write anything if current thread has a pending interrupt:
2157
2158 if (iovcnt == 0) return 0;
2159
2160 size_t total = 0;
2161 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2162
2163 io_allocate_write_buffer(fptr, 1);
2164
2165 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2166 // The end of the buffered data:
2167 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2168
2169 if (offset + total <= (size_t)fptr->wbuf.capa) {
2170 for (int i = 1; i < iovcnt; i++) {
2171 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2172 offset += iov[i].iov_len;
2173 }
2174
2175 fptr->wbuf.len += total;
2176
2177 return total;
2178 }
2179 else {
2180 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2181 iov[0].iov_len = fptr->wbuf.len;
2182 }
2183 }
2184 else {
2185 // The first iov is reserved for the internal buffer, and it's empty.
2186 iov++;
2187
2188 if (!--iovcnt) {
2189 // If there are no other io vectors we are done.
2190 return 0;
2191 }
2192 }
2193
2194 struct binwritev_arg arg;
2195 arg.fptr = fptr;
2196 arg.iov = iov;
2197 arg.iovcnt = iovcnt;
2198 arg.total = total;
2199
2200 if (!NIL_P(fptr->write_lock)) {
2201 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2202 }
2203 else {
2204 return io_binwritev_internal((VALUE)&arg);
2205 }
2206}
2207
2208static long
2209io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2210{
2211 int i, converted, iovcnt = argc + 1;
2212 long n;
2213 VALUE v1, v2, str, tmp, *tmp_array;
2214 struct iovec *iov;
2215
2216 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2217 tmp_array = ALLOCV_N(VALUE, v2, argc);
2218
2219 for (i = 0; i < argc; i++) {
2220 str = rb_obj_as_string(argv[i]);
2221 converted = 0;
2222 str = do_writeconv(str, fptr, &converted);
2223
2224 if (converted)
2225 OBJ_FREEZE(str);
2226
2227 tmp = rb_str_tmp_frozen_acquire(str);
2228 tmp_array[i] = tmp;
2229
2230 /* iov[0] is reserved for buffer of fptr */
2231 iov[i+1].iov_base = RSTRING_PTR(tmp);
2232 iov[i+1].iov_len = RSTRING_LEN(tmp);
2233 }
2234
2235 n = io_binwritev(iov, iovcnt, fptr);
2236 if (v1) ALLOCV_END(v1);
2237
2238 for (i = 0; i < argc; i++) {
2239 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2240 }
2241
2242 if (v2) ALLOCV_END(v2);
2243
2244 return n;
2245}
2246
2247static int
2248iovcnt_ok(int iovcnt)
2249{
2250#ifdef IOV_MAX
2251 return iovcnt < IOV_MAX;
2252#else /* GNU/Hurd has writev, but no IOV_MAX */
2253 return 1;
2254#endif
2255}
2256#endif /* HAVE_WRITEV */
2257
2258static VALUE
2259io_writev(int argc, const VALUE *argv, VALUE io)
2260{
2261 rb_io_t *fptr;
2262 long n;
2263 VALUE tmp, total = INT2FIX(0);
2264 int i, cnt = 1;
2265
2266 io = GetWriteIO(io);
2267 tmp = rb_io_check_io(io);
2268
2269 if (NIL_P(tmp)) {
2270 /* port is not IO, call write method for it. */
2271 return rb_funcallv(io, id_write, argc, argv);
2272 }
2273
2274 io = tmp;
2275
2276 GetOpenFile(io, fptr);
2278
2279 for (i = 0; i < argc; i += cnt) {
2280#ifdef HAVE_WRITEV
2281 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2282 n = io_fwritev(cnt, &argv[i], fptr);
2283 }
2284 else
2285#endif
2286 {
2287 cnt = 1;
2288 /* sync at last item */
2289 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2290 }
2291
2292 if (n < 0L)
2293 rb_sys_fail_on_write(fptr);
2294
2295 total = rb_fix_plus(LONG2FIX(n), total);
2296 }
2297
2298 return total;
2299}
2300
2301/*
2302 * call-seq:
2303 * write(*objects) -> integer
2304 *
2305 * Writes each of the given +objects+ to +self+,
2306 * which must be opened for writing
2307 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2308 * returns the total number bytes written;
2309 * each of +objects+ that is not a string is converted via method +to_s+:
2310 *
2311 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2312 * $stdout.write('foo', :bar, 2, "\n") # => 8
2313 *
2314 * Output:
2315 *
2316 * Hello, World!
2317 * foobar2
2318 *
2319 * Related: IO#read.
2320 */
2321
2322static VALUE
2323io_write_m(int argc, VALUE *argv, VALUE io)
2324{
2325 if (argc != 1) {
2326 return io_writev(argc, argv, io);
2327 }
2328 else {
2329 VALUE str = argv[0];
2330 return io_write(io, str, 0);
2331 }
2332}
2333
2334VALUE
2335rb_io_write(VALUE io, VALUE str)
2336{
2337 return rb_funcallv(io, id_write, 1, &str);
2338}
2339
2340static VALUE
2341rb_io_writev(VALUE io, int argc, const VALUE *argv)
2342{
2343 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2344 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2345 VALUE klass = CLASS_OF(io);
2346 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2348 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2349 " which accepts just one argument",
2350 klass, sep
2351 );
2352 }
2353
2354 do rb_io_write(io, *argv++); while (--argc);
2355
2356 return Qnil;
2357 }
2358
2359 return rb_funcallv(io, id_write, argc, argv);
2360}
2361
2362/*
2363 * call-seq:
2364 * self << object -> self
2365 *
2366 * Writes the given +object+ to +self+,
2367 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2368 * returns +self+;
2369 * if +object+ is not a string, it is converted via method +to_s+:
2370 *
2371 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2372 * $stdout << 'foo' << :bar << 2 << "\n"
2373 *
2374 * Output:
2375 *
2376 * Hello, World!
2377 * foobar2
2378 *
2379 */
2380
2381
2382VALUE
2384{
2385 rb_io_write(io, str);
2386 return io;
2387}
2388
2389#ifdef HAVE_FSYNC
2390static VALUE
2391nogvl_fsync(void *ptr)
2392{
2393 rb_io_t *fptr = ptr;
2394
2395#ifdef _WIN32
2396 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2397 return 0;
2398#endif
2399 return (VALUE)fsync(fptr->fd);
2400}
2401#endif
2402
2403VALUE
2404rb_io_flush_raw(VALUE io, int sync)
2405{
2406 rb_io_t *fptr;
2407
2408 if (!RB_TYPE_P(io, T_FILE)) {
2409 return rb_funcall(io, id_flush, 0);
2410 }
2411
2412 io = GetWriteIO(io);
2413 GetOpenFile(io, fptr);
2414
2415 if (fptr->mode & FMODE_WRITABLE) {
2416 if (io_fflush(fptr) < 0)
2417 rb_sys_fail_on_write(fptr);
2418 }
2419 if (fptr->mode & FMODE_READABLE) {
2420 io_unread(fptr, true);
2421 }
2422
2423 return io;
2424}
2425
2426/*
2427 * call-seq:
2428 * flush -> self
2429 *
2430 * Flushes data buffered in +self+ to the operating system
2431 * (but does not necessarily flush data buffered in the operating system):
2432 *
2433 * $stdout.print 'no newline' # Not necessarily flushed.
2434 * $stdout.flush # Flushed.
2435 *
2436 */
2437
2438VALUE
2439rb_io_flush(VALUE io)
2440{
2441 return rb_io_flush_raw(io, 1);
2442}
2443
2444/*
2445 * call-seq:
2446 * tell -> integer
2447 *
2448 * Returns the current position (in bytes) in +self+
2449 * (see {Position}[rdoc-ref:IO@Position]):
2450 *
2451 * f = File.open('t.txt')
2452 * f.tell # => 0
2453 * f.gets # => "First line\n"
2454 * f.tell # => 12
2455 * f.close
2456 *
2457 * Related: IO#pos=, IO#seek.
2458 */
2459
2460static VALUE
2461rb_io_tell(VALUE io)
2462{
2463 rb_io_t *fptr;
2464 rb_off_t pos;
2465
2466 GetOpenFile(io, fptr);
2467 pos = io_tell(fptr);
2468 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2469 pos -= fptr->rbuf.len;
2470 return OFFT2NUM(pos);
2471}
2472
2473static VALUE
2474rb_io_seek(VALUE io, VALUE offset, int whence)
2475{
2476 rb_io_t *fptr;
2477 rb_off_t pos;
2478
2479 pos = NUM2OFFT(offset);
2480 GetOpenFile(io, fptr);
2481 pos = io_seek(fptr, pos, whence);
2482 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2483
2484 return INT2FIX(0);
2485}
2486
2487static int
2488interpret_seek_whence(VALUE vwhence)
2489{
2490 if (vwhence == sym_SET)
2491 return SEEK_SET;
2492 if (vwhence == sym_CUR)
2493 return SEEK_CUR;
2494 if (vwhence == sym_END)
2495 return SEEK_END;
2496#ifdef SEEK_DATA
2497 if (vwhence == sym_DATA)
2498 return SEEK_DATA;
2499#endif
2500#ifdef SEEK_HOLE
2501 if (vwhence == sym_HOLE)
2502 return SEEK_HOLE;
2503#endif
2504 return NUM2INT(vwhence);
2505}
2506
2507/*
2508 * call-seq:
2509 * seek(offset, whence = IO::SEEK_SET) -> 0
2510 *
2511 * Seeks to the position given by integer +offset+
2512 * (see {Position}[rdoc-ref:IO@Position])
2513 * and constant +whence+, which is one of:
2514 *
2515 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2516 * Repositions the stream to its current position plus the given +offset+:
2517 *
2518 * f = File.open('t.txt')
2519 * f.tell # => 0
2520 * f.seek(20, :CUR) # => 0
2521 * f.tell # => 20
2522 * f.seek(-10, :CUR) # => 0
2523 * f.tell # => 10
2524 * f.close
2525 *
2526 * - +:END+ or <tt>IO::SEEK_END</tt>:
2527 * Repositions the stream to its end plus the given +offset+:
2528 *
2529 * f = File.open('t.txt')
2530 * f.tell # => 0
2531 * f.seek(0, :END) # => 0 # Repositions to stream end.
2532 * f.tell # => 52
2533 * f.seek(-20, :END) # => 0
2534 * f.tell # => 32
2535 * f.seek(-40, :END) # => 0
2536 * f.tell # => 12
2537 * f.close
2538 *
2539 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2540 * Repositions the stream to the given +offset+:
2541 *
2542 * f = File.open('t.txt')
2543 * f.tell # => 0
2544 * f.seek(20, :SET) # => 0
2545 * f.tell # => 20
2546 * f.seek(40, :SET) # => 0
2547 * f.tell # => 40
2548 * f.close
2549 *
2550 * Related: IO#pos=, IO#tell.
2551 *
2552 */
2553
2554static VALUE
2555rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2556{
2557 VALUE offset, ptrname;
2558 int whence = SEEK_SET;
2559
2560 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2561 whence = interpret_seek_whence(ptrname);
2562 }
2563
2564 return rb_io_seek(io, offset, whence);
2565}
2566
2567/*
2568 * call-seq:
2569 * pos = new_position -> new_position
2570 *
2571 * Seeks to the given +new_position+ (in bytes);
2572 * see {Position}[rdoc-ref:IO@Position]:
2573 *
2574 * f = File.open('t.txt')
2575 * f.tell # => 0
2576 * f.pos = 20 # => 20
2577 * f.tell # => 20
2578 * f.close
2579 *
2580 * Related: IO#seek, IO#tell.
2581 *
2582 */
2583
2584static VALUE
2585rb_io_set_pos(VALUE io, VALUE offset)
2586{
2587 rb_io_t *fptr;
2588 rb_off_t pos;
2589
2590 pos = NUM2OFFT(offset);
2591 GetOpenFile(io, fptr);
2592 pos = io_seek(fptr, pos, SEEK_SET);
2593 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2594
2595 return OFFT2NUM(pos);
2596}
2597
2598static void clear_readconv(rb_io_t *fptr);
2599
2600/*
2601 * call-seq:
2602 * rewind -> 0
2603 *
2604 * Repositions the stream to its beginning,
2605 * setting both the position and the line number to zero;
2606 * see {Position}[rdoc-ref:IO@Position]
2607 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2608 *
2609 * f = File.open('t.txt')
2610 * f.tell # => 0
2611 * f.lineno # => 0
2612 * f.gets # => "First line\n"
2613 * f.tell # => 12
2614 * f.lineno # => 1
2615 * f.rewind # => 0
2616 * f.tell # => 0
2617 * f.lineno # => 0
2618 * f.close
2619 *
2620 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2621 *
2622 */
2623
2624static VALUE
2625rb_io_rewind(VALUE io)
2626{
2627 rb_io_t *fptr;
2628
2629 GetOpenFile(io, fptr);
2630 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2631 if (io == ARGF.current_file) {
2632 ARGF.lineno -= fptr->lineno;
2633 }
2634 fptr->lineno = 0;
2635 if (fptr->readconv) {
2636 clear_readconv(fptr);
2637 }
2638
2639 return INT2FIX(0);
2640}
2641
2642static int
2643fptr_wait_readable(rb_io_t *fptr)
2644{
2645 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2646
2647 if (result)
2648 rb_io_check_closed(fptr);
2649
2650 return result;
2651}
2652
2653static int
2654io_fillbuf(rb_io_t *fptr)
2655{
2656 ssize_t r;
2657
2658 if (fptr->rbuf.ptr == NULL) {
2659 fptr->rbuf.off = 0;
2660 fptr->rbuf.len = 0;
2661 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2662 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2663 }
2664 if (fptr->rbuf.len == 0) {
2665 retry:
2666 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2667
2668 if (r < 0) {
2669 if (fptr_wait_readable(fptr))
2670 goto retry;
2671
2672 int e = errno;
2673 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2674 if (!NIL_P(fptr->pathv)) {
2675 rb_str_append(path, fptr->pathv);
2676 }
2677
2678 rb_syserr_fail_path(e, path);
2679 }
2680 if (r > 0) rb_io_check_closed(fptr);
2681 fptr->rbuf.off = 0;
2682 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2683 if (r == 0)
2684 return -1; /* EOF */
2685 }
2686 return 0;
2687}
2688
2689/*
2690 * call-seq:
2691 * eof -> true or false
2692 *
2693 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2694 * see {Position}[rdoc-ref:IO@Position]:
2695 *
2696 * f = File.open('t.txt')
2697 * f.eof # => false
2698 * f.seek(0, :END) # => 0
2699 * f.eof # => true
2700 * f.close
2701 *
2702 * Raises an exception unless the stream is opened for reading;
2703 * see {Mode}[rdoc-ref:File@Access+Modes].
2704 *
2705 * If +self+ is a stream such as pipe or socket, this method
2706 * blocks until the other end sends some data or closes it:
2707 *
2708 * r, w = IO.pipe
2709 * Thread.new { sleep 1; w.close }
2710 * r.eof? # => true # After 1-second wait.
2711 *
2712 * r, w = IO.pipe
2713 * Thread.new { sleep 1; w.puts "a" }
2714 * r.eof? # => false # After 1-second wait.
2715 *
2716 * r, w = IO.pipe
2717 * r.eof? # blocks forever
2718 *
2719 * Note that this method reads data to the input byte buffer. So
2720 * IO#sysread may not behave as you intend with IO#eof?, unless you
2721 * call IO#rewind first (which is not available for some streams).
2722 */
2723
2724VALUE
2726{
2727 rb_io_t *fptr;
2728
2729 GetOpenFile(io, fptr);
2731
2732 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2733 if (READ_DATA_PENDING(fptr)) return Qfalse;
2734 READ_CHECK(fptr);
2735#if RUBY_CRLF_ENVIRONMENT
2736 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2737 return RBOOL(eof(fptr->fd));
2738 }
2739#endif
2740 return RBOOL(io_fillbuf(fptr) < 0);
2741}
2742
2743/*
2744 * call-seq:
2745 * sync -> true or false
2746 *
2747 * Returns the current sync mode of the stream.
2748 * When sync mode is true, all output is immediately flushed to the underlying
2749 * operating system and is not buffered by Ruby internally. See also #fsync.
2750 *
2751 * f = File.open('t.tmp', 'w')
2752 * f.sync # => false
2753 * f.sync = true
2754 * f.sync # => true
2755 * f.close
2756 *
2757 */
2758
2759static VALUE
2760rb_io_sync(VALUE io)
2761{
2762 rb_io_t *fptr;
2763
2764 io = GetWriteIO(io);
2765 GetOpenFile(io, fptr);
2766 return RBOOL(fptr->mode & FMODE_SYNC);
2767}
2768
2769#ifdef HAVE_FSYNC
2770
2771/*
2772 * call-seq:
2773 * sync = boolean -> boolean
2774 *
2775 * Sets the _sync_ _mode_ for the stream to the given value;
2776 * returns the given value.
2777 *
2778 * Values for the sync mode:
2779 *
2780 * - +true+: All output is immediately flushed to the
2781 * underlying operating system and is not buffered internally.
2782 * - +false+: Output may be buffered internally.
2783 *
2784 * Example;
2785 *
2786 * f = File.open('t.tmp', 'w')
2787 * f.sync # => false
2788 * f.sync = true
2789 * f.sync # => true
2790 * f.close
2791 *
2792 * Related: IO#fsync.
2793 *
2794 */
2795
2796static VALUE
2797rb_io_set_sync(VALUE io, VALUE sync)
2798{
2799 rb_io_t *fptr;
2800
2801 io = GetWriteIO(io);
2802 GetOpenFile(io, fptr);
2803 if (RTEST(sync)) {
2804 fptr->mode |= FMODE_SYNC;
2805 }
2806 else {
2807 fptr->mode &= ~FMODE_SYNC;
2808 }
2809 return sync;
2810}
2811
2812/*
2813 * call-seq:
2814 * fsync -> 0
2815 *
2816 * Immediately writes to disk all data buffered in the stream,
2817 * via the operating system's <tt>fsync(2)</tt>.
2818
2819 * Note this difference:
2820 *
2821 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2822 * but does not guarantee that the operating system actually writes the data to disk.
2823 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2824 * and that data is written to disk.
2825 *
2826 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2827 *
2828 */
2829
2830static VALUE
2831rb_io_fsync(VALUE io)
2832{
2833 rb_io_t *fptr;
2834
2835 io = GetWriteIO(io);
2836 GetOpenFile(io, fptr);
2837
2838 if (io_fflush(fptr) < 0)
2839 rb_sys_fail_on_write(fptr);
2840
2841 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2842 rb_sys_fail_path(fptr->pathv);
2843
2844 return INT2FIX(0);
2845}
2846#else
2847# define rb_io_fsync rb_f_notimplement
2848# define rb_io_sync rb_f_notimplement
2849static VALUE
2850rb_io_set_sync(VALUE io, VALUE sync)
2851{
2854}
2855#endif
2856
2857#ifdef HAVE_FDATASYNC
2858static VALUE
2859nogvl_fdatasync(void *ptr)
2860{
2861 rb_io_t *fptr = ptr;
2862
2863#ifdef _WIN32
2864 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2865 return 0;
2866#endif
2867 return (VALUE)fdatasync(fptr->fd);
2868}
2869
2870/*
2871 * call-seq:
2872 * fdatasync -> 0
2873 *
2874 * Immediately writes to disk all data buffered in the stream,
2875 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2876 * otherwise via <tt>fsync(2)</tt>, if supported;
2877 * otherwise raises an exception.
2878 *
2879 */
2880
2881static VALUE
2882rb_io_fdatasync(VALUE io)
2883{
2884 rb_io_t *fptr;
2885
2886 io = GetWriteIO(io);
2887 GetOpenFile(io, fptr);
2888
2889 if (io_fflush(fptr) < 0)
2890 rb_sys_fail_on_write(fptr);
2891
2892 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2893 return INT2FIX(0);
2894
2895 /* fall back */
2896 return rb_io_fsync(io);
2897}
2898#else
2899#define rb_io_fdatasync rb_io_fsync
2900#endif
2901
2902/*
2903 * call-seq:
2904 * fileno -> integer
2905 *
2906 * Returns the integer file descriptor for the stream:
2907 *
2908 * $stdin.fileno # => 0
2909 * $stdout.fileno # => 1
2910 * $stderr.fileno # => 2
2911 * File.open('t.txt').fileno # => 10
2912 * f.close
2913 *
2914 */
2915
2916static VALUE
2917rb_io_fileno(VALUE io)
2918{
2919 rb_io_t *fptr = RFILE(io)->fptr;
2920 int fd;
2921
2922 rb_io_check_closed(fptr);
2923 fd = fptr->fd;
2924 return INT2FIX(fd);
2925}
2926
2927int
2929{
2930 if (RB_TYPE_P(io, T_FILE)) {
2931 rb_io_t *fptr = RFILE(io)->fptr;
2932 rb_io_check_closed(fptr);
2933 return fptr->fd;
2934 }
2935 else {
2936 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2937 if (!UNDEF_P(fileno)) {
2938 return RB_NUM2INT(fileno);
2939 }
2940 }
2941
2942 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2943
2945}
2946
2947int
2948rb_io_mode(VALUE io)
2949{
2950 rb_io_t *fptr;
2951 GetOpenFile(io, fptr);
2952 return fptr->mode;
2953}
2954
2955/*
2956 * call-seq:
2957 * pid -> integer or nil
2958 *
2959 * Returns the process ID of a child process associated with the stream,
2960 * which will have been set by IO#popen, or +nil+ if the stream was not
2961 * created by IO#popen:
2962 *
2963 * pipe = IO.popen("-")
2964 * if pipe
2965 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2966 * else
2967 * $stderr.puts "In child, pid is #{$$}"
2968 * end
2969 *
2970 * Output:
2971 *
2972 * In child, pid is 26209
2973 * In parent, child pid is 26209
2974 *
2975 */
2976
2977static VALUE
2978rb_io_pid(VALUE io)
2979{
2980 rb_io_t *fptr;
2981
2982 GetOpenFile(io, fptr);
2983 if (!fptr->pid)
2984 return Qnil;
2985 return PIDT2NUM(fptr->pid);
2986}
2987
2988/*
2989 * call-seq:
2990 * path -> string or nil
2991 *
2992 * Returns the path associated with the IO, or +nil+ if there is no path
2993 * associated with the IO. It is not guaranteed that the path exists on
2994 * the filesystem.
2995 *
2996 * $stdin.path # => "<STDIN>"
2997 *
2998 * File.open("testfile") {|f| f.path} # => "testfile"
2999 */
3000
3001VALUE
3003{
3004 rb_io_t *fptr = RFILE(io)->fptr;
3005
3006 if (!fptr)
3007 return Qnil;
3008
3009 return rb_obj_dup(fptr->pathv);
3010}
3011
3012/*
3013 * call-seq:
3014 * inspect -> string
3015 *
3016 * Returns a string representation of +self+:
3017 *
3018 * f = File.open('t.txt')
3019 * f.inspect # => "#<File:t.txt>"
3020 * f.close
3021 *
3022 */
3023
3024static VALUE
3025rb_io_inspect(VALUE obj)
3026{
3027 rb_io_t *fptr;
3028 VALUE result;
3029 static const char closed[] = " (closed)";
3030
3031 fptr = RFILE(obj)->fptr;
3032 if (!fptr) return rb_any_to_s(obj);
3033 result = rb_str_new_cstr("#<");
3034 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3035 rb_str_cat2(result, ":");
3036 if (NIL_P(fptr->pathv)) {
3037 if (fptr->fd < 0) {
3038 rb_str_cat(result, closed+1, strlen(closed)-1);
3039 }
3040 else {
3041 rb_str_catf(result, "fd %d", fptr->fd);
3042 }
3043 }
3044 else {
3045 rb_str_append(result, fptr->pathv);
3046 if (fptr->fd < 0) {
3047 rb_str_cat(result, closed, strlen(closed));
3048 }
3049 }
3050 return rb_str_cat2(result, ">");
3051}
3052
3053/*
3054 * call-seq:
3055 * to_io -> self
3056 *
3057 * Returns +self+.
3058 *
3059 */
3060
3061static VALUE
3062rb_io_to_io(VALUE io)
3063{
3064 return io;
3065}
3066
3067/* reading functions */
3068static long
3069read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3070{
3071 int n;
3072
3073 n = READ_DATA_PENDING_COUNT(fptr);
3074 if (n <= 0) return 0;
3075 if (n > len) n = (int)len;
3076 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3077 fptr->rbuf.off += n;
3078 fptr->rbuf.len -= n;
3079 return n;
3080}
3081
3082static long
3083io_bufread(char *ptr, long len, rb_io_t *fptr)
3084{
3085 long offset = 0;
3086 long n = len;
3087 long c;
3088
3089 if (READ_DATA_PENDING(fptr) == 0) {
3090 while (n > 0) {
3091 again:
3092 rb_io_check_closed(fptr);
3093 c = rb_io_read_memory(fptr, ptr+offset, n);
3094 if (c == 0) break;
3095 if (c < 0) {
3096 if (fptr_wait_readable(fptr))
3097 goto again;
3098 return -1;
3099 }
3100 offset += c;
3101 if ((n -= c) <= 0) break;
3102 }
3103 return len - n;
3104 }
3105
3106 while (n > 0) {
3107 c = read_buffered_data(ptr+offset, n, fptr);
3108 if (c > 0) {
3109 offset += c;
3110 if ((n -= c) <= 0) break;
3111 }
3112 rb_io_check_closed(fptr);
3113 if (io_fillbuf(fptr) < 0) {
3114 break;
3115 }
3116 }
3117 return len - n;
3118}
3119
3120static int io_setstrbuf(VALUE *str, long len);
3121
3123 char *str_ptr;
3124 long len;
3125 rb_io_t *fptr;
3126};
3127
3128static VALUE
3129bufread_call(VALUE arg)
3130{
3131 struct bufread_arg *p = (struct bufread_arg *)arg;
3132 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3133 return Qundef;
3134}
3135
3136static long
3137io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3138{
3139 long len;
3140 struct bufread_arg arg;
3141
3142 io_setstrbuf(&str, offset + size);
3143 arg.str_ptr = RSTRING_PTR(str) + offset;
3144 arg.len = size;
3145 arg.fptr = fptr;
3146 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3147 len = arg.len;
3148 if (len < 0) rb_sys_fail_path(fptr->pathv);
3149 return len;
3150}
3151
3152static long
3153remain_size(rb_io_t *fptr)
3154{
3155 struct stat st;
3156 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3157 rb_off_t pos;
3158
3159 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3160#if defined(__HAIKU__)
3161 && (st.st_dev > 3)
3162#endif
3163 )
3164 {
3165 if (io_fflush(fptr) < 0)
3166 rb_sys_fail_on_write(fptr);
3167 pos = lseek(fptr->fd, 0, SEEK_CUR);
3168 if (st.st_size >= pos && pos >= 0) {
3169 siz += st.st_size - pos;
3170 if (siz > LONG_MAX) {
3171 rb_raise(rb_eIOError, "file too big for single read");
3172 }
3173 }
3174 }
3175 else {
3176 siz += BUFSIZ;
3177 }
3178 return (long)siz;
3179}
3180
3181static VALUE
3182io_enc_str(VALUE str, rb_io_t *fptr)
3183{
3184 rb_enc_associate(str, io_read_encoding(fptr));
3185 return str;
3186}
3187
3188static void
3189make_readconv(rb_io_t *fptr, int size)
3190{
3191 if (!fptr->readconv) {
3192 int ecflags;
3193 VALUE ecopts;
3194 const char *sname, *dname;
3195 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3196 ecopts = fptr->encs.ecopts;
3197 if (fptr->encs.enc2) {
3198 sname = rb_enc_name(fptr->encs.enc2);
3199 dname = rb_enc_name(io_read_encoding(fptr));
3200 }
3201 else {
3202 sname = dname = "";
3203 }
3204 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3205 if (!fptr->readconv)
3206 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3207 fptr->cbuf.off = 0;
3208 fptr->cbuf.len = 0;
3209 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3210 fptr->cbuf.capa = size;
3211 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3212 }
3213}
3214
3215#define MORE_CHAR_SUSPENDED Qtrue
3216#define MORE_CHAR_FINISHED Qnil
3217static VALUE
3218fill_cbuf(rb_io_t *fptr, int ec_flags)
3219{
3220 const unsigned char *ss, *sp, *se;
3221 unsigned char *ds, *dp, *de;
3223 int putbackable;
3224 int cbuf_len0;
3225 VALUE exc;
3226
3227 ec_flags |= ECONV_PARTIAL_INPUT;
3228
3229 if (fptr->cbuf.len == fptr->cbuf.capa)
3230 return MORE_CHAR_SUSPENDED; /* cbuf full */
3231 if (fptr->cbuf.len == 0)
3232 fptr->cbuf.off = 0;
3233 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3234 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3235 fptr->cbuf.off = 0;
3236 }
3237
3238 cbuf_len0 = fptr->cbuf.len;
3239
3240 while (1) {
3241 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3242 se = sp + fptr->rbuf.len;
3243 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3244 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3245 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3246 fptr->rbuf.off += (int)(sp - ss);
3247 fptr->rbuf.len -= (int)(sp - ss);
3248 fptr->cbuf.len += (int)(dp - ds);
3249
3250 putbackable = rb_econv_putbackable(fptr->readconv);
3251 if (putbackable) {
3252 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3253 fptr->rbuf.off -= putbackable;
3254 fptr->rbuf.len += putbackable;
3255 }
3256
3257 exc = rb_econv_make_exception(fptr->readconv);
3258 if (!NIL_P(exc))
3259 return exc;
3260
3261 if (cbuf_len0 != fptr->cbuf.len)
3262 return MORE_CHAR_SUSPENDED;
3263
3264 if (res == econv_finished) {
3265 return MORE_CHAR_FINISHED;
3266 }
3267
3268 if (res == econv_source_buffer_empty) {
3269 if (fptr->rbuf.len == 0) {
3270 READ_CHECK(fptr);
3271 if (io_fillbuf(fptr) < 0) {
3272 if (!fptr->readconv) {
3273 return MORE_CHAR_FINISHED;
3274 }
3275 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3276 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3277 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3278 fptr->cbuf.len += (int)(dp - ds);
3280 break;
3281 }
3282 }
3283 }
3284 }
3285 if (cbuf_len0 != fptr->cbuf.len)
3286 return MORE_CHAR_SUSPENDED;
3287
3288 return MORE_CHAR_FINISHED;
3289}
3290
3291static VALUE
3292more_char(rb_io_t *fptr)
3293{
3294 VALUE v;
3295 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3296 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3297 rb_exc_raise(v);
3298 return v;
3299}
3300
3301static VALUE
3302io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3303{
3304 VALUE str = Qnil;
3305 if (strp) {
3306 str = *strp;
3307 if (NIL_P(str)) {
3308 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3309 }
3310 else {
3311 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3312 }
3313 rb_enc_associate(str, fptr->encs.enc);
3314 }
3315 fptr->cbuf.off += len;
3316 fptr->cbuf.len -= len;
3317 /* xxx: set coderange */
3318 if (fptr->cbuf.len == 0)
3319 fptr->cbuf.off = 0;
3320 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3321 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3322 fptr->cbuf.off = 0;
3323 }
3324 return str;
3325}
3326
3327static int
3328io_setstrbuf(VALUE *str, long len)
3329{
3330 if (NIL_P(*str)) {
3331 *str = rb_str_new(0, len);
3332 return TRUE;
3333 }
3334 else {
3335 VALUE s = StringValue(*str);
3336 rb_str_modify(s);
3337
3338 long clen = RSTRING_LEN(s);
3339 if (clen >= len) {
3340 return FALSE;
3341 }
3342 len -= clen;
3343 }
3344 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3346 }
3347 return FALSE;
3348}
3349
3350#define MAX_REALLOC_GAP 4096
3351static void
3352io_shrink_read_string(VALUE str, long n)
3353{
3354 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3355 rb_str_resize(str, n);
3356 }
3357}
3358
3359static void
3360io_set_read_length(VALUE str, long n, int shrinkable)
3361{
3362 if (RSTRING_LEN(str) != n) {
3363 rb_str_modify(str);
3364 rb_str_set_len(str, n);
3365 if (shrinkable) io_shrink_read_string(str, n);
3366 }
3367}
3368
3369static VALUE
3370read_all(rb_io_t *fptr, long siz, VALUE str)
3371{
3372 long bytes;
3373 long n;
3374 long pos;
3375 rb_encoding *enc;
3376 int cr;
3377 int shrinkable;
3378
3379 if (NEED_READCONV(fptr)) {
3380 int first = !NIL_P(str);
3381 SET_BINARY_MODE(fptr);
3382 shrinkable = io_setstrbuf(&str,0);
3383 make_readconv(fptr, 0);
3384 while (1) {
3385 VALUE v;
3386 if (fptr->cbuf.len) {
3387 if (first) rb_str_set_len(str, first = 0);
3388 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3389 }
3390 v = fill_cbuf(fptr, 0);
3391 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3392 if (fptr->cbuf.len) {
3393 if (first) rb_str_set_len(str, first = 0);
3394 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3395 }
3396 rb_exc_raise(v);
3397 }
3398 if (v == MORE_CHAR_FINISHED) {
3399 clear_readconv(fptr);
3400 if (first) rb_str_set_len(str, first = 0);
3401 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3402 return io_enc_str(str, fptr);
3403 }
3404 }
3405 }
3406
3407 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3408 bytes = 0;
3409 pos = 0;
3410
3411 enc = io_read_encoding(fptr);
3412 cr = 0;
3413
3414 if (siz == 0) siz = BUFSIZ;
3415 shrinkable = io_setstrbuf(&str, siz);
3416 for (;;) {
3417 READ_CHECK(fptr);
3418 n = io_fread(str, bytes, siz - bytes, fptr);
3419 if (n == 0 && bytes == 0) {
3420 rb_str_set_len(str, 0);
3421 break;
3422 }
3423 bytes += n;
3424 rb_str_set_len(str, bytes);
3425 if (cr != ENC_CODERANGE_BROKEN)
3426 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3427 if (bytes < siz) break;
3428 siz += BUFSIZ;
3429
3430 size_t capa = rb_str_capacity(str);
3431 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3432 if (capa < BUFSIZ) {
3433 capa = BUFSIZ;
3434 }
3435 else if (capa > IO_MAX_BUFFER_GROWTH) {
3436 capa = IO_MAX_BUFFER_GROWTH;
3437 }
3439 }
3440 }
3441 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3442 str = io_enc_str(str, fptr);
3443 ENC_CODERANGE_SET(str, cr);
3444 return str;
3445}
3446
3447void
3449{
3450 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3451 rb_sys_fail_path(fptr->pathv);
3452 }
3453}
3454
3455static VALUE
3456io_read_memory_call(VALUE arg)
3457{
3458 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3459
3460 VALUE scheduler = rb_fiber_scheduler_current();
3461 if (scheduler != Qnil) {
3462 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3463
3464 if (!UNDEF_P(result)) {
3465 // This is actually returned as a pseudo-VALUE and later cast to a long:
3467 }
3468 }
3469
3470 if (iis->nonblock) {
3471 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3472 }
3473 else {
3474 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3475 }
3476}
3477
3478static long
3479io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3480{
3481 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3482}
3483
3484#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3485
3486static VALUE
3487io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3488{
3489 rb_io_t *fptr;
3490 VALUE length, str;
3491 long n, len;
3492 struct io_internal_read_struct iis;
3493 int shrinkable;
3494
3495 rb_scan_args(argc, argv, "11", &length, &str);
3496
3497 if ((len = NUM2LONG(length)) < 0) {
3498 rb_raise(rb_eArgError, "negative length %ld given", len);
3499 }
3500
3501 shrinkable = io_setstrbuf(&str, len);
3502
3503 GetOpenFile(io, fptr);
3505
3506 if (len == 0) {
3507 io_set_read_length(str, 0, shrinkable);
3508 return str;
3509 }
3510
3511 if (!nonblock)
3512 READ_CHECK(fptr);
3513 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3514 if (n <= 0) {
3515 again:
3516 if (nonblock) {
3517 rb_io_set_nonblock(fptr);
3518 }
3519 io_setstrbuf(&str, len);
3520 iis.th = rb_thread_current();
3521 iis.fptr = fptr;
3522 iis.nonblock = nonblock;
3523 iis.fd = fptr->fd;
3524 iis.buf = RSTRING_PTR(str);
3525 iis.capa = len;
3526 iis.timeout = NULL;
3527 n = io_read_memory_locktmp(str, &iis);
3528 if (n < 0) {
3529 int e = errno;
3530 if (!nonblock && fptr_wait_readable(fptr))
3531 goto again;
3532 if (nonblock && (io_again_p(e))) {
3533 if (no_exception)
3534 return sym_wait_readable;
3535 else
3536 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3537 e, "read would block");
3538 }
3539 rb_syserr_fail_path(e, fptr->pathv);
3540 }
3541 }
3542 io_set_read_length(str, n, shrinkable);
3543
3544 if (n == 0)
3545 return Qnil;
3546 else
3547 return str;
3548}
3549
3550/*
3551 * call-seq:
3552 * readpartial(maxlen) -> string
3553 * readpartial(maxlen, out_string) -> out_string
3554 *
3555 * Reads up to +maxlen+ bytes from the stream;
3556 * returns a string (either a new string or the given +out_string+).
3557 * Its encoding is:
3558 *
3559 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3560 * - ASCII-8BIT, otherwise.
3561 *
3562 * - Contains +maxlen+ bytes from the stream, if available.
3563 * - Otherwise contains all available bytes, if any available.
3564 * - Otherwise is an empty string.
3565 *
3566 * With the single non-negative integer argument +maxlen+ given,
3567 * returns a new string:
3568 *
3569 * f = File.new('t.txt')
3570 * f.readpartial(20) # => "First line\nSecond l"
3571 * f.readpartial(20) # => "ine\n\nFourth line\n"
3572 * f.readpartial(20) # => "Fifth line\n"
3573 * f.readpartial(20) # Raises EOFError.
3574 * f.close
3575 *
3576 * With both argument +maxlen+ and string argument +out_string+ given,
3577 * returns modified +out_string+:
3578 *
3579 * f = File.new('t.txt')
3580 * s = 'foo'
3581 * f.readpartial(20, s) # => "First line\nSecond l"
3582 * s = 'bar'
3583 * f.readpartial(0, s) # => ""
3584 * f.close
3585 *
3586 * This method is useful for a stream such as a pipe, a socket, or a tty.
3587 * It blocks only when no data is immediately available.
3588 * This means that it blocks only when _all_ of the following are true:
3589 *
3590 * - The byte buffer in the stream is empty.
3591 * - The content of the stream is empty.
3592 * - The stream is not at EOF.
3593 *
3594 * When blocked, the method waits for either more data or EOF on the stream:
3595 *
3596 * - If more data is read, the method returns the data.
3597 * - If EOF is reached, the method raises EOFError.
3598 *
3599 * When not blocked, the method responds immediately:
3600 *
3601 * - Returns data from the buffer if there is any.
3602 * - Otherwise returns data from the stream if there is any.
3603 * - Otherwise raises EOFError if the stream has reached EOF.
3604 *
3605 * Note that this method is similar to sysread. The differences are:
3606 *
3607 * - If the byte buffer is not empty, read from the byte buffer
3608 * instead of "sysread for buffered IO (IOError)".
3609 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3610 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3611 * readpartial retries the system call.
3612 *
3613 * The latter means that readpartial is non-blocking-flag insensitive.
3614 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3615 * if the fd is blocking mode.
3616 *
3617 * Examples:
3618 *
3619 * # # Returned Buffer Content Pipe Content
3620 * r, w = IO.pipe #
3621 * w << 'abc' # "" "abc".
3622 * r.readpartial(4096) # => "abc" "" ""
3623 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3624 *
3625 * # # Returned Buffer Content Pipe Content
3626 * r, w = IO.pipe #
3627 * w << 'abc' # "" "abc"
3628 * w.close # "" "abc" EOF
3629 * r.readpartial(4096) # => "abc" "" EOF
3630 * r.readpartial(4096) # raises EOFError
3631 *
3632 * # # Returned Buffer Content Pipe Content
3633 * r, w = IO.pipe #
3634 * w << "abc\ndef\n" # "" "abc\ndef\n"
3635 * r.gets # => "abc\n" "def\n" ""
3636 * w << "ghi\n" # "def\n" "ghi\n"
3637 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3638 * r.readpartial(4096) # => "ghi\n" "" ""
3639 *
3640 */
3641
3642static VALUE
3643io_readpartial(int argc, VALUE *argv, VALUE io)
3644{
3645 VALUE ret;
3646
3647 ret = io_getpartial(argc, argv, io, Qnil, 0);
3648 if (NIL_P(ret))
3649 rb_eof_error();
3650 return ret;
3651}
3652
3653static VALUE
3654io_nonblock_eof(int no_exception)
3655{
3656 if (!no_exception) {
3657 rb_eof_error();
3658 }
3659 return Qnil;
3660}
3661
3662/* :nodoc: */
3663static VALUE
3664io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3665{
3666 rb_io_t *fptr;
3667 long n, len;
3668 struct io_internal_read_struct iis;
3669 int shrinkable;
3670
3671 if ((len = NUM2LONG(length)) < 0) {
3672 rb_raise(rb_eArgError, "negative length %ld given", len);
3673 }
3674
3675 shrinkable = io_setstrbuf(&str, len);
3676 rb_bool_expected(ex, "exception", TRUE);
3677
3678 GetOpenFile(io, fptr);
3680
3681 if (len == 0) {
3682 io_set_read_length(str, 0, shrinkable);
3683 return str;
3684 }
3685
3686 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3687 if (n <= 0) {
3688 rb_fd_set_nonblock(fptr->fd);
3689 shrinkable |= io_setstrbuf(&str, len);
3690 iis.fptr = fptr;
3691 iis.nonblock = 1;
3692 iis.fd = fptr->fd;
3693 iis.buf = RSTRING_PTR(str);
3694 iis.capa = len;
3695 iis.timeout = NULL;
3696 n = io_read_memory_locktmp(str, &iis);
3697 if (n < 0) {
3698 int e = errno;
3699 if (io_again_p(e)) {
3700 if (!ex) return sym_wait_readable;
3701 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3702 e, "read would block");
3703 }
3704 rb_syserr_fail_path(e, fptr->pathv);
3705 }
3706 }
3707 io_set_read_length(str, n, shrinkable);
3708
3709 if (n == 0) {
3710 if (!ex) return Qnil;
3711 rb_eof_error();
3712 }
3713
3714 return str;
3715}
3716
3717/* :nodoc: */
3718static VALUE
3719io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3720{
3721 rb_io_t *fptr;
3722 long n;
3723
3724 if (!RB_TYPE_P(str, T_STRING))
3725 str = rb_obj_as_string(str);
3726 rb_bool_expected(ex, "exception", TRUE);
3727
3728 io = GetWriteIO(io);
3729 GetOpenFile(io, fptr);
3731
3732 if (io_fflush(fptr) < 0)
3733 rb_sys_fail_on_write(fptr);
3734
3735 rb_fd_set_nonblock(fptr->fd);
3736 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3737 RB_GC_GUARD(str);
3738
3739 if (n < 0) {
3740 int e = errno;
3741 if (io_again_p(e)) {
3742 if (!ex) {
3743 return sym_wait_writable;
3744 }
3745 else {
3746 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3747 }
3748 }
3749 rb_syserr_fail_path(e, fptr->pathv);
3750 }
3751
3752 return LONG2FIX(n);
3753}
3754
3755/*
3756 * call-seq:
3757 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3758 *
3759 * Reads bytes from the stream; the stream must be opened for reading
3760 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3761 *
3762 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3763 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3764 *
3765 * Returns a string (either a new string or the given +out_string+)
3766 * containing the bytes read.
3767 * The encoding of the string depends on both +maxLen+ and +out_string+:
3768 *
3769 * - +maxlen+ is +nil+: uses internal encoding of +self+
3770 * (regardless of whether +out_string+ was given).
3771 * - +maxlen+ not +nil+:
3772 *
3773 * - +out_string+ given: encoding of +out_string+ not modified.
3774 * - +out_string+ not given: ASCII-8BIT is used.
3775 *
3776 * <b>Without Argument +out_string+</b>
3777 *
3778 * When argument +out_string+ is omitted,
3779 * the returned value is a new string:
3780 *
3781 * f = File.new('t.txt')
3782 * f.read
3783 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3784 * f.rewind
3785 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3786 * f.read(30) # => "rth line\r\nFifth line\r\n"
3787 * f.read(30) # => nil
3788 * f.close
3789 *
3790 * If +maxlen+ is zero, returns an empty string.
3791 *
3792 * <b> With Argument +out_string+</b>
3793 *
3794 * When argument +out_string+ is given,
3795 * the returned value is +out_string+, whose content is replaced:
3796 *
3797 * f = File.new('t.txt')
3798 * s = 'foo' # => "foo"
3799 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3800 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3801 * f.rewind
3802 * s = 'bar'
3803 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3804 * s # => "First line\r\nSecond line\r\n\r\nFou"
3805 * s = 'baz'
3806 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3807 * s # => "rth line\r\nFifth line\r\n"
3808 * s = 'bat'
3809 * f.read(30, s) # => nil
3810 * s # => ""
3811 * f.close
3812 *
3813 * Note that this method behaves like the fread() function in C.
3814 * This means it retries to invoke read(2) system calls to read data
3815 * with the specified maxlen (or until EOF).
3816 *
3817 * This behavior is preserved even if the stream is in non-blocking mode.
3818 * (This method is non-blocking-flag insensitive as other methods.)
3819 *
3820 * If you need the behavior like a single read(2) system call,
3821 * consider #readpartial, #read_nonblock, and #sysread.
3822 *
3823 * Related: IO#write.
3824 */
3825
3826static VALUE
3827io_read(int argc, VALUE *argv, VALUE io)
3828{
3829 rb_io_t *fptr;
3830 long n, len;
3831 VALUE length, str;
3832 int shrinkable;
3833#if RUBY_CRLF_ENVIRONMENT
3834 int previous_mode;
3835#endif
3836
3837 rb_scan_args(argc, argv, "02", &length, &str);
3838
3839 if (NIL_P(length)) {
3840 GetOpenFile(io, fptr);
3842 return read_all(fptr, remain_size(fptr), str);
3843 }
3844 len = NUM2LONG(length);
3845 if (len < 0) {
3846 rb_raise(rb_eArgError, "negative length %ld given", len);
3847 }
3848
3849 shrinkable = io_setstrbuf(&str,len);
3850
3851 GetOpenFile(io, fptr);
3853 if (len == 0) {
3854 io_set_read_length(str, 0, shrinkable);
3855 return str;
3856 }
3857
3858 READ_CHECK(fptr);
3859#if RUBY_CRLF_ENVIRONMENT
3860 previous_mode = set_binary_mode_with_seek_cur(fptr);
3861#endif
3862 n = io_fread(str, 0, len, fptr);
3863 io_set_read_length(str, n, shrinkable);
3864#if RUBY_CRLF_ENVIRONMENT
3865 if (previous_mode == O_TEXT) {
3866 setmode(fptr->fd, O_TEXT);
3867 }
3868#endif
3869 if (n == 0) return Qnil;
3870
3871 return str;
3872}
3873
3874static void
3875rscheck(const char *rsptr, long rslen, VALUE rs)
3876{
3877 if (!rs) return;
3878 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3879 rb_raise(rb_eRuntimeError, "rs modified");
3880}
3881
3882static const char *
3883search_delim(const char *p, long len, int delim, rb_encoding *enc)
3884{
3885 if (rb_enc_mbminlen(enc) == 1) {
3886 p = memchr(p, delim, len);
3887 if (p) return p + 1;
3888 }
3889 else {
3890 const char *end = p + len;
3891 while (p < end) {
3892 int r = rb_enc_precise_mbclen(p, end, enc);
3893 if (!MBCLEN_CHARFOUND_P(r)) {
3894 p += rb_enc_mbminlen(enc);
3895 continue;
3896 }
3897 int n = MBCLEN_CHARFOUND_LEN(r);
3898 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3899 return p + n;
3900 }
3901 p += n;
3902 }
3903 }
3904 return NULL;
3905}
3906
3907static int
3908appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3909{
3910 VALUE str = *strp;
3911 long limit = *lp;
3912
3913 if (NEED_READCONV(fptr)) {
3914 SET_BINARY_MODE(fptr);
3915 make_readconv(fptr, 0);
3916 do {
3917 const char *p, *e;
3918 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3919 if (searchlen) {
3920 p = READ_CHAR_PENDING_PTR(fptr);
3921 if (0 < limit && limit < searchlen)
3922 searchlen = (int)limit;
3923 e = search_delim(p, searchlen, delim, enc);
3924 if (e) {
3925 int len = (int)(e-p);
3926 if (NIL_P(str))
3927 *strp = str = rb_str_new(p, len);
3928 else
3929 rb_str_buf_cat(str, p, len);
3930 fptr->cbuf.off += len;
3931 fptr->cbuf.len -= len;
3932 limit -= len;
3933 *lp = limit;
3934 return delim;
3935 }
3936
3937 if (NIL_P(str))
3938 *strp = str = rb_str_new(p, searchlen);
3939 else
3940 rb_str_buf_cat(str, p, searchlen);
3941 fptr->cbuf.off += searchlen;
3942 fptr->cbuf.len -= searchlen;
3943 limit -= searchlen;
3944
3945 if (limit == 0) {
3946 *lp = limit;
3947 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3948 }
3949 }
3950 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3951 clear_readconv(fptr);
3952 *lp = limit;
3953 return EOF;
3954 }
3955
3956 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3957 do {
3958 long pending = READ_DATA_PENDING_COUNT(fptr);
3959 if (pending > 0) {
3960 const char *p = READ_DATA_PENDING_PTR(fptr);
3961 const char *e;
3962 long last;
3963
3964 if (limit > 0 && pending > limit) pending = limit;
3965 e = search_delim(p, pending, delim, enc);
3966 if (e) pending = e - p;
3967 if (!NIL_P(str)) {
3968 last = RSTRING_LEN(str);
3969 rb_str_resize(str, last + pending);
3970 }
3971 else {
3972 last = 0;
3973 *strp = str = rb_str_buf_new(pending);
3974 rb_str_set_len(str, pending);
3975 }
3976 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3977 limit -= pending;
3978 *lp = limit;
3979 if (e) return delim;
3980 if (limit == 0)
3981 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3982 }
3983 READ_CHECK(fptr);
3984 } while (io_fillbuf(fptr) >= 0);
3985 *lp = limit;
3986 return EOF;
3987}
3988
3989static inline int
3990swallow(rb_io_t *fptr, int term)
3991{
3992 if (NEED_READCONV(fptr)) {
3993 rb_encoding *enc = io_read_encoding(fptr);
3994 int needconv = rb_enc_mbminlen(enc) != 1;
3995 SET_BINARY_MODE(fptr);
3996 make_readconv(fptr, 0);
3997 do {
3998 size_t cnt;
3999 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4000 const char *p = READ_CHAR_PENDING_PTR(fptr);
4001 int i;
4002 if (!needconv) {
4003 if (*p != term) return TRUE;
4004 i = (int)cnt;
4005 while (--i && *++p == term);
4006 }
4007 else {
4008 const char *e = p + cnt;
4009 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4010 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4011 i = (int)(e - p);
4012 }
4013 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4014 }
4015 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4016 return FALSE;
4017 }
4018
4019 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4020 do {
4021 size_t cnt;
4022 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4023 char buf[1024];
4024 const char *p = READ_DATA_PENDING_PTR(fptr);
4025 int i;
4026 if (cnt > sizeof buf) cnt = sizeof buf;
4027 if (*p != term) return TRUE;
4028 i = (int)cnt;
4029 while (--i && *++p == term);
4030 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4031 rb_sys_fail_path(fptr->pathv);
4032 }
4033 READ_CHECK(fptr);
4034 } while (io_fillbuf(fptr) == 0);
4035 return FALSE;
4036}
4037
4038static VALUE
4039rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4040{
4041 VALUE str = Qnil;
4042 int len = 0;
4043 long pos = 0;
4044 int cr = 0;
4045
4046 do {
4047 int pending = READ_DATA_PENDING_COUNT(fptr);
4048
4049 if (pending > 0) {
4050 const char *p = READ_DATA_PENDING_PTR(fptr);
4051 const char *e;
4052 int chomplen = 0;
4053
4054 e = memchr(p, '\n', pending);
4055 if (e) {
4056 pending = (int)(e - p + 1);
4057 if (chomp) {
4058 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4059 }
4060 }
4061 if (NIL_P(str)) {
4062 str = rb_str_new(p, pending - chomplen);
4063 fptr->rbuf.off += pending;
4064 fptr->rbuf.len -= pending;
4065 }
4066 else {
4067 rb_str_resize(str, len + pending - chomplen);
4068 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4069 fptr->rbuf.off += chomplen;
4070 fptr->rbuf.len -= chomplen;
4071 if (pending == 1 && chomplen == 1 && len > 0) {
4072 if (RSTRING_PTR(str)[len-1] == '\r') {
4073 rb_str_resize(str, --len);
4074 break;
4075 }
4076 }
4077 }
4078 len += pending - chomplen;
4079 if (cr != ENC_CODERANGE_BROKEN)
4080 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4081 if (e) break;
4082 }
4083 READ_CHECK(fptr);
4084 } while (io_fillbuf(fptr) >= 0);
4085 if (NIL_P(str)) return Qnil;
4086
4087 str = io_enc_str(str, fptr);
4088 ENC_CODERANGE_SET(str, cr);
4089 fptr->lineno++;
4090
4091 return str;
4092}
4093
4095 VALUE io;
4096 VALUE rs;
4097 long limit;
4098 unsigned int chomp: 1;
4099};
4100
4101static void
4102extract_getline_opts(VALUE opts, struct getline_arg *args)
4103{
4104 int chomp = FALSE;
4105 if (!NIL_P(opts)) {
4106 static ID kwds[1];
4107 VALUE vchomp;
4108 if (!kwds[0]) {
4109 kwds[0] = rb_intern_const("chomp");
4110 }
4111 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4112 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4113 }
4114 args->chomp = chomp;
4115}
4116
4117static void
4118extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4119{
4120 VALUE rs = rb_rs, lim = Qnil;
4121
4122 if (argc == 1) {
4123 VALUE tmp = Qnil;
4124
4125 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4126 rs = tmp;
4127 }
4128 else {
4129 lim = argv[0];
4130 }
4131 }
4132 else if (2 <= argc) {
4133 rs = argv[0], lim = argv[1];
4134 if (!NIL_P(rs))
4135 StringValue(rs);
4136 }
4137 args->rs = rs;
4138 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4139}
4140
4141static void
4142check_getline_args(VALUE *rsp, long *limit, VALUE io)
4143{
4144 rb_io_t *fptr;
4145 VALUE rs = *rsp;
4146
4147 if (!NIL_P(rs)) {
4148 rb_encoding *enc_rs, *enc_io;
4149
4150 GetOpenFile(io, fptr);
4151 enc_rs = rb_enc_get(rs);
4152 enc_io = io_read_encoding(fptr);
4153 if (enc_io != enc_rs &&
4154 (!is_ascii_string(rs) ||
4155 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4156 if (rs == rb_default_rs) {
4157 rs = rb_enc_str_new(0, 0, enc_io);
4158 rb_str_buf_cat_ascii(rs, "\n");
4159 *rsp = rs;
4160 }
4161 else {
4162 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4163 rb_enc_name(enc_io),
4164 rb_enc_name(enc_rs));
4165 }
4166 }
4167 }
4168}
4169
4170static void
4171prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4172{
4173 VALUE opts;
4174 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4175 extract_getline_args(argc, argv, args);
4176 extract_getline_opts(opts, args);
4177 check_getline_args(&args->rs, &args->limit, io);
4178}
4179
4180static VALUE
4181rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4182{
4183 VALUE str = Qnil;
4184 int nolimit = 0;
4185 rb_encoding *enc;
4186
4188 if (NIL_P(rs) && limit < 0) {
4189 str = read_all(fptr, 0, Qnil);
4190 if (RSTRING_LEN(str) == 0) return Qnil;
4191 }
4192 else if (limit == 0) {
4193 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4194 }
4195 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4196 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4197 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4198 return rb_io_getline_fast(fptr, enc, chomp);
4199 }
4200 else {
4201 int c, newline = -1;
4202 const char *rsptr = 0;
4203 long rslen = 0;
4204 int rspara = 0;
4205 int extra_limit = 16;
4206 int chomp_cr = chomp;
4207
4208 SET_BINARY_MODE(fptr);
4209 enc = io_read_encoding(fptr);
4210
4211 if (!NIL_P(rs)) {
4212 rslen = RSTRING_LEN(rs);
4213 if (rslen == 0) {
4214 rsptr = "\n\n";
4215 rslen = 2;
4216 rspara = 1;
4217 swallow(fptr, '\n');
4218 rs = 0;
4219 if (!rb_enc_asciicompat(enc)) {
4220 rs = rb_usascii_str_new(rsptr, rslen);
4221 rs = rb_str_conv_enc(rs, 0, enc);
4222 OBJ_FREEZE(rs);
4223 rsptr = RSTRING_PTR(rs);
4224 rslen = RSTRING_LEN(rs);
4225 }
4226 newline = '\n';
4227 }
4228 else if (rb_enc_mbminlen(enc) == 1) {
4229 rsptr = RSTRING_PTR(rs);
4230 newline = (unsigned char)rsptr[rslen - 1];
4231 }
4232 else {
4233 rs = rb_str_conv_enc(rs, 0, enc);
4234 rsptr = RSTRING_PTR(rs);
4235 const char *e = rsptr + rslen;
4236 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4237 int n;
4238 newline = rb_enc_codepoint_len(last, e, &n, enc);
4239 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4240 }
4241 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4242 }
4243
4244 /* MS - Optimization */
4245 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4246 const char *s, *p, *pp, *e;
4247
4248 if (c == newline) {
4249 if (RSTRING_LEN(str) < rslen) continue;
4250 s = RSTRING_PTR(str);
4251 e = RSTRING_END(str);
4252 p = e - rslen;
4253 if (!at_char_boundary(s, p, e, enc)) continue;
4254 if (!rspara) rscheck(rsptr, rslen, rs);
4255 if (memcmp(p, rsptr, rslen) == 0) {
4256 if (chomp) {
4257 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4258 rb_str_set_len(str, p - s);
4259 }
4260 break;
4261 }
4262 }
4263 if (limit == 0) {
4264 s = RSTRING_PTR(str);
4265 p = RSTRING_END(str);
4266 pp = rb_enc_prev_char(s, p, p, enc);
4267 if (extra_limit && pp &&
4268 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4269 /* relax the limit while incomplete character.
4270 * extra_limit limits the relax length */
4271 limit = 1;
4272 extra_limit--;
4273 }
4274 else {
4275 nolimit = 1;
4276 break;
4277 }
4278 }
4279 }
4280
4281 if (rspara && c != EOF)
4282 swallow(fptr, '\n');
4283 if (!NIL_P(str))
4284 str = io_enc_str(str, fptr);
4285 }
4286
4287 if (!NIL_P(str) && !nolimit) {
4288 fptr->lineno++;
4289 }
4290
4291 return str;
4292}
4293
4294static VALUE
4295rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4296{
4297 rb_io_t *fptr;
4298 int old_lineno, new_lineno;
4299 VALUE str;
4300
4301 GetOpenFile(io, fptr);
4302 old_lineno = fptr->lineno;
4303 str = rb_io_getline_0(rs, limit, chomp, fptr);
4304 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4305 if (io == ARGF.current_file) {
4306 ARGF.lineno += new_lineno - old_lineno;
4307 ARGF.last_lineno = ARGF.lineno;
4308 }
4309 else {
4310 ARGF.last_lineno = new_lineno;
4311 }
4312 }
4313
4314 return str;
4315}
4316
4317static VALUE
4318rb_io_getline(int argc, VALUE *argv, VALUE io)
4319{
4320 struct getline_arg args;
4321
4322 prepare_getline_args(argc, argv, &args, io);
4323 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4324}
4325
4326VALUE
4328{
4329 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4330}
4331
4332VALUE
4333rb_io_gets_limit_internal(VALUE io, long limit)
4334{
4335 rb_io_t *fptr;
4336 GetOpenFile(io, fptr);
4337 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4338}
4339
4340VALUE
4341rb_io_gets_internal(VALUE io)
4342{
4343 return rb_io_gets_limit_internal(io, -1);
4344}
4345
4346/*
4347 * call-seq:
4348 * gets(sep = $/, chomp: false) -> string or nil
4349 * gets(limit, chomp: false) -> string or nil
4350 * gets(sep, limit, chomp: false) -> string or nil
4351 *
4352 * Reads and returns a line from the stream;
4353 * assigns the return value to <tt>$_</tt>.
4354 * See {Line IO}[rdoc-ref:IO@Line+IO].
4355 *
4356 * With no arguments given, returns the next line
4357 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4358 *
4359 * f = File.open('t.txt')
4360 * f.gets # => "First line\n"
4361 * $_ # => "First line\n"
4362 * f.gets # => "\n"
4363 * f.gets # => "Fourth line\n"
4364 * f.gets # => "Fifth line\n"
4365 * f.gets # => nil
4366 * f.close
4367 *
4368 * With only string argument +sep+ given,
4369 * returns the next line as determined by line separator +sep+,
4370 * or +nil+ if none;
4371 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4372 *
4373 * f = File.new('t.txt')
4374 * f.gets('l') # => "First l"
4375 * f.gets('li') # => "ine\nSecond li"
4376 * f.gets('lin') # => "ne\n\nFourth lin"
4377 * f.gets # => "e\n"
4378 * f.close
4379 *
4380 * The two special values for +sep+ are honored:
4381 *
4382 * f = File.new('t.txt')
4383 * # Get all.
4384 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4385 * f.rewind
4386 * # Get paragraph (up to two line separators).
4387 * f.gets('') # => "First line\nSecond line\n\n"
4388 * f.close
4389 *
4390 * With only integer argument +limit+ given,
4391 * limits the number of bytes in the line;
4392 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4393 *
4394 * # No more than one line.
4395 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4396 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4397 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4398 *
4399 * With arguments +sep+ and +limit+ given,
4400 * combines the two behaviors
4401 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4402 *
4403 * Optional keyword argument +chomp+ specifies whether line separators
4404 * are to be omitted:
4405 *
4406 * f = File.open('t.txt')
4407 * # Chomp the lines.
4408 * f.gets(chomp: true) # => "First line"
4409 * f.gets(chomp: true) # => "Second line"
4410 * f.gets(chomp: true) # => ""
4411 * f.gets(chomp: true) # => "Fourth line"
4412 * f.gets(chomp: true) # => "Fifth line"
4413 * f.gets(chomp: true) # => nil
4414 * f.close
4415 *
4416 */
4417
4418static VALUE
4419rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4420{
4421 VALUE str;
4422
4423 str = rb_io_getline(argc, argv, io);
4424 rb_lastline_set(str);
4425
4426 return str;
4427}
4428
4429/*
4430 * call-seq:
4431 * lineno -> integer
4432 *
4433 * Returns the current line number for the stream;
4434 * see {Line Number}[rdoc-ref:IO@Line+Number].
4435 *
4436 */
4437
4438static VALUE
4439rb_io_lineno(VALUE io)
4440{
4441 rb_io_t *fptr;
4442
4443 GetOpenFile(io, fptr);
4445 return INT2NUM(fptr->lineno);
4446}
4447
4448/*
4449 * call-seq:
4450 * lineno = integer -> integer
4451 *
4452 * Sets and returns the line number for the stream;
4453 * see {Line Number}[rdoc-ref:IO@Line+Number].
4454 *
4455 */
4456
4457static VALUE
4458rb_io_set_lineno(VALUE io, VALUE lineno)
4459{
4460 rb_io_t *fptr;
4461
4462 GetOpenFile(io, fptr);
4464 fptr->lineno = NUM2INT(lineno);
4465 return lineno;
4466}
4467
4468/* :nodoc: */
4469static VALUE
4470io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4471{
4472 long limit = -1;
4473 if (NIL_P(lim)) {
4474 VALUE tmp = Qnil;
4475 // If sep is specified, but it's not a string and not nil, then assume
4476 // it's the limit (it should be an integer)
4477 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4478 // If the user has specified a non-nil / non-string value
4479 // for the separator, we assume it's the limit and set the
4480 // separator to default: rb_rs.
4481 lim = sep;
4482 limit = NUM2LONG(lim);
4483 sep = rb_rs;
4484 }
4485 else {
4486 sep = tmp;
4487 }
4488 }
4489 else {
4490 if (!NIL_P(sep)) StringValue(sep);
4491 limit = NUM2LONG(lim);
4492 }
4493
4494 check_getline_args(&sep, &limit, io);
4495
4496 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4497 rb_lastline_set_up(line, 1);
4498
4499 if (NIL_P(line)) {
4500 rb_eof_error();
4501 }
4502 return line;
4503}
4504
4505static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4506
4507/*
4508 * call-seq:
4509 * readlines(sep = $/, chomp: false) -> array
4510 * readlines(limit, chomp: false) -> array
4511 * readlines(sep, limit, chomp: false) -> array
4512 *
4513 * Reads and returns all remaining line from the stream;
4514 * does not modify <tt>$_</tt>.
4515 * See {Line IO}[rdoc-ref:IO@Line+IO].
4516 *
4517 * With no arguments given, returns lines
4518 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4519 *
4520 * f = File.new('t.txt')
4521 * f.readlines
4522 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4523 * f.readlines # => []
4524 * f.close
4525 *
4526 * With only string argument +sep+ given,
4527 * returns lines as determined by line separator +sep+,
4528 * or +nil+ if none;
4529 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4530 *
4531 * f = File.new('t.txt')
4532 * f.readlines('li')
4533 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4534 * f.close
4535 *
4536 * The two special values for +sep+ are honored:
4537 *
4538 * f = File.new('t.txt')
4539 * # Get all into one string.
4540 * f.readlines(nil)
4541 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4542 * # Get paragraphs (up to two line separators).
4543 * f.rewind
4544 * f.readlines('')
4545 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4546 * f.close
4547 *
4548 * With only integer argument +limit+ given,
4549 * limits the number of bytes in each line;
4550 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4551 *
4552 * f = File.new('t.txt')
4553 * f.readlines(8)
4554 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4555 * f.close
4556 *
4557 * With arguments +sep+ and +limit+ given,
4558 * combines the two behaviors
4559 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4560 *
4561 * Optional keyword argument +chomp+ specifies whether line separators
4562 * are to be omitted:
4563 *
4564 * f = File.new('t.txt')
4565 * f.readlines(chomp: true)
4566 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4567 * f.close
4568 *
4569 */
4570
4571static VALUE
4572rb_io_readlines(int argc, VALUE *argv, VALUE io)
4573{
4574 struct getline_arg args;
4575
4576 prepare_getline_args(argc, argv, &args, io);
4577 return io_readlines(&args, io);
4578}
4579
4580static VALUE
4581io_readlines(const struct getline_arg *arg, VALUE io)
4582{
4583 VALUE line, ary;
4584
4585 if (arg->limit == 0)
4586 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4587 ary = rb_ary_new();
4588 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4589 rb_ary_push(ary, line);
4590 }
4591 return ary;
4592}
4593
4594/*
4595 * call-seq:
4596 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4597 * each_line(limit, chomp: false) {|line| ... } -> self
4598 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4599 * each_line -> enumerator
4600 *
4601 * Calls the block with each remaining line read from the stream;
4602 * returns +self+.
4603 * Does nothing if already at end-of-stream;
4604 * See {Line IO}[rdoc-ref:IO@Line+IO].
4605 *
4606 * With no arguments given, reads lines
4607 * as determined by line separator <tt>$/</tt>:
4608 *
4609 * f = File.new('t.txt')
4610 * f.each_line {|line| p line }
4611 * f.each_line {|line| fail 'Cannot happen' }
4612 * f.close
4613 *
4614 * Output:
4615 *
4616 * "First line\n"
4617 * "Second line\n"
4618 * "\n"
4619 * "Fourth line\n"
4620 * "Fifth line\n"
4621 *
4622 * With only string argument +sep+ given,
4623 * reads lines as determined by line separator +sep+;
4624 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4625 *
4626 * f = File.new('t.txt')
4627 * f.each_line('li') {|line| p line }
4628 * f.close
4629 *
4630 * Output:
4631 *
4632 * "First li"
4633 * "ne\nSecond li"
4634 * "ne\n\nFourth li"
4635 * "ne\nFifth li"
4636 * "ne\n"
4637 *
4638 * The two special values for +sep+ are honored:
4639 *
4640 * f = File.new('t.txt')
4641 * # Get all into one string.
4642 * f.each_line(nil) {|line| p line }
4643 * f.close
4644 *
4645 * Output:
4646 *
4647 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4648 *
4649 * f.rewind
4650 * # Get paragraphs (up to two line separators).
4651 * f.each_line('') {|line| p line }
4652 *
4653 * Output:
4654 *
4655 * "First line\nSecond line\n\n"
4656 * "Fourth line\nFifth line\n"
4657 *
4658 * With only integer argument +limit+ given,
4659 * limits the number of bytes in each line;
4660 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4661 *
4662 * f = File.new('t.txt')
4663 * f.each_line(8) {|line| p line }
4664 * f.close
4665 *
4666 * Output:
4667 *
4668 * "First li"
4669 * "ne\n"
4670 * "Second l"
4671 * "ine\n"
4672 * "\n"
4673 * "Fourth l"
4674 * "ine\n"
4675 * "Fifth li"
4676 * "ne\n"
4677 *
4678 * With arguments +sep+ and +limit+ given,
4679 * combines the two behaviors
4680 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4681 *
4682 * Optional keyword argument +chomp+ specifies whether line separators
4683 * are to be omitted:
4684 *
4685 * f = File.new('t.txt')
4686 * f.each_line(chomp: true) {|line| p line }
4687 * f.close
4688 *
4689 * Output:
4690 *
4691 * "First line"
4692 * "Second line"
4693 * ""
4694 * "Fourth line"
4695 * "Fifth line"
4696 *
4697 * Returns an Enumerator if no block is given.
4698 */
4699
4700static VALUE
4701rb_io_each_line(int argc, VALUE *argv, VALUE io)
4702{
4703 VALUE str;
4704 struct getline_arg args;
4705
4706 RETURN_ENUMERATOR(io, argc, argv);
4707 prepare_getline_args(argc, argv, &args, io);
4708 if (args.limit == 0)
4709 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4710 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4711 rb_yield(str);
4712 }
4713 return io;
4714}
4715
4716/*
4717 * call-seq:
4718 * each_byte {|byte| ... } -> self
4719 * each_byte -> enumerator
4720 *
4721 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4722 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4723 *
4724 * File.read('t.ja') # => "こんにちは"
4725 * f = File.new('t.ja')
4726 * a = []
4727 * f.each_byte {|b| a << b }
4728 * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
4729 * f.close
4730 *
4731 * Returns an Enumerator if no block is given.
4732 *
4733 * Related: IO#each_char, IO#each_codepoint.
4734 *
4735 */
4736
4737static VALUE
4738rb_io_each_byte(VALUE io)
4739{
4740 rb_io_t *fptr;
4741
4742 RETURN_ENUMERATOR(io, 0, 0);
4743 GetOpenFile(io, fptr);
4744
4745 do {
4746 while (fptr->rbuf.len > 0) {
4747 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4748 fptr->rbuf.len--;
4749 rb_yield(INT2FIX(*p & 0xff));
4751 errno = 0;
4752 }
4753 READ_CHECK(fptr);
4754 } while (io_fillbuf(fptr) >= 0);
4755 return io;
4756}
4757
4758static VALUE
4759io_getc(rb_io_t *fptr, rb_encoding *enc)
4760{
4761 int r, n, cr = 0;
4762 VALUE str;
4763
4764 if (NEED_READCONV(fptr)) {
4765 rb_encoding *read_enc = io_read_encoding(fptr);
4766
4767 str = Qnil;
4768 SET_BINARY_MODE(fptr);
4769 make_readconv(fptr, 0);
4770
4771 while (1) {
4772 if (fptr->cbuf.len) {
4773 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4774 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4775 read_enc);
4776 if (!MBCLEN_NEEDMORE_P(r))
4777 break;
4778 if (fptr->cbuf.len == fptr->cbuf.capa) {
4779 rb_raise(rb_eIOError, "too long character");
4780 }
4781 }
4782
4783 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4784 if (fptr->cbuf.len == 0) {
4785 clear_readconv(fptr);
4786 return Qnil;
4787 }
4788 /* return an unit of an incomplete character just before EOF */
4789 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4790 fptr->cbuf.off += 1;
4791 fptr->cbuf.len -= 1;
4792 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4794 return str;
4795 }
4796 }
4797 if (MBCLEN_INVALID_P(r)) {
4798 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4799 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4800 read_enc);
4801 io_shift_cbuf(fptr, r, &str);
4803 }
4804 else {
4805 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4807 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4808 ISASCII(RSTRING_PTR(str)[0])) {
4809 cr = ENC_CODERANGE_7BIT;
4810 }
4811 }
4812 str = io_enc_str(str, fptr);
4813 ENC_CODERANGE_SET(str, cr);
4814 return str;
4815 }
4816
4817 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4818 if (io_fillbuf(fptr) < 0) {
4819 return Qnil;
4820 }
4821 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4822 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4823 fptr->rbuf.off += 1;
4824 fptr->rbuf.len -= 1;
4825 cr = ENC_CODERANGE_7BIT;
4826 }
4827 else {
4828 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4829 if (MBCLEN_CHARFOUND_P(r) &&
4830 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4831 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4832 fptr->rbuf.off += n;
4833 fptr->rbuf.len -= n;
4835 }
4836 else if (MBCLEN_NEEDMORE_P(r)) {
4837 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4838 fptr->rbuf.len = 0;
4839 getc_needmore:
4840 if (io_fillbuf(fptr) != -1) {
4841 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4842 fptr->rbuf.off++;
4843 fptr->rbuf.len--;
4844 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4845 if (MBCLEN_NEEDMORE_P(r)) {
4846 goto getc_needmore;
4847 }
4848 else if (MBCLEN_CHARFOUND_P(r)) {
4850 }
4851 }
4852 }
4853 else {
4854 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4855 fptr->rbuf.off++;
4856 fptr->rbuf.len--;
4857 }
4858 }
4859 if (!cr) cr = ENC_CODERANGE_BROKEN;
4860 str = io_enc_str(str, fptr);
4861 ENC_CODERANGE_SET(str, cr);
4862 return str;
4863}
4864
4865/*
4866 * call-seq:
4867 * each_char {|c| ... } -> self
4868 * each_char -> enumerator
4869 *
4870 * Calls the given block with each character in the stream; returns +self+.
4871 * See {Character IO}[rdoc-ref:IO@Character+IO].
4872 *
4873 * File.read('t.ja') # => "こんにちは"
4874 * f = File.new('t.ja')
4875 * a = []
4876 * f.each_char {|c| a << c.ord }
4877 * a # => [12371, 12435, 12395, 12385, 12399]
4878 * f.close
4879 *
4880 * Returns an Enumerator if no block is given.
4881 *
4882 * Related: IO#each_byte, IO#each_codepoint.
4883 *
4884 */
4885
4886static VALUE
4887rb_io_each_char(VALUE io)
4888{
4889 rb_io_t *fptr;
4890 rb_encoding *enc;
4891 VALUE c;
4892
4893 RETURN_ENUMERATOR(io, 0, 0);
4894 GetOpenFile(io, fptr);
4896
4897 enc = io_input_encoding(fptr);
4898 READ_CHECK(fptr);
4899 while (!NIL_P(c = io_getc(fptr, enc))) {
4900 rb_yield(c);
4901 }
4902 return io;
4903}
4904
4905/*
4906 * call-seq:
4907 * each_codepoint {|c| ... } -> self
4908 * each_codepoint -> enumerator
4909 *
4910 * Calls the given block with each codepoint in the stream; returns +self+:
4911 *
4912 * File.read('t.ja') # => "こんにちは"
4913 * f = File.new('t.ja')
4914 * a = []
4915 * f.each_codepoint {|c| a << c }
4916 * a # => [12371, 12435, 12395, 12385, 12399]
4917 * f.close
4918 *
4919 * Returns an Enumerator if no block is given.
4920 *
4921 * Related: IO#each_byte, IO#each_char.
4922 *
4923 */
4924
4925static VALUE
4926rb_io_each_codepoint(VALUE io)
4927{
4928 rb_io_t *fptr;
4929 rb_encoding *enc;
4930 unsigned int c;
4931 int r, n;
4932
4933 RETURN_ENUMERATOR(io, 0, 0);
4934 GetOpenFile(io, fptr);
4936
4937 READ_CHECK(fptr);
4938 enc = io_read_encoding(fptr);
4939 if (NEED_READCONV(fptr)) {
4940 SET_BINARY_MODE(fptr);
4941 r = 1; /* no invalid char yet */
4942 for (;;) {
4943 make_readconv(fptr, 0);
4944 for (;;) {
4945 if (fptr->cbuf.len) {
4946 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4947 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4948 enc);
4949 if (!MBCLEN_NEEDMORE_P(r))
4950 break;
4951 if (fptr->cbuf.len == fptr->cbuf.capa) {
4952 rb_raise(rb_eIOError, "too long character");
4953 }
4954 }
4955 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4956 clear_readconv(fptr);
4957 if (!MBCLEN_CHARFOUND_P(r)) {
4958 goto invalid;
4959 }
4960 return io;
4961 }
4962 }
4963 if (MBCLEN_INVALID_P(r)) {
4964 goto invalid;
4965 }
4966 n = MBCLEN_CHARFOUND_LEN(r);
4967 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4968 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4969 enc);
4970 fptr->cbuf.off += n;
4971 fptr->cbuf.len -= n;
4972 rb_yield(UINT2NUM(c));
4974 }
4975 }
4976 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4977 while (io_fillbuf(fptr) >= 0) {
4978 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4979 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4980 if (MBCLEN_CHARFOUND_P(r) &&
4981 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4982 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4983 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4984 fptr->rbuf.off += n;
4985 fptr->rbuf.len -= n;
4986 rb_yield(UINT2NUM(c));
4987 }
4988 else if (MBCLEN_INVALID_P(r)) {
4989 goto invalid;
4990 }
4991 else if (MBCLEN_NEEDMORE_P(r)) {
4992 char cbuf[8], *p = cbuf;
4993 int more = MBCLEN_NEEDMORE_LEN(r);
4994 if (more > numberof(cbuf)) goto invalid;
4995 more += n = fptr->rbuf.len;
4996 if (more > numberof(cbuf)) goto invalid;
4997 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4998 (p += n, (more -= n) > 0)) {
4999 if (io_fillbuf(fptr) < 0) goto invalid;
5000 if ((n = fptr->rbuf.len) > more) n = more;
5001 }
5002 r = rb_enc_precise_mbclen(cbuf, p, enc);
5003 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5004 c = rb_enc_codepoint(cbuf, p, enc);
5005 rb_yield(UINT2NUM(c));
5006 }
5007 else {
5008 continue;
5009 }
5011 }
5012 return io;
5013
5014 invalid:
5015 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5017}
5018
5019/*
5020 * call-seq:
5021 * getc -> character or nil
5022 *
5023 * Reads and returns the next 1-character string from the stream;
5024 * returns +nil+ if already at end-of-stream.
5025 * See {Character IO}[rdoc-ref:IO@Character+IO].
5026 *
5027 * f = File.open('t.txt')
5028 * f.getc # => "F"
5029 * f.close
5030 * File.read('t.ja') # => "こんにちは"
5031 * f = File.open('t.ja')
5032 * f.getc.ord # => 12371
5033 * f.close
5034 *
5035 * Related: IO#readchar (may raise EOFError).
5036 *
5037 */
5038
5039static VALUE
5040rb_io_getc(VALUE io)
5041{
5042 rb_io_t *fptr;
5043 rb_encoding *enc;
5044
5045 GetOpenFile(io, fptr);
5047
5048 enc = io_input_encoding(fptr);
5049 READ_CHECK(fptr);
5050 return io_getc(fptr, enc);
5051}
5052
5053/*
5054 * call-seq:
5055 * readchar -> string
5056 *
5057 * Reads and returns the next 1-character string from the stream;
5058 * raises EOFError if already at end-of-stream.
5059 * See {Character IO}[rdoc-ref:IO@Character+IO].
5060 *
5061 * f = File.open('t.txt')
5062 * f.readchar # => "F"
5063 * f.close
5064 * File.read('t.ja') # => "こんにちは"
5065 * f = File.open('t.ja')
5066 * f.readchar.ord # => 12371
5067 * f.close
5068 *
5069 * Related: IO#getc (will not raise EOFError).
5070 *
5071 */
5072
5073static VALUE
5074rb_io_readchar(VALUE io)
5075{
5076 VALUE c = rb_io_getc(io);
5077
5078 if (NIL_P(c)) {
5079 rb_eof_error();
5080 }
5081 return c;
5082}
5083
5084/*
5085 * call-seq:
5086 * getbyte -> integer or nil
5087 *
5088 * Reads and returns the next byte (in range 0..255) from the stream;
5089 * returns +nil+ if already at end-of-stream.
5090 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5091 *
5092 * f = File.open('t.txt')
5093 * f.getbyte # => 70
5094 * f.close
5095 * File.read('t.ja') # => "こんにちは"
5096 * f = File.open('t.ja')
5097 * f.getbyte # => 227
5098 * f.close
5099 *
5100 * Related: IO#readbyte (may raise EOFError).
5101 */
5102
5103VALUE
5105{
5106 rb_io_t *fptr;
5107 int c;
5108
5109 GetOpenFile(io, fptr);
5111 READ_CHECK(fptr);
5112 VALUE r_stdout = rb_ractor_stdout();
5113 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5114 rb_io_t *ofp;
5115 GetOpenFile(r_stdout, ofp);
5116 if (ofp->mode & FMODE_TTY) {
5117 rb_io_flush(r_stdout);
5118 }
5119 }
5120 if (io_fillbuf(fptr) < 0) {
5121 return Qnil;
5122 }
5123 fptr->rbuf.off++;
5124 fptr->rbuf.len--;
5125 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5126 return INT2FIX(c & 0xff);
5127}
5128
5129/*
5130 * call-seq:
5131 * readbyte -> integer
5132 *
5133 * Reads and returns the next byte (in range 0..255) from the stream;
5134 * raises EOFError if already at end-of-stream.
5135 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5136 *
5137 * f = File.open('t.txt')
5138 * f.readbyte # => 70
5139 * f.close
5140 * File.read('t.ja') # => "こんにちは"
5141 * f = File.open('t.ja')
5142 * f.readbyte # => 227
5143 * f.close
5144 *
5145 * Related: IO#getbyte (will not raise EOFError).
5146 *
5147 */
5148
5149static VALUE
5150rb_io_readbyte(VALUE io)
5151{
5152 VALUE c = rb_io_getbyte(io);
5153
5154 if (NIL_P(c)) {
5155 rb_eof_error();
5156 }
5157 return c;
5158}
5159
5160/*
5161 * call-seq:
5162 * ungetbyte(integer) -> nil
5163 * ungetbyte(string) -> nil
5164 *
5165 * Pushes back ("unshifts") the given data onto the stream's buffer,
5166 * placing the data so that it is next to be read; returns +nil+.
5167 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5168 *
5169 * Note that:
5170 *
5171 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5172 * - Calling #rewind on the stream discards the pushed-back data.
5173 *
5174 * When argument +integer+ is given, uses only its low-order byte:
5175 *
5176 * File.write('t.tmp', '012')
5177 * f = File.open('t.tmp')
5178 * f.ungetbyte(0x41) # => nil
5179 * f.read # => "A012"
5180 * f.rewind
5181 * f.ungetbyte(0x4243) # => nil
5182 * f.read # => "C012"
5183 * f.close
5184 *
5185 * When argument +string+ is given, uses all bytes:
5186 *
5187 * File.write('t.tmp', '012')
5188 * f = File.open('t.tmp')
5189 * f.ungetbyte('A') # => nil
5190 * f.read # => "A012"
5191 * f.rewind
5192 * f.ungetbyte('BCDE') # => nil
5193 * f.read # => "BCDE012"
5194 * f.close
5195 *
5196 */
5197
5198VALUE
5200{
5201 rb_io_t *fptr;
5202
5203 GetOpenFile(io, fptr);
5205 switch (TYPE(b)) {
5206 case T_NIL:
5207 return Qnil;
5208 case T_FIXNUM:
5209 case T_BIGNUM: ;
5210 VALUE v = rb_int_modulo(b, INT2FIX(256));
5211 unsigned char c = NUM2INT(v) & 0xFF;
5212 b = rb_str_new((const char *)&c, 1);
5213 break;
5214 default:
5215 StringValue(b);
5216 }
5217 io_ungetbyte(b, fptr);
5218 return Qnil;
5219}
5220
5221/*
5222 * call-seq:
5223 * ungetc(integer) -> nil
5224 * ungetc(string) -> nil
5225 *
5226 * Pushes back ("unshifts") the given data onto the stream's buffer,
5227 * placing the data so that it is next to be read; returns +nil+.
5228 * See {Character IO}[rdoc-ref:IO@Character+IO].
5229 *
5230 * Note that:
5231 *
5232 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5233 * - Calling #rewind on the stream discards the pushed-back data.
5234 *
5235 * When argument +integer+ is given, interprets the integer as a character:
5236 *
5237 * File.write('t.tmp', '012')
5238 * f = File.open('t.tmp')
5239 * f.ungetc(0x41) # => nil
5240 * f.read # => "A012"
5241 * f.rewind
5242 * f.ungetc(0x0442) # => nil
5243 * f.getc.ord # => 1090
5244 * f.close
5245 *
5246 * When argument +string+ is given, uses all characters:
5247 *
5248 * File.write('t.tmp', '012')
5249 * f = File.open('t.tmp')
5250 * f.ungetc('A') # => nil
5251 * f.read # => "A012"
5252 * f.rewind
5253 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5254 * f.getc.ord # => 1090
5255 * f.getc.ord # => 1077
5256 * f.getc.ord # => 1089
5257 * f.getc.ord # => 1090
5258 * f.close
5259 *
5260 */
5261
5262VALUE
5264{
5265 rb_io_t *fptr;
5266 long len;
5267
5268 GetOpenFile(io, fptr);
5270 if (FIXNUM_P(c)) {
5271 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5272 }
5273 else if (RB_BIGNUM_TYPE_P(c)) {
5274 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5275 }
5276 else {
5277 StringValue(c);
5278 }
5279 if (NEED_READCONV(fptr)) {
5280 SET_BINARY_MODE(fptr);
5281 len = RSTRING_LEN(c);
5282#if SIZEOF_LONG > SIZEOF_INT
5283 if (len > INT_MAX)
5284 rb_raise(rb_eIOError, "ungetc failed");
5285#endif
5286 make_readconv(fptr, (int)len);
5287 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5288 rb_raise(rb_eIOError, "ungetc failed");
5289 if (fptr->cbuf.off < len) {
5290 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5291 fptr->cbuf.ptr+fptr->cbuf.off,
5292 char, fptr->cbuf.len);
5293 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5294 }
5295 fptr->cbuf.off -= (int)len;
5296 fptr->cbuf.len += (int)len;
5297 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5298 }
5299 else {
5300 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5301 io_ungetbyte(c, fptr);
5302 }
5303 return Qnil;
5304}
5305
5306/*
5307 * call-seq:
5308 * isatty -> true or false
5309 *
5310 * Returns +true+ if the stream is associated with a terminal device (tty),
5311 * +false+ otherwise:
5312 *
5313 * f = File.new('t.txt').isatty #=> false
5314 * f.close
5315 * f = File.new('/dev/tty').isatty #=> true
5316 * f.close
5317 *
5318 */
5319
5320static VALUE
5321rb_io_isatty(VALUE io)
5322{
5323 rb_io_t *fptr;
5324
5325 GetOpenFile(io, fptr);
5326 return RBOOL(isatty(fptr->fd) != 0);
5327}
5328
5329#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5330/*
5331 * call-seq:
5332 * close_on_exec? -> true or false
5333 *
5334 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5335 *
5336 * f = File.open('t.txt')
5337 * f.close_on_exec? # => true
5338 * f.close_on_exec = false
5339 * f.close_on_exec? # => false
5340 * f.close
5341 *
5342 */
5343
5344static VALUE
5345rb_io_close_on_exec_p(VALUE io)
5346{
5347 rb_io_t *fptr;
5348 VALUE write_io;
5349 int fd, ret;
5350
5351 write_io = GetWriteIO(io);
5352 if (io != write_io) {
5353 GetOpenFile(write_io, fptr);
5354 if (fptr && 0 <= (fd = fptr->fd)) {
5355 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5356 if (!(ret & FD_CLOEXEC)) return Qfalse;
5357 }
5358 }
5359
5360 GetOpenFile(io, fptr);
5361 if (fptr && 0 <= (fd = fptr->fd)) {
5362 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5363 if (!(ret & FD_CLOEXEC)) return Qfalse;
5364 }
5365 return Qtrue;
5366}
5367#else
5368#define rb_io_close_on_exec_p rb_f_notimplement
5369#endif
5370
5371#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5372/*
5373 * call-seq:
5374 * self.close_on_exec = bool -> true or false
5375 *
5376 * Sets a close-on-exec flag.
5377 *
5378 * f = File.open(File::NULL)
5379 * f.close_on_exec = true
5380 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5381 * f.closed? #=> false
5382 *
5383 * Ruby sets close-on-exec flags of all file descriptors by default
5384 * since Ruby 2.0.0.
5385 * So you don't need to set by yourself.
5386 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5387 * if another thread use fork() and exec() (via system() method for example).
5388 * If you really needs file descriptor inheritance to child process,
5389 * use spawn()'s argument such as fd=>fd.
5390 */
5391
5392static VALUE
5393rb_io_set_close_on_exec(VALUE io, VALUE arg)
5394{
5395 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5396 rb_io_t *fptr;
5397 VALUE write_io;
5398 int fd, ret;
5399
5400 write_io = GetWriteIO(io);
5401 if (io != write_io) {
5402 GetOpenFile(write_io, fptr);
5403 if (fptr && 0 <= (fd = fptr->fd)) {
5404 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5405 if ((ret & FD_CLOEXEC) != flag) {
5406 ret = (ret & ~FD_CLOEXEC) | flag;
5407 ret = fcntl(fd, F_SETFD, ret);
5408 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5409 }
5410 }
5411
5412 }
5413
5414 GetOpenFile(io, fptr);
5415 if (fptr && 0 <= (fd = fptr->fd)) {
5416 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5417 if ((ret & FD_CLOEXEC) != flag) {
5418 ret = (ret & ~FD_CLOEXEC) | flag;
5419 ret = fcntl(fd, F_SETFD, ret);
5420 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5421 }
5422 }
5423 return Qnil;
5424}
5425#else
5426#define rb_io_set_close_on_exec rb_f_notimplement
5427#endif
5428
5429#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5430#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5431
5432static VALUE
5433finish_writeconv(rb_io_t *fptr, int noalloc)
5434{
5435 unsigned char *ds, *dp, *de;
5437
5438 if (!fptr->wbuf.ptr) {
5439 unsigned char buf[1024];
5440
5442 while (res == econv_destination_buffer_full) {
5443 ds = dp = buf;
5444 de = buf + sizeof(buf);
5445 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5446 while (dp-ds) {
5447 size_t remaining = dp-ds;
5448 long result = rb_io_write_memory(fptr, ds, remaining);
5449
5450 if (result > 0) {
5451 ds += result;
5452 if ((size_t)result == remaining) break;
5453 }
5454 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5455 if (fptr->fd < 0)
5456 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5457 }
5458 else {
5459 return noalloc ? Qtrue : INT2NUM(errno);
5460 }
5461 }
5462 if (res == econv_invalid_byte_sequence ||
5463 res == econv_incomplete_input ||
5465 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5466 }
5467 }
5468
5469 return Qnil;
5470 }
5471
5473 while (res == econv_destination_buffer_full) {
5474 if (fptr->wbuf.len == fptr->wbuf.capa) {
5475 if (io_fflush(fptr) < 0) {
5476 return noalloc ? Qtrue : INT2NUM(errno);
5477 }
5478 }
5479
5480 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5481 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5482 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5483 fptr->wbuf.len += (int)(dp - ds);
5484 if (res == econv_invalid_byte_sequence ||
5485 res == econv_incomplete_input ||
5487 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5488 }
5489 }
5490 return Qnil;
5491}
5492
5494 rb_io_t *fptr;
5495 int noalloc;
5496};
5497
5498static VALUE
5499finish_writeconv_sync(VALUE arg)
5500{
5501 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5502 return finish_writeconv(p->fptr, p->noalloc);
5503}
5504
5505static void*
5506nogvl_close(void *ptr)
5507{
5508 int *fd = ptr;
5509
5510 return (void*)(intptr_t)close(*fd);
5511}
5512
5513static int
5514maygvl_close(int fd, int keepgvl)
5515{
5516 if (keepgvl)
5517 return close(fd);
5518
5519 /*
5520 * close() may block for certain file types (NFS, SO_LINGER sockets,
5521 * inotify), so let other threads run.
5522 */
5523 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5524}
5525
5526static void*
5527nogvl_fclose(void *ptr)
5528{
5529 FILE *file = ptr;
5530
5531 return (void*)(intptr_t)fclose(file);
5532}
5533
5534static int
5535maygvl_fclose(FILE *file, int keepgvl)
5536{
5537 if (keepgvl)
5538 return fclose(file);
5539
5540 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5541}
5542
5543static void free_io_buffer(rb_io_buffer_t *buf);
5544
5545static void
5546fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5547{
5548 VALUE error = Qnil;
5549 int fd = fptr->fd;
5550 FILE *stdio_file = fptr->stdio_file;
5551 int mode = fptr->mode;
5552
5553 if (fptr->writeconv) {
5554 if (!NIL_P(fptr->write_lock) && !noraise) {
5555 struct finish_writeconv_arg arg;
5556 arg.fptr = fptr;
5557 arg.noalloc = noraise;
5558 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5559 }
5560 else {
5561 error = finish_writeconv(fptr, noraise);
5562 }
5563 }
5564 if (fptr->wbuf.len) {
5565 if (noraise) {
5566 io_flush_buffer_sync(fptr);
5567 }
5568 else {
5569 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5570 error = INT2NUM(errno);
5571 }
5572 }
5573 }
5574
5575 int done = 0;
5576
5577 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5578 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5579 done = 1;
5580 }
5581
5582 fptr->fd = -1;
5583 fptr->stdio_file = 0;
5585
5586 // Wait for blocking operations to ensure they do not hit EBADF:
5587 rb_thread_io_close_wait(fptr);
5588
5589 if (!done && stdio_file) {
5590 // stdio_file is deallocated anyway even if fclose failed.
5591 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5592 if (!noraise) {
5593 error = INT2NUM(errno);
5594 }
5595 }
5596
5597 done = 1;
5598 }
5599
5600 VALUE scheduler = rb_fiber_scheduler_current();
5601 if (!done && fd >= 0 && scheduler != Qnil) {
5602 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5603
5604 if (!UNDEF_P(result)) {
5605 done = RTEST(result);
5606 }
5607 }
5608
5609 if (!done && fd >= 0) {
5610 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5611 // We assumes it is closed.
5612
5613 keepgvl |= !(mode & FMODE_WRITABLE);
5614 keepgvl |= noraise;
5615 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5616 if (!noraise) {
5617 error = INT2NUM(errno);
5618 }
5619 }
5620
5621 done = 1;
5622 }
5623
5624 if (!NIL_P(error) && !noraise) {
5625 if (RB_INTEGER_TYPE_P(error))
5626 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5627 else
5628 rb_exc_raise(error);
5629 }
5630}
5631
5632static void
5633fptr_finalize(rb_io_t *fptr, int noraise)
5634{
5635 fptr_finalize_flush(fptr, noraise, FALSE);
5636 free_io_buffer(&fptr->rbuf);
5637 free_io_buffer(&fptr->wbuf);
5638 clear_codeconv(fptr);
5639}
5640
5641static void
5642rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5643{
5644 if (fptr->finalize) {
5645 (*fptr->finalize)(fptr, noraise);
5646 }
5647 else {
5648 fptr_finalize(fptr, noraise);
5649 }
5650}
5651
5652static void
5653free_io_buffer(rb_io_buffer_t *buf)
5654{
5655 if (buf->ptr) {
5656 ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
5657 buf->ptr = NULL;
5658 }
5659}
5660
5661static void
5662clear_readconv(rb_io_t *fptr)
5663{
5664 if (fptr->readconv) {
5665 rb_econv_close(fptr->readconv);
5666 fptr->readconv = NULL;
5667 }
5668 free_io_buffer(&fptr->cbuf);
5669}
5670
5671static void
5672clear_writeconv(rb_io_t *fptr)
5673{
5674 if (fptr->writeconv) {
5676 fptr->writeconv = NULL;
5677 }
5678 fptr->writeconv_initialized = 0;
5679}
5680
5681static void
5682clear_codeconv(rb_io_t *fptr)
5683{
5684 clear_readconv(fptr);
5685 clear_writeconv(fptr);
5686}
5687
5688static void
5689rb_io_fptr_cleanup_all(rb_io_t *fptr)
5690{
5691 fptr->pathv = Qnil;
5692 if (0 <= fptr->fd)
5693 rb_io_fptr_cleanup(fptr, TRUE);
5694 fptr->write_lock = Qnil;
5695 free_io_buffer(&fptr->rbuf);
5696 free_io_buffer(&fptr->wbuf);
5697 clear_codeconv(fptr);
5698}
5699
5700int
5702{
5703 if (!io) return 0;
5704 rb_io_fptr_cleanup_all(io);
5705 free(io);
5706
5707 return 1;
5708}
5709
5710size_t
5711rb_io_memsize(const rb_io_t *io)
5712{
5713 size_t size = sizeof(rb_io_t);
5714 size += io->rbuf.capa;
5715 size += io->wbuf.capa;
5716 size += io->cbuf.capa;
5717 if (io->readconv) size += rb_econv_memsize(io->readconv);
5718 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5719
5720 struct rb_io_blocking_operation *blocking_operation = 0;
5721
5722 // Validate the fork generation of the IO object. If the IO object fork generation is different, the list of blocking operations is not valid memory. See `rb_io_blocking_operations` for the exact semantics.
5723 rb_serial_t fork_generation = GET_VM()->fork_gen;
5724 if (io->fork_generation == fork_generation) {
5725 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5726 size += sizeof(struct rb_io_blocking_operation);
5727 }
5728 }
5729
5730 return size;
5731}
5732
5733#ifdef _WIN32
5734/* keep GVL while closing to prevent crash on Windows */
5735# define KEEPGVL TRUE
5736#else
5737# define KEEPGVL FALSE
5738#endif
5739
5740static rb_io_t *
5741io_close_fptr(VALUE io)
5742{
5743 rb_io_t *fptr;
5744 VALUE write_io;
5745 rb_io_t *write_fptr;
5746
5747 write_io = GetWriteIO(io);
5748 if (io != write_io) {
5749 write_fptr = RFILE(write_io)->fptr;
5750 if (write_fptr && 0 <= write_fptr->fd) {
5751 rb_io_fptr_cleanup(write_fptr, TRUE);
5752 }
5753 }
5754
5755 fptr = RFILE(io)->fptr;
5756 if (!fptr) return 0;
5757 if (fptr->fd < 0) return 0;
5758
5759 // This guards against multiple threads closing the same IO object:
5760 if (rb_thread_io_close_interrupt(fptr)) {
5761 /* calls close(fptr->fd): */
5762 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5763 }
5764
5765 rb_io_fptr_cleanup(fptr, FALSE);
5766 return fptr;
5767}
5768
5769static void
5770fptr_waitpid(rb_io_t *fptr, int nohang)
5771{
5772 int status;
5773 if (fptr->pid) {
5774 rb_last_status_clear();
5775 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5776 fptr->pid = 0;
5777 }
5778}
5779
5780VALUE
5782{
5783 rb_io_t *fptr = io_close_fptr(io);
5784 if (fptr) fptr_waitpid(fptr, 0);
5785 return Qnil;
5786}
5787
5788/*
5789 * call-seq:
5790 * close -> nil
5791 *
5792 * Closes the stream for both reading and writing
5793 * if open for either or both; returns +nil+.
5794 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5795 *
5796 * If the stream is open for writing, flushes any buffered writes
5797 * to the operating system before closing.
5798 *
5799 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5800 * (child exit status).
5801 *
5802 * It is not an error to close an IO object that has already been closed.
5803 * It just returns nil.
5804 *
5805 * Example:
5806 *
5807 * IO.popen('ruby', 'r+') do |pipe|
5808 * puts pipe.closed?
5809 * pipe.close
5810 * puts $?
5811 * puts pipe.closed?
5812 * end
5813 *
5814 * Output:
5815 *
5816 * false
5817 * pid 13760 exit 0
5818 * true
5819 *
5820 * Related: IO#close_read, IO#close_write, IO#closed?.
5821 */
5822
5823static VALUE
5824rb_io_close_m(VALUE io)
5825{
5826 rb_io_t *fptr = rb_io_get_fptr(io);
5827 if (fptr->fd < 0) {
5828 return Qnil;
5829 }
5830 rb_io_close(io);
5831 return Qnil;
5832}
5833
5834static VALUE
5835io_call_close(VALUE io)
5836{
5837 rb_check_funcall(io, rb_intern("close"), 0, 0);
5838 return io;
5839}
5840
5841static VALUE
5842ignore_closed_stream(VALUE io, VALUE exc)
5843{
5844 enum {mesg_len = sizeof(closed_stream)-1};
5845 VALUE mesg = rb_attr_get(exc, idMesg);
5846 if (!RB_TYPE_P(mesg, T_STRING) ||
5847 RSTRING_LEN(mesg) != mesg_len ||
5848 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5849 rb_exc_raise(exc);
5850 }
5851 return io;
5852}
5853
5854static VALUE
5855io_close(VALUE io)
5856{
5857 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5858 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5859 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5860 rb_eIOError, (VALUE)0);
5861 return io;
5862}
5863
5864/*
5865 * call-seq:
5866 * closed? -> true or false
5867 *
5868 * Returns +true+ if the stream is closed for both reading and writing,
5869 * +false+ otherwise.
5870 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5871 *
5872 * IO.popen('ruby', 'r+') do |pipe|
5873 * puts pipe.closed?
5874 * pipe.close_read
5875 * puts pipe.closed?
5876 * pipe.close_write
5877 * puts pipe.closed?
5878 * end
5879 *
5880 * Output:
5881 *
5882 * false
5883 * false
5884 * true
5885 *
5886 * Related: IO#close_read, IO#close_write, IO#close.
5887 */
5888VALUE
5890{
5891 rb_io_t *fptr;
5892 VALUE write_io;
5893 rb_io_t *write_fptr;
5894
5895 write_io = GetWriteIO(io);
5896 if (io != write_io) {
5897 write_fptr = RFILE(write_io)->fptr;
5898 if (write_fptr && 0 <= write_fptr->fd) {
5899 return Qfalse;
5900 }
5901 }
5902
5903 fptr = rb_io_get_fptr(io);
5904 return RBOOL(0 > fptr->fd);
5905}
5906
5907/*
5908 * call-seq:
5909 * close_read -> nil
5910 *
5911 * Closes the stream for reading if open for reading;
5912 * returns +nil+.
5913 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5914 *
5915 * If the stream was opened by IO.popen and is also closed for writing,
5916 * sets global variable <tt>$?</tt> (child exit status).
5917 *
5918 * Example:
5919 *
5920 * IO.popen('ruby', 'r+') do |pipe|
5921 * puts pipe.closed?
5922 * pipe.close_write
5923 * puts pipe.closed?
5924 * pipe.close_read
5925 * puts $?
5926 * puts pipe.closed?
5927 * end
5928 *
5929 * Output:
5930 *
5931 * false
5932 * false
5933 * pid 14748 exit 0
5934 * true
5935 *
5936 * Related: IO#close, IO#close_write, IO#closed?.
5937 */
5938
5939static VALUE
5940rb_io_close_read(VALUE io)
5941{
5942 rb_io_t *fptr;
5943 VALUE write_io;
5944
5945 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5946 if (fptr->fd < 0) return Qnil;
5947 if (is_socket(fptr->fd, fptr->pathv)) {
5948#ifndef SHUT_RD
5949# define SHUT_RD 0
5950#endif
5951 if (shutdown(fptr->fd, SHUT_RD) < 0)
5952 rb_sys_fail_path(fptr->pathv);
5953 fptr->mode &= ~FMODE_READABLE;
5954 if (!(fptr->mode & FMODE_WRITABLE))
5955 return rb_io_close(io);
5956 return Qnil;
5957 }
5958
5959 write_io = GetWriteIO(io);
5960 if (io != write_io) {
5961 rb_io_t *wfptr;
5962 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5963 wfptr->pid = fptr->pid;
5964 fptr->pid = 0;
5965 RFILE(io)->fptr = wfptr;
5966 /* bind to write_io temporarily to get rid of memory/fd leak */
5967 fptr->tied_io_for_writing = 0;
5968 RFILE(write_io)->fptr = fptr;
5969 rb_io_fptr_cleanup(fptr, FALSE);
5970 /* should not finalize fptr because another thread may be reading it */
5971 return Qnil;
5972 }
5973
5974 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5975 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5976 }
5977 return rb_io_close(io);
5978}
5979
5980/*
5981 * call-seq:
5982 * close_write -> nil
5983 *
5984 * Closes the stream for writing if open for writing;
5985 * returns +nil+.
5986 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5987 *
5988 * Flushes any buffered writes to the operating system before closing.
5989 *
5990 * If the stream was opened by IO.popen and is also closed for reading,
5991 * sets global variable <tt>$?</tt> (child exit status).
5992 *
5993 * IO.popen('ruby', 'r+') do |pipe|
5994 * puts pipe.closed?
5995 * pipe.close_read
5996 * puts pipe.closed?
5997 * pipe.close_write
5998 * puts $?
5999 * puts pipe.closed?
6000 * end
6001 *
6002 * Output:
6003 *
6004 * false
6005 * false
6006 * pid 15044 exit 0
6007 * true
6008 *
6009 * Related: IO#close, IO#close_read, IO#closed?.
6010 */
6011
6012static VALUE
6013rb_io_close_write(VALUE io)
6014{
6015 rb_io_t *fptr;
6016 VALUE write_io;
6017
6018 write_io = GetWriteIO(io);
6019 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6020 if (fptr->fd < 0) return Qnil;
6021 if (is_socket(fptr->fd, fptr->pathv)) {
6022#ifndef SHUT_WR
6023# define SHUT_WR 1
6024#endif
6025 if (shutdown(fptr->fd, SHUT_WR) < 0)
6026 rb_sys_fail_path(fptr->pathv);
6027 fptr->mode &= ~FMODE_WRITABLE;
6028 if (!(fptr->mode & FMODE_READABLE))
6029 return rb_io_close(write_io);
6030 return Qnil;
6031 }
6032
6033 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6034 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6035 }
6036
6037 if (io != write_io) {
6038 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6039 fptr->tied_io_for_writing = 0;
6040 }
6041 rb_io_close(write_io);
6042 return Qnil;
6043}
6044
6045/*
6046 * call-seq:
6047 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6048 *
6049 * Behaves like IO#seek, except that it:
6050 *
6051 * - Uses low-level system functions.
6052 * - Returns the new position.
6053 *
6054 */
6055
6056static VALUE
6057rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6058{
6059 VALUE offset, ptrname;
6060 int whence = SEEK_SET;
6061 rb_io_t *fptr;
6062 rb_off_t pos;
6063
6064 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6065 whence = interpret_seek_whence(ptrname);
6066 }
6067 pos = NUM2OFFT(offset);
6068 GetOpenFile(io, fptr);
6069 if ((fptr->mode & FMODE_READABLE) &&
6070 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6071 rb_raise(rb_eIOError, "sysseek for buffered IO");
6072 }
6073 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6074 rb_warn("sysseek for buffered IO");
6075 }
6076 errno = 0;
6077 pos = lseek(fptr->fd, pos, whence);
6078 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6079
6080 return OFFT2NUM(pos);
6081}
6082
6083/*
6084 * call-seq:
6085 * syswrite(object) -> integer
6086 *
6087 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6088 * returns the number bytes written.
6089 * If +object+ is not a string is converted via method to_s:
6090 *
6091 * f = File.new('t.tmp', 'w')
6092 * f.syswrite('foo') # => 3
6093 * f.syswrite(30) # => 2
6094 * f.syswrite(:foo) # => 3
6095 * f.close
6096 *
6097 * This methods should not be used with other stream-writer methods.
6098 *
6099 */
6100
6101static VALUE
6102rb_io_syswrite(VALUE io, VALUE str)
6103{
6104 VALUE tmp;
6105 rb_io_t *fptr;
6106 long n, len;
6107 const char *ptr;
6108
6109 if (!RB_TYPE_P(str, T_STRING))
6110 str = rb_obj_as_string(str);
6111
6112 io = GetWriteIO(io);
6113 GetOpenFile(io, fptr);
6115
6116 if (fptr->wbuf.len) {
6117 rb_warn("syswrite for buffered IO");
6118 }
6119
6120 tmp = rb_str_tmp_frozen_acquire(str);
6121 RSTRING_GETMEM(tmp, ptr, len);
6122 n = rb_io_write_memory(fptr, ptr, len);
6123 if (n < 0) rb_sys_fail_path(fptr->pathv);
6124 rb_str_tmp_frozen_release(str, tmp);
6125
6126 return LONG2FIX(n);
6127}
6128
6129/*
6130 * call-seq:
6131 * sysread(maxlen) -> string
6132 * sysread(maxlen, out_string) -> string
6133 *
6134 * Behaves like IO#readpartial, except that it uses low-level system functions.
6135 *
6136 * This method should not be used with other stream-reader methods.
6137 *
6138 */
6139
6140static VALUE
6141rb_io_sysread(int argc, VALUE *argv, VALUE io)
6142{
6143 VALUE len, str;
6144 rb_io_t *fptr;
6145 long n, ilen;
6146 struct io_internal_read_struct iis;
6147 int shrinkable;
6148
6149 rb_scan_args(argc, argv, "11", &len, &str);
6150 ilen = NUM2LONG(len);
6151
6152 shrinkable = io_setstrbuf(&str, ilen);
6153 if (ilen == 0) return str;
6154
6155 GetOpenFile(io, fptr);
6157
6158 if (READ_DATA_BUFFERED(fptr)) {
6159 rb_raise(rb_eIOError, "sysread for buffered IO");
6160 }
6161
6162 rb_io_check_closed(fptr);
6163
6164 io_setstrbuf(&str, ilen);
6165 iis.th = rb_thread_current();
6166 iis.fptr = fptr;
6167 iis.nonblock = 0;
6168 iis.fd = fptr->fd;
6169 iis.buf = RSTRING_PTR(str);
6170 iis.capa = ilen;
6171 iis.timeout = NULL;
6172 n = io_read_memory_locktmp(str, &iis);
6173
6174 if (n < 0) {
6175 rb_sys_fail_path(fptr->pathv);
6176 }
6177
6178 io_set_read_length(str, n, shrinkable);
6179
6180 if (n == 0 && ilen > 0) {
6181 rb_eof_error();
6182 }
6183
6184 return str;
6185}
6186
6188 struct rb_io *io;
6189 int fd;
6190 void *buf;
6191 size_t count;
6192 rb_off_t offset;
6193};
6194
6195static VALUE
6196internal_pread_func(void *_arg)
6197{
6198 struct prdwr_internal_arg *arg = _arg;
6199
6200 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6201}
6202
6203static VALUE
6204pread_internal_call(VALUE _arg)
6205{
6206 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6207
6208 VALUE scheduler = rb_fiber_scheduler_current();
6209 if (scheduler != Qnil) {
6210 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6211
6212 if (!UNDEF_P(result)) {
6214 }
6215 }
6216
6217 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6218}
6219
6220/*
6221 * call-seq:
6222 * pread(maxlen, offset) -> string
6223 * pread(maxlen, offset, out_string) -> string
6224 *
6225 * Behaves like IO#readpartial, except that it:
6226 *
6227 * - Reads at the given +offset+ (in bytes).
6228 * - Disregards, and does not modify, the stream's position
6229 * (see {Position}[rdoc-ref:IO@Position]).
6230 * - Bypasses any user space buffering in the stream.
6231 *
6232 * Because this method does not disturb the stream's state
6233 * (its position, in particular), +pread+ allows multiple threads and processes
6234 * to use the same \IO object for reading at various offsets.
6235 *
6236 * f = File.open('t.txt')
6237 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6238 * f.pos # => 52
6239 * # Read 12 bytes at offset 0.
6240 * f.pread(12, 0) # => "First line\n"
6241 * # Read 9 bytes at offset 8.
6242 * f.pread(9, 8) # => "ne\nSecon"
6243 * f.close
6244 *
6245 * Not available on some platforms.
6246 *
6247 */
6248static VALUE
6249rb_io_pread(int argc, VALUE *argv, VALUE io)
6250{
6251 VALUE len, offset, str;
6252 rb_io_t *fptr;
6253 ssize_t n;
6254 struct prdwr_internal_arg arg;
6255 int shrinkable;
6256
6257 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6258 arg.count = NUM2SIZET(len);
6259 arg.offset = NUM2OFFT(offset);
6260
6261 shrinkable = io_setstrbuf(&str, (long)arg.count);
6262 if (arg.count == 0) return str;
6263 arg.buf = RSTRING_PTR(str);
6264
6265 GetOpenFile(io, fptr);
6267
6268 arg.io = fptr;
6269 arg.fd = fptr->fd;
6270 rb_io_check_closed(fptr);
6271
6272 rb_str_locktmp(str);
6273 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6274
6275 if (n < 0) {
6276 rb_sys_fail_path(fptr->pathv);
6277 }
6278 io_set_read_length(str, n, shrinkable);
6279 if (n == 0 && arg.count > 0) {
6280 rb_eof_error();
6281 }
6282
6283 return str;
6284}
6285
6286static VALUE
6287internal_pwrite_func(void *_arg)
6288{
6289 struct prdwr_internal_arg *arg = _arg;
6290
6291 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6292}
6293
6294static VALUE
6295pwrite_internal_call(VALUE _arg)
6296{
6297 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6298
6299 VALUE scheduler = rb_fiber_scheduler_current();
6300 if (scheduler != Qnil) {
6301 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6302
6303 if (!UNDEF_P(result)) {
6305 }
6306 }
6307
6308 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6309}
6310
6311/*
6312 * call-seq:
6313 * pwrite(object, offset) -> integer
6314 *
6315 * Behaves like IO#write, except that it:
6316 *
6317 * - Writes at the given +offset+ (in bytes).
6318 * - Disregards, and does not modify, the stream's position
6319 * (see {Position}[rdoc-ref:IO@Position]).
6320 * - Bypasses any user space buffering in the stream.
6321 *
6322 * Because this method does not disturb the stream's state
6323 * (its position, in particular), +pwrite+ allows multiple threads and processes
6324 * to use the same \IO object for writing at various offsets.
6325 *
6326 * f = File.open('t.tmp', 'w+')
6327 * # Write 6 bytes at offset 3.
6328 * f.pwrite('ABCDEF', 3) # => 6
6329 * f.rewind
6330 * f.read # => "\u0000\u0000\u0000ABCDEF"
6331 * f.close
6332 *
6333 * Not available on some platforms.
6334 *
6335 */
6336static VALUE
6337rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6338{
6339 rb_io_t *fptr;
6340 ssize_t n;
6341 struct prdwr_internal_arg arg;
6342 VALUE tmp;
6343
6344 if (!RB_TYPE_P(str, T_STRING))
6345 str = rb_obj_as_string(str);
6346
6347 arg.offset = NUM2OFFT(offset);
6348
6349 io = GetWriteIO(io);
6350 GetOpenFile(io, fptr);
6352
6353 arg.io = fptr;
6354 arg.fd = fptr->fd;
6355
6356 tmp = rb_str_tmp_frozen_acquire(str);
6357 arg.buf = RSTRING_PTR(tmp);
6358 arg.count = (size_t)RSTRING_LEN(tmp);
6359
6360 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6361 if (n < 0) rb_sys_fail_path(fptr->pathv);
6362 rb_str_tmp_frozen_release(str, tmp);
6363
6364 return SSIZET2NUM(n);
6365}
6366
6367VALUE
6369{
6370 rb_io_t *fptr;
6371
6372 GetOpenFile(io, fptr);
6373 if (fptr->readconv)
6375 if (fptr->writeconv)
6377 fptr->mode |= FMODE_BINMODE;
6378 fptr->mode &= ~FMODE_TEXTMODE;
6379 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6380#ifdef O_BINARY
6381 if (!fptr->readconv) {
6382 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6383 }
6384 else {
6385 setmode(fptr->fd, O_BINARY);
6386 }
6387#endif
6388 return io;
6389}
6390
6391static void
6392io_ascii8bit_binmode(rb_io_t *fptr)
6393{
6394 if (fptr->readconv) {
6395 rb_econv_close(fptr->readconv);
6396 fptr->readconv = NULL;
6397 }
6398 if (fptr->writeconv) {
6400 fptr->writeconv = NULL;
6401 }
6402 fptr->mode |= FMODE_BINMODE;
6403 fptr->mode &= ~FMODE_TEXTMODE;
6404 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6405
6406 fptr->encs.enc = rb_ascii8bit_encoding();
6407 fptr->encs.enc2 = NULL;
6408 fptr->encs.ecflags = 0;
6409 fptr->encs.ecopts = Qnil;
6410 clear_codeconv(fptr);
6411}
6412
6413VALUE
6415{
6416 rb_io_t *fptr;
6417
6418 GetOpenFile(io, fptr);
6419 io_ascii8bit_binmode(fptr);
6420
6421 return io;
6422}
6423
6424/*
6425 * call-seq:
6426 * binmode -> self
6427 *
6428 * Sets the stream's data mode as binary
6429 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6430 *
6431 * A stream's data mode may not be changed from binary to text.
6432 *
6433 */
6434
6435static VALUE
6436rb_io_binmode_m(VALUE io)
6437{
6438 VALUE write_io;
6439
6441
6442 write_io = GetWriteIO(io);
6443 if (write_io != io)
6444 rb_io_ascii8bit_binmode(write_io);
6445 return io;
6446}
6447
6448/*
6449 * call-seq:
6450 * binmode? -> true or false
6451 *
6452 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6453 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6454 *
6455 */
6456static VALUE
6457rb_io_binmode_p(VALUE io)
6458{
6459 rb_io_t *fptr;
6460 GetOpenFile(io, fptr);
6461 return RBOOL(fptr->mode & FMODE_BINMODE);
6462}
6463
6464static const char*
6465rb_io_fmode_modestr(enum rb_io_mode fmode)
6466{
6467 if (fmode & FMODE_APPEND) {
6468 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6469 return MODE_BTMODE("a+", "ab+", "at+");
6470 }
6471 return MODE_BTMODE("a", "ab", "at");
6472 }
6473 switch (fmode & FMODE_READWRITE) {
6474 default:
6475 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6476 case FMODE_READABLE:
6477 return MODE_BTMODE("r", "rb", "rt");
6478 case FMODE_WRITABLE:
6479 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6480 case FMODE_READWRITE:
6481 if (fmode & FMODE_CREATE) {
6482 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6483 }
6484 return MODE_BTMODE("r+", "rb+", "rt+");
6485 }
6486}
6487
6488static const char bom_prefix[] = "bom|";
6489static const char utf_prefix[] = "utf-";
6490enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6491enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6492
6493static int
6494io_encname_bom_p(const char *name, long len)
6495{
6496 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6497}
6498
6499enum rb_io_mode
6500rb_io_modestr_fmode(const char *modestr)
6501{
6502 enum rb_io_mode fmode = 0;
6503 const char *m = modestr, *p = NULL;
6504
6505 switch (*m++) {
6506 case 'r':
6507 fmode |= FMODE_READABLE;
6508 break;
6509 case 'w':
6511 break;
6512 case 'a':
6514 break;
6515 default:
6516 goto error;
6517 }
6518
6519 while (*m) {
6520 switch (*m++) {
6521 case 'b':
6522 fmode |= FMODE_BINMODE;
6523 break;
6524 case 't':
6525 fmode |= FMODE_TEXTMODE;
6526 break;
6527 case '+':
6528 fmode |= FMODE_READWRITE;
6529 break;
6530 case 'x':
6531 if (modestr[0] != 'w')
6532 goto error;
6533 fmode |= FMODE_EXCL;
6534 break;
6535 default:
6536 goto error;
6537 case ':':
6538 p = strchr(m, ':');
6539 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6540 fmode |= FMODE_SETENC_BY_BOM;
6541 goto finished;
6542 }
6543 }
6544
6545 finished:
6546 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6547 goto error;
6548
6549 return fmode;
6550
6551 error:
6552 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6554}
6555
6556int
6557rb_io_oflags_fmode(int oflags)
6558{
6559 enum rb_io_mode fmode = 0;
6560
6561 switch (oflags & O_ACCMODE) {
6562 case O_RDONLY:
6563 fmode = FMODE_READABLE;
6564 break;
6565 case O_WRONLY:
6566 fmode = FMODE_WRITABLE;
6567 break;
6568 case O_RDWR:
6569 fmode = FMODE_READWRITE;
6570 break;
6571 }
6572
6573 if (oflags & O_APPEND) {
6574 fmode |= FMODE_APPEND;
6575 }
6576 if (oflags & O_TRUNC) {
6577 fmode |= FMODE_TRUNC;
6578 }
6579 if (oflags & O_CREAT) {
6580 fmode |= FMODE_CREATE;
6581 }
6582 if (oflags & O_EXCL) {
6583 fmode |= FMODE_EXCL;
6584 }
6585#ifdef O_BINARY
6586 if (oflags & O_BINARY) {
6587 fmode |= FMODE_BINMODE;
6588 }
6589#endif
6590
6591 return fmode;
6592}
6593
6594static int
6595rb_io_fmode_oflags(enum rb_io_mode fmode)
6596{
6597 int oflags = 0;
6598
6599 switch (fmode & FMODE_READWRITE) {
6600 case FMODE_READABLE:
6601 oflags |= O_RDONLY;
6602 break;
6603 case FMODE_WRITABLE:
6604 oflags |= O_WRONLY;
6605 break;
6606 case FMODE_READWRITE:
6607 oflags |= O_RDWR;
6608 break;
6609 }
6610
6611 if (fmode & FMODE_APPEND) {
6612 oflags |= O_APPEND;
6613 }
6614 if (fmode & FMODE_TRUNC) {
6615 oflags |= O_TRUNC;
6616 }
6617 if (fmode & FMODE_CREATE) {
6618 oflags |= O_CREAT;
6619 }
6620 if (fmode & FMODE_EXCL) {
6621 oflags |= O_EXCL;
6622 }
6623#ifdef O_BINARY
6624 if (fmode & FMODE_BINMODE) {
6625 oflags |= O_BINARY;
6626 }
6627#endif
6628
6629 return oflags;
6630}
6631
6632int
6633rb_io_modestr_oflags(const char *modestr)
6634{
6635 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6636}
6637
6638static const char*
6639rb_io_oflags_modestr(int oflags)
6640{
6641#ifdef O_BINARY
6642# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6643#else
6644# define MODE_BINARY(a,b) (a)
6645#endif
6646 int accmode;
6647 if (oflags & O_EXCL) {
6648 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6649 }
6650 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6651 if (oflags & O_APPEND) {
6652 if (accmode == O_WRONLY) {
6653 return MODE_BINARY("a", "ab");
6654 }
6655 if (accmode == O_RDWR) {
6656 return MODE_BINARY("a+", "ab+");
6657 }
6658 }
6659 switch (accmode) {
6660 default:
6661 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6662 case O_RDONLY:
6663 return MODE_BINARY("r", "rb");
6664 case O_WRONLY:
6665 return MODE_BINARY("w", "wb");
6666 case O_RDWR:
6667 if (oflags & O_TRUNC) {
6668 return MODE_BINARY("w+", "wb+");
6669 }
6670 return MODE_BINARY("r+", "rb+");
6671 }
6672}
6673
6674/*
6675 * Convert external/internal encodings to enc/enc2
6676 * NULL => use default encoding
6677 * Qnil => no encoding specified (internal only)
6678 */
6679static void
6680rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6681{
6682 int default_ext = 0;
6683
6684 if (ext == NULL) {
6685 ext = rb_default_external_encoding();
6686 default_ext = 1;
6687 }
6688 if (rb_is_ascii8bit_enc(ext)) {
6689 /* If external is ASCII-8BIT, no transcoding */
6690 intern = NULL;
6691 }
6692 else if (intern == NULL) {
6693 intern = rb_default_internal_encoding();
6694 }
6695 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6696 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6697 /* No internal encoding => use external + no transcoding */
6698 *enc = (default_ext && intern != ext) ? NULL : ext;
6699 *enc2 = NULL;
6700 }
6701 else {
6702 *enc = intern;
6703 *enc2 = ext;
6704 }
6705}
6706
6707static void
6708unsupported_encoding(const char *name, rb_encoding *enc)
6709{
6710 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6711}
6712
6713static void
6714parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6715 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6716{
6717 const char *p;
6718 char encname[ENCODING_MAXNAMELEN+1];
6719 int idx, idx2;
6720 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6721 rb_encoding *ext_enc, *int_enc;
6722 long len;
6723
6724 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6725
6726 p = strrchr(estr, ':');
6727 len = p ? (p++ - estr) : (long)strlen(estr);
6728 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6729 estr += bom_prefix_len;
6730 len -= bom_prefix_len;
6731 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6732 fmode |= FMODE_SETENC_BY_BOM;
6733 }
6734 else {
6735 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6736 fmode &= ~FMODE_SETENC_BY_BOM;
6737 }
6738 }
6739 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6740 idx = -1;
6741 }
6742 else {
6743 if (p) {
6744 memcpy(encname, estr, len);
6745 encname[len] = '\0';
6746 estr = encname;
6747 }
6748 idx = rb_enc_find_index(estr);
6749 }
6750 if (fmode_p) *fmode_p = fmode;
6751
6752 if (idx >= 0)
6753 ext_enc = rb_enc_from_index(idx);
6754 else {
6755 if (idx != -2)
6756 unsupported_encoding(estr, estr_enc);
6757 ext_enc = NULL;
6758 }
6759
6760 int_enc = NULL;
6761 if (p) {
6762 if (*p == '-' && *(p+1) == '\0') {
6763 /* Special case - "-" => no transcoding */
6764 int_enc = (rb_encoding *)Qnil;
6765 }
6766 else {
6767 idx2 = rb_enc_find_index(p);
6768 if (idx2 < 0)
6769 unsupported_encoding(p, estr_enc);
6770 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6771 int_enc = (rb_encoding *)Qnil;
6772 }
6773 else
6774 int_enc = rb_enc_from_index(idx2);
6775 }
6776 }
6777
6778 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6779}
6780
6781int
6782rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6783{
6784 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6785 int extracted = 0;
6786 rb_encoding *extencoding = NULL;
6787 rb_encoding *intencoding = NULL;
6788
6789 if (!NIL_P(opt)) {
6790 VALUE v;
6791 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6792 if (v != Qnil) encoding = v;
6793 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6794 if (v != Qnil) extenc = v;
6795 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6796 if (!UNDEF_P(v)) intenc = v;
6797 }
6798 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6799 if (!NIL_P(ruby_verbose)) {
6800 int idx = rb_to_encoding_index(encoding);
6801 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6802 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6803 encoding, UNDEF_P(extenc) ? "internal" : "external");
6804 }
6805 encoding = Qnil;
6806 }
6807 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6808 extencoding = rb_to_encoding(extenc);
6809 }
6810 if (!UNDEF_P(intenc)) {
6811 if (NIL_P(intenc)) {
6812 /* internal_encoding: nil => no transcoding */
6813 intencoding = (rb_encoding *)Qnil;
6814 }
6815 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6816 char *p = StringValueCStr(tmp);
6817
6818 if (*p == '-' && *(p+1) == '\0') {
6819 /* Special case - "-" => no transcoding */
6820 intencoding = (rb_encoding *)Qnil;
6821 }
6822 else {
6823 intencoding = rb_to_encoding(intenc);
6824 }
6825 }
6826 else {
6827 intencoding = rb_to_encoding(intenc);
6828 }
6829 if (extencoding == intencoding) {
6830 intencoding = (rb_encoding *)Qnil;
6831 }
6832 }
6833 if (!NIL_P(encoding)) {
6834 extracted = 1;
6835 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6836 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6837 enc_p, enc2_p, fmode_p);
6838 }
6839 else {
6840 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6841 }
6842 }
6843 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6844 extracted = 1;
6845 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6846 }
6847 return extracted;
6848}
6849
6850static void
6851validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6852{
6853 enum rb_io_mode fmode = *fmode_p;
6854
6855 if ((fmode & FMODE_READABLE) &&
6856 !enc2 &&
6857 !(fmode & FMODE_BINMODE) &&
6858 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6859 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6860
6861 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6862 rb_raise(rb_eArgError, "newline decorator with binary mode");
6863 }
6864 if (!(fmode & FMODE_BINMODE) &&
6865 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6866 fmode |= FMODE_TEXTMODE;
6867 *fmode_p = fmode;
6868 }
6869#if !DEFAULT_TEXTMODE
6870 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6871 fmode &= ~FMODE_TEXTMODE;
6872 *fmode_p = fmode;
6873 }
6874#endif
6875}
6876
6877static void
6878extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6879{
6880 if (!NIL_P(opthash)) {
6881 VALUE v;
6882 v = rb_hash_aref(opthash, sym_textmode);
6883 if (!NIL_P(v)) {
6884 if (*fmode & FMODE_TEXTMODE)
6885 rb_raise(rb_eArgError, "textmode specified twice");
6886 if (*fmode & FMODE_BINMODE)
6887 rb_raise(rb_eArgError, "both textmode and binmode specified");
6888 if (RTEST(v))
6889 *fmode |= FMODE_TEXTMODE;
6890 }
6891 v = rb_hash_aref(opthash, sym_binmode);
6892 if (!NIL_P(v)) {
6893 if (*fmode & FMODE_BINMODE)
6894 rb_raise(rb_eArgError, "binmode specified twice");
6895 if (*fmode & FMODE_TEXTMODE)
6896 rb_raise(rb_eArgError, "both textmode and binmode specified");
6897 if (RTEST(v))
6898 *fmode |= FMODE_BINMODE;
6899 }
6900
6901 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6902 rb_raise(rb_eArgError, "both textmode and binmode specified");
6903 }
6904}
6905
6906void
6907rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6908 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6909{
6910 VALUE vmode;
6911 int oflags;
6912 enum rb_io_mode fmode;
6913 rb_encoding *enc, *enc2;
6914 int ecflags;
6915 VALUE ecopts;
6916 int has_enc = 0, has_vmode = 0;
6917 VALUE intmode;
6918
6919 vmode = *vmode_p;
6920
6921 /* Set to defaults */
6922 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6923
6924 vmode_handle:
6925 if (NIL_P(vmode)) {
6926 fmode = FMODE_READABLE;
6927 oflags = O_RDONLY;
6928 }
6929 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6930 vmode = intmode;
6931 oflags = NUM2INT(intmode);
6932 fmode = rb_io_oflags_fmode(oflags);
6933 }
6934 else {
6935 const char *p;
6936
6937 StringValue(vmode);
6938 p = StringValueCStr(vmode);
6939 fmode = rb_io_modestr_fmode(p);
6940 oflags = rb_io_fmode_oflags(fmode);
6941 p = strchr(p, ':');
6942 if (p) {
6943 has_enc = 1;
6944 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6945 }
6946 else {
6947 rb_encoding *e;
6948
6949 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6950 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6951 }
6952 }
6953
6954 if (NIL_P(opthash)) {
6955 ecflags = (fmode & FMODE_READABLE) ?
6958#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6959 ecflags |= (fmode & FMODE_WRITABLE) ?
6960 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6961 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6962#endif
6963 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6964 ecopts = Qnil;
6965 if (fmode & FMODE_BINMODE) {
6966#ifdef O_BINARY
6967 oflags |= O_BINARY;
6968#endif
6969 if (!has_enc)
6970 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6971 }
6972#if DEFAULT_TEXTMODE
6973 else if (NIL_P(vmode)) {
6974 fmode |= DEFAULT_TEXTMODE;
6975 }
6976#endif
6977 }
6978 else {
6979 VALUE v;
6980 if (!has_vmode) {
6981 v = rb_hash_aref(opthash, sym_mode);
6982 if (!NIL_P(v)) {
6983 if (!NIL_P(vmode)) {
6984 rb_raise(rb_eArgError, "mode specified twice");
6985 }
6986 has_vmode = 1;
6987 vmode = v;
6988 goto vmode_handle;
6989 }
6990 }
6991 v = rb_hash_aref(opthash, sym_flags);
6992 if (!NIL_P(v)) {
6993 v = rb_to_int(v);
6994 oflags |= NUM2INT(v);
6995 vmode = INT2NUM(oflags);
6996 fmode = rb_io_oflags_fmode(oflags);
6997 }
6998 extract_binmode(opthash, &fmode);
6999 if (fmode & FMODE_BINMODE) {
7000#ifdef O_BINARY
7001 oflags |= O_BINARY;
7002#endif
7003 if (!has_enc)
7004 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7005 }
7006#if DEFAULT_TEXTMODE
7007 else if (NIL_P(vmode)) {
7008 fmode |= DEFAULT_TEXTMODE;
7009 }
7010#endif
7011 v = rb_hash_aref(opthash, sym_perm);
7012 if (!NIL_P(v)) {
7013 if (vperm_p) {
7014 if (!NIL_P(*vperm_p)) {
7015 rb_raise(rb_eArgError, "perm specified twice");
7016 }
7017 *vperm_p = v;
7018 }
7019 else {
7020 /* perm no use, just ignore */
7021 }
7022 }
7023 ecflags = (fmode & FMODE_READABLE) ?
7026#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7027 ecflags |= (fmode & FMODE_WRITABLE) ?
7028 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7029 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7030#endif
7031
7032 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7033 if (has_enc) {
7034 rb_raise(rb_eArgError, "encoding specified twice");
7035 }
7036 }
7037 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7038 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7039 }
7040
7041 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7042
7043 *vmode_p = vmode;
7044
7045 *oflags_p = oflags;
7046 *fmode_p = fmode;
7047 convconfig_p->enc = enc;
7048 convconfig_p->enc2 = enc2;
7049 convconfig_p->ecflags = ecflags;
7050 convconfig_p->ecopts = ecopts;
7051}
7052
7054 VALUE fname;
7055 int oflags;
7056 mode_t perm;
7057};
7058
7059static void *
7060sysopen_func(void *ptr)
7061{
7062 const struct sysopen_struct *data = ptr;
7063 const char *fname = RSTRING_PTR(data->fname);
7064 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7065}
7066
7067static inline int
7068rb_sysopen_internal(struct sysopen_struct *data)
7069{
7070 int fd;
7071 do {
7072 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7073 } while (fd < 0 && errno == EINTR);
7074 if (0 <= fd)
7075 rb_update_max_fd(fd);
7076 return fd;
7077}
7078
7079static int
7080rb_sysopen(VALUE fname, int oflags, mode_t perm)
7081{
7082 int fd = -1;
7083 struct sysopen_struct data;
7084
7085 data.fname = rb_str_encode_ospath(fname);
7086 StringValueCStr(data.fname);
7087 data.oflags = oflags;
7088 data.perm = perm;
7089
7090 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7091 rb_syserr_fail_path(first_errno, fname);
7092 }
7093 return fd;
7094}
7095
7096static inline FILE *
7097fdopen_internal(int fd, const char *modestr)
7098{
7099 FILE *file;
7100
7101#if defined(__sun)
7102 errno = 0;
7103#endif
7104 file = fdopen(fd, modestr);
7105 if (!file) {
7106#ifdef _WIN32
7107 if (errno == 0) errno = EINVAL;
7108#elif defined(__sun)
7109 if (errno == 0) errno = EMFILE;
7110#endif
7111 }
7112 return file;
7113}
7114
7115FILE *
7116rb_fdopen(int fd, const char *modestr)
7117{
7118 FILE *file = 0;
7119
7120 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7121 rb_syserr_fail(first_errno, 0);
7122 }
7123
7124 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7125#ifdef USE_SETVBUF
7126 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7127 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7128#endif
7129 return file;
7130}
7131
7132static int
7133io_check_tty(rb_io_t *fptr)
7134{
7135 int t = isatty(fptr->fd);
7136 if (t)
7137 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7138 return t;
7139}
7140
7141static VALUE rb_io_internal_encoding(VALUE);
7142static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7143
7144static int
7145io_strip_bom(VALUE io)
7146{
7147 VALUE b1, b2, b3, b4;
7148 rb_io_t *fptr;
7149
7150 GetOpenFile(io, fptr);
7151 if (!(fptr->mode & FMODE_READABLE)) return 0;
7152 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7153 switch (b1) {
7154 case INT2FIX(0xEF):
7155 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7156 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7157 if (b3 == INT2FIX(0xBF)) {
7158 return rb_utf8_encindex();
7159 }
7160 rb_io_ungetbyte(io, b3);
7161 }
7162 rb_io_ungetbyte(io, b2);
7163 break;
7164
7165 case INT2FIX(0xFE):
7166 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7167 if (b2 == INT2FIX(0xFF)) {
7168 return ENCINDEX_UTF_16BE;
7169 }
7170 rb_io_ungetbyte(io, b2);
7171 break;
7172
7173 case INT2FIX(0xFF):
7174 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7175 if (b2 == INT2FIX(0xFE)) {
7176 b3 = rb_io_getbyte(io);
7177 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7178 if (b4 == INT2FIX(0)) {
7179 return ENCINDEX_UTF_32LE;
7180 }
7181 rb_io_ungetbyte(io, b4);
7182 }
7183 rb_io_ungetbyte(io, b3);
7184 return ENCINDEX_UTF_16LE;
7185 }
7186 rb_io_ungetbyte(io, b2);
7187 break;
7188
7189 case INT2FIX(0):
7190 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7191 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7192 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7193 if (b4 == INT2FIX(0xFF)) {
7194 return ENCINDEX_UTF_32BE;
7195 }
7196 rb_io_ungetbyte(io, b4);
7197 }
7198 rb_io_ungetbyte(io, b3);
7199 }
7200 rb_io_ungetbyte(io, b2);
7201 break;
7202 }
7203 rb_io_ungetbyte(io, b1);
7204 return 0;
7205}
7206
7207static rb_encoding *
7208io_set_encoding_by_bom(VALUE io)
7209{
7210 int idx = io_strip_bom(io);
7211 rb_io_t *fptr;
7212 rb_encoding *extenc = NULL;
7213
7214 GetOpenFile(io, fptr);
7215 if (idx) {
7216 extenc = rb_enc_from_index(idx);
7217 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7218 rb_io_internal_encoding(io), Qnil);
7219 }
7220 else {
7221 fptr->encs.enc2 = NULL;
7222 }
7223 return extenc;
7224}
7225
7226static VALUE
7227rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7228 const struct rb_io_encoding *convconfig, mode_t perm)
7229{
7230 VALUE pathv;
7231 rb_io_t *fptr;
7232 struct rb_io_encoding cc;
7233 if (!convconfig) {
7234 /* Set to default encodings */
7235 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7236 cc.ecflags = 0;
7237 cc.ecopts = Qnil;
7238 convconfig = &cc;
7239 }
7240 validate_enc_binmode(&fmode, convconfig->ecflags,
7241 convconfig->enc, convconfig->enc2);
7242
7243 MakeOpenFile(io, fptr);
7244 fptr->mode = fmode;
7245 fptr->encs = *convconfig;
7246 pathv = rb_str_new_frozen(filename);
7247#ifdef O_TMPFILE
7248 if (!(oflags & O_TMPFILE)) {
7249 fptr->pathv = pathv;
7250 }
7251#else
7252 fptr->pathv = pathv;
7253#endif
7254 fptr->fd = rb_sysopen(pathv, oflags, perm);
7255 io_check_tty(fptr);
7256 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7257
7258 return io;
7259}
7260
7261static VALUE
7262rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7263{
7264 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7265 const char *p = strchr(modestr, ':');
7266 struct rb_io_encoding convconfig;
7267
7268 if (p) {
7269 parse_mode_enc(p+1, rb_usascii_encoding(),
7270 &convconfig.enc, &convconfig.enc2, &fmode);
7271 }
7272 else {
7273 rb_encoding *e;
7274 /* Set to default encodings */
7275
7276 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7277 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7278 }
7279
7280 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7283#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7284 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7285 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7286 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7287#endif
7288 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7289 convconfig.ecopts = Qnil;
7290
7291 return rb_file_open_generic(io, filename,
7292 rb_io_fmode_oflags(fmode),
7293 fmode,
7294 &convconfig,
7295 0666);
7296}
7297
7298VALUE
7299rb_file_open_str(VALUE fname, const char *modestr)
7300{
7301 FilePathValue(fname);
7302 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7303}
7304
7305VALUE
7306rb_file_open(const char *fname, const char *modestr)
7307{
7308 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7309}
7310
7311#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7312static struct pipe_list {
7313 rb_io_t *fptr;
7314 struct pipe_list *next;
7315} *pipe_list;
7316
7317static void
7318pipe_add_fptr(rb_io_t *fptr)
7319{
7320 struct pipe_list *list;
7321
7322 list = ALLOC(struct pipe_list);
7323 list->fptr = fptr;
7324 list->next = pipe_list;
7325 pipe_list = list;
7326}
7327
7328static void
7329pipe_del_fptr(rb_io_t *fptr)
7330{
7331 struct pipe_list **prev = &pipe_list;
7332 struct pipe_list *tmp;
7333
7334 while ((tmp = *prev) != 0) {
7335 if (tmp->fptr == fptr) {
7336 *prev = tmp->next;
7337 free(tmp);
7338 return;
7339 }
7340 prev = &tmp->next;
7341 }
7342}
7343
7344#if defined (_WIN32) || defined(__CYGWIN__)
7345static void
7346pipe_atexit(void)
7347{
7348 struct pipe_list *list = pipe_list;
7349 struct pipe_list *tmp;
7350
7351 while (list) {
7352 tmp = list->next;
7353 rb_io_fptr_finalize(list->fptr);
7354 list = tmp;
7355 }
7356}
7357#endif
7358
7359static void
7360pipe_finalize(rb_io_t *fptr, int noraise)
7361{
7362#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7363 int status = 0;
7364 if (fptr->stdio_file) {
7365 status = pclose(fptr->stdio_file);
7366 }
7367 fptr->fd = -1;
7368 fptr->stdio_file = 0;
7369 rb_last_status_set(status, fptr->pid);
7370#else
7371 fptr_finalize(fptr, noraise);
7372#endif
7373 pipe_del_fptr(fptr);
7374}
7375#endif
7376
7377static void
7378fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7379{
7380#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7381 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7382
7383 if (old_finalize == orig->finalize) return;
7384#endif
7385
7386 fptr->finalize = orig->finalize;
7387
7388#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7389 if (old_finalize != pipe_finalize) {
7390 struct pipe_list *list;
7391 for (list = pipe_list; list; list = list->next) {
7392 if (list->fptr == fptr) break;
7393 }
7394 if (!list) pipe_add_fptr(fptr);
7395 }
7396 else {
7397 pipe_del_fptr(fptr);
7398 }
7399#endif
7400}
7401
7402void
7404{
7406 fptr->mode |= FMODE_SYNC;
7407}
7408
7409void
7410rb_io_unbuffered(rb_io_t *fptr)
7411{
7412 rb_io_synchronized(fptr);
7413}
7414
7415int
7416rb_pipe(int *pipes)
7417{
7418 int ret;
7419 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7420 if (ret == 0) {
7421 rb_update_max_fd(pipes[0]);
7422 rb_update_max_fd(pipes[1]);
7423 }
7424 return ret;
7425}
7426
7427#ifdef _WIN32
7428#define HAVE_SPAWNV 1
7429#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7430#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7431#endif
7432
7433#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7434struct popen_arg {
7435 VALUE execarg_obj;
7436 struct rb_execarg *eargp;
7437 int modef;
7438 int pair[2];
7439 int write_pair[2];
7440};
7441#endif
7442
7443#ifdef HAVE_WORKING_FORK
7444# ifndef __EMSCRIPTEN__
7445static void
7446popen_redirect(struct popen_arg *p)
7447{
7448 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7449 close(p->write_pair[1]);
7450 if (p->write_pair[0] != 0) {
7451 dup2(p->write_pair[0], 0);
7452 close(p->write_pair[0]);
7453 }
7454 close(p->pair[0]);
7455 if (p->pair[1] != 1) {
7456 dup2(p->pair[1], 1);
7457 close(p->pair[1]);
7458 }
7459 }
7460 else if (p->modef & FMODE_READABLE) {
7461 close(p->pair[0]);
7462 if (p->pair[1] != 1) {
7463 dup2(p->pair[1], 1);
7464 close(p->pair[1]);
7465 }
7466 }
7467 else {
7468 close(p->pair[1]);
7469 if (p->pair[0] != 0) {
7470 dup2(p->pair[0], 0);
7471 close(p->pair[0]);
7472 }
7473 }
7474}
7475# endif
7476
7477#if defined(__linux__)
7478/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7479 * Since /proc may not be available, linux_get_maxfd is just a hint.
7480 * This function, linux_get_maxfd, must be async-signal-safe.
7481 * I.e. opendir() is not usable.
7482 *
7483 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7484 * However they are easy to re-implement in async-signal-safe manner.
7485 * (Also note that there is missing/memcmp.c.)
7486 */
7487static int
7488linux_get_maxfd(void)
7489{
7490 int fd;
7491 char buf[4096], *p, *np, *e;
7492 ssize_t ss;
7493 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7494 if (fd < 0) return fd;
7495 ss = read(fd, buf, sizeof(buf));
7496 if (ss < 0) goto err;
7497 p = buf;
7498 e = buf + ss;
7499 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7500 (np = memchr(p, '\n', e-p)) != NULL) {
7501 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7502 int fdsize;
7503 p += sizeof("FDSize:")-1;
7504 *np = '\0';
7505 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7506 close(fd);
7507 return fdsize;
7508 }
7509 p = np+1;
7510 }
7511 /* fall through */
7512
7513 err:
7514 close(fd);
7515 return (int)ss;
7516}
7517#endif
7518
7519/* This function should be async-signal-safe. */
7520void
7521rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7522{
7523#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7524 int fd, ret;
7525 int max = (int)max_file_descriptor;
7526# ifdef F_MAXFD
7527 /* F_MAXFD is available since NetBSD 2.0. */
7528 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7529 if (ret != -1)
7530 maxhint = max = ret;
7531# elif defined(__linux__)
7532 ret = linux_get_maxfd();
7533 if (maxhint < ret)
7534 maxhint = ret;
7535 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7536# endif
7537 if (max < maxhint)
7538 max = maxhint;
7539 for (fd = lowfd; fd <= max; fd++) {
7540 if (!NIL_P(noclose_fds) &&
7541 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7542 continue;
7543 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7544 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7545 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7546 }
7547# define CONTIGUOUS_CLOSED_FDS 20
7548 if (ret != -1) {
7549 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7550 max = fd + CONTIGUOUS_CLOSED_FDS;
7551 }
7552 }
7553#endif
7554}
7555
7556# ifndef __EMSCRIPTEN__
7557static int
7558popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7559{
7560 struct popen_arg *p = (struct popen_arg*)pp;
7561
7562 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7563}
7564# endif
7565#endif
7566
7567#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7568static VALUE
7569rb_execarg_fixup_v(VALUE execarg_obj)
7570{
7571 rb_execarg_parent_start(execarg_obj);
7572 return Qnil;
7573}
7574#else
7575char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7576#endif
7577
7578#ifndef __EMSCRIPTEN__
7579static VALUE
7580pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7581 const struct rb_io_encoding *convconfig)
7582{
7583 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7584 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7585 rb_pid_t pid = 0;
7586 rb_io_t *fptr;
7587 VALUE port;
7588 rb_io_t *write_fptr;
7589 VALUE write_port;
7590#if defined(HAVE_WORKING_FORK)
7591 int status;
7592 char errmsg[80] = { '\0' };
7593#endif
7594#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7595 int state;
7596 struct popen_arg arg;
7597#endif
7598 int e = 0;
7599#if defined(HAVE_SPAWNV)
7600# if defined(HAVE_SPAWNVE)
7601# define DO_SPAWN(cmd, args, envp) ((args) ? \
7602 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7603 spawne(P_NOWAIT, (cmd), (envp)))
7604# else
7605# define DO_SPAWN(cmd, args, envp) ((args) ? \
7606 spawnv(P_NOWAIT, (cmd), (args)) : \
7607 spawn(P_NOWAIT, (cmd)))
7608# endif
7609# if !defined(HAVE_WORKING_FORK)
7610 char **args = NULL;
7611# if defined(HAVE_SPAWNVE)
7612 char **envp = NULL;
7613# endif
7614# endif
7615#endif
7616#if !defined(HAVE_WORKING_FORK)
7617 struct rb_execarg sarg, *sargp = &sarg;
7618#endif
7619 FILE *fp = 0;
7620 int fd = -1;
7621 int write_fd = -1;
7622#if !defined(HAVE_WORKING_FORK)
7623 const char *cmd = 0;
7624
7625 if (prog)
7626 cmd = StringValueCStr(prog);
7627#endif
7628
7629#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7630 arg.execarg_obj = execarg_obj;
7631 arg.eargp = eargp;
7632 arg.modef = fmode;
7633 arg.pair[0] = arg.pair[1] = -1;
7634 arg.write_pair[0] = arg.write_pair[1] = -1;
7635# if !defined(HAVE_WORKING_FORK)
7636 if (eargp && !eargp->use_shell) {
7637 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7638 }
7639# endif
7640 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7642 if (rb_pipe(arg.write_pair) < 0)
7643 rb_sys_fail_str(prog);
7644 if (rb_pipe(arg.pair) < 0) {
7645 e = errno;
7646 close(arg.write_pair[0]);
7647 close(arg.write_pair[1]);
7648 rb_syserr_fail_str(e, prog);
7649 }
7650 if (eargp) {
7651 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7652 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7653 }
7654 break;
7655 case FMODE_READABLE:
7656 if (rb_pipe(arg.pair) < 0)
7657 rb_sys_fail_str(prog);
7658 if (eargp)
7659 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7660 break;
7661 case FMODE_WRITABLE:
7662 if (rb_pipe(arg.pair) < 0)
7663 rb_sys_fail_str(prog);
7664 if (eargp)
7665 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7666 break;
7667 default:
7668 rb_sys_fail_str(prog);
7669 }
7670 if (!NIL_P(execarg_obj)) {
7671 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7672 if (state) {
7673 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7674 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7675 if (0 <= arg.pair[0]) close(arg.pair[0]);
7676 if (0 <= arg.pair[1]) close(arg.pair[1]);
7677 rb_execarg_parent_end(execarg_obj);
7678 rb_jump_tag(state);
7679 }
7680
7681# if defined(HAVE_WORKING_FORK)
7682 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7683# else
7684 rb_execarg_run_options(eargp, sargp, NULL, 0);
7685# if defined(HAVE_SPAWNVE)
7686 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7687# endif
7688 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7689 /* exec failed */
7690 switch (e = errno) {
7691 case EAGAIN:
7692# if EWOULDBLOCK != EAGAIN
7693 case EWOULDBLOCK:
7694# endif
7695 rb_thread_sleep(1);
7696 continue;
7697 }
7698 break;
7699 }
7700 if (eargp)
7701 rb_execarg_run_options(sargp, NULL, NULL, 0);
7702# endif
7703 rb_execarg_parent_end(execarg_obj);
7704 }
7705 else {
7706# if defined(HAVE_WORKING_FORK)
7707 pid = rb_call_proc__fork();
7708 if (pid == 0) { /* child */
7709 popen_redirect(&arg);
7710 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7711 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7712 return Qnil;
7713 }
7714# else
7716# endif
7717 }
7718
7719 /* parent */
7720 if (pid < 0) {
7721# if defined(HAVE_WORKING_FORK)
7722 e = errno;
7723# endif
7724 close(arg.pair[0]);
7725 close(arg.pair[1]);
7727 close(arg.write_pair[0]);
7728 close(arg.write_pair[1]);
7729 }
7730# if defined(HAVE_WORKING_FORK)
7731 if (errmsg[0])
7732 rb_syserr_fail(e, errmsg);
7733# endif
7734 rb_syserr_fail_str(e, prog);
7735 }
7736 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7737 close(arg.pair[1]);
7738 fd = arg.pair[0];
7739 close(arg.write_pair[0]);
7740 write_fd = arg.write_pair[1];
7741 }
7742 else if (fmode & FMODE_READABLE) {
7743 close(arg.pair[1]);
7744 fd = arg.pair[0];
7745 }
7746 else {
7747 close(arg.pair[0]);
7748 fd = arg.pair[1];
7749 }
7750#else
7751 cmd = rb_execarg_commandline(eargp, &prog);
7752 if (!NIL_P(execarg_obj)) {
7753 rb_execarg_parent_start(execarg_obj);
7754 rb_execarg_run_options(eargp, sargp, NULL, 0);
7755 }
7756 fp = popen(cmd, modestr);
7757 e = errno;
7758 if (eargp) {
7759 rb_execarg_parent_end(execarg_obj);
7760 rb_execarg_run_options(sargp, NULL, NULL, 0);
7761 }
7762 if (!fp) rb_syserr_fail_path(e, prog);
7763 fd = fileno(fp);
7764#endif
7765
7766 port = io_alloc(rb_cIO);
7767 MakeOpenFile(port, fptr);
7768 fptr->fd = fd;
7769 fptr->stdio_file = fp;
7770 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7771 if (convconfig) {
7772 fptr->encs = *convconfig;
7773#if RUBY_CRLF_ENVIRONMENT
7776 }
7777#endif
7778 }
7779 else {
7780 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7782 }
7783#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7784 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7785 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7786 }
7787#endif
7788 }
7789 fptr->pid = pid;
7790
7791 if (0 <= write_fd) {
7792 write_port = io_alloc(rb_cIO);
7793 MakeOpenFile(write_port, write_fptr);
7794 write_fptr->fd = write_fd;
7795 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7796 fptr->mode &= ~FMODE_WRITABLE;
7797 fptr->tied_io_for_writing = write_port;
7798 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7799 }
7800
7801#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7802 fptr->finalize = pipe_finalize;
7803 pipe_add_fptr(fptr);
7804#endif
7805 return port;
7806}
7807#else
7808static VALUE
7809pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7810 const struct rb_io_encoding *convconfig)
7811{
7812 rb_raise(rb_eNotImpError, "popen() is not available");
7813}
7814#endif
7815
7816static int
7817is_popen_fork(VALUE prog)
7818{
7819 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7820#if !defined(HAVE_WORKING_FORK)
7821 rb_raise(rb_eNotImpError,
7822 "fork() function is unimplemented on this machine");
7823#else
7824 return TRUE;
7825#endif
7826 }
7827 return FALSE;
7828}
7829
7830static VALUE
7831pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7832 const struct rb_io_encoding *convconfig)
7833{
7834 int argc = 1;
7835 VALUE *argv = &prog;
7836 VALUE execarg_obj = Qnil;
7837
7838 if (!is_popen_fork(prog))
7839 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7840 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7841}
7842
7843static VALUE
7844pipe_close(VALUE io)
7845{
7846 rb_io_t *fptr = io_close_fptr(io);
7847 if (fptr) {
7848 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7849 }
7850 return Qnil;
7851}
7852
7853static VALUE popen_finish(VALUE port, VALUE klass);
7854
7855/*
7856 * call-seq:
7857 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7858 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7859 *
7860 * Executes the given command +cmd+ as a subprocess
7861 * whose $stdin and $stdout are connected to a new stream +io+.
7862 *
7863 * This method has potential security vulnerabilities if called with untrusted input;
7864 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
7865 *
7866 * If no block is given, returns the new stream,
7867 * which depending on given +mode+ may be open for reading, writing, or both.
7868 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7869 *
7870 * If a block is given, the stream is passed to the block
7871 * (again, open for reading, writing, or both);
7872 * when the block exits, the stream is closed,
7873 * the block's value is returned,
7874 * and the global variable <tt>$?</tt> is set to the child's exit status.
7875 *
7876 * Optional argument +mode+ may be any valid \IO mode.
7877 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7878 *
7879 * Required argument +cmd+ determines which of the following occurs:
7880 *
7881 * - The process forks.
7882 * - A specified program runs in a shell.
7883 * - A specified program runs with specified arguments.
7884 * - A specified program runs with specified arguments and a specified +argv0+.
7885 *
7886 * Each of these is detailed below.
7887 *
7888 * The optional hash argument +env+ specifies name/value pairs that are to be added
7889 * to the environment variables for the subprocess:
7890 *
7891 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7892 * pipe.puts 'puts ENV["FOO"]'
7893 * pipe.close_write
7894 * pipe.gets
7895 * end => "bar\n"
7896 *
7897 * Optional keyword arguments +opts+ specify:
7898 *
7899 * - {Open options}[rdoc-ref:IO@Open+Options].
7900 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7901 * - Options for Kernel#spawn.
7902 *
7903 * <b>Forked Process</b>
7904 *
7905 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7906 * IO.popen('-') do |pipe|
7907 * if pipe
7908 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7909 * else
7910 * $stderr.puts "In child, pid is #{$$}\n"
7911 * end
7912 * end
7913 *
7914 * Output:
7915 *
7916 * In parent, child pid is 26253
7917 * In child, pid is 26253
7918 *
7919 * Note that this is not supported on all platforms.
7920 *
7921 * <b>Shell Subprocess</b>
7922 *
7923 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7924 * the program named +cmd+ is run as a shell command:
7925 *
7926 * IO.popen('uname') do |pipe|
7927 * pipe.readlines
7928 * end
7929 *
7930 * Output:
7931 *
7932 * ["Linux\n"]
7933 *
7934 * Another example:
7935 *
7936 * IO.popen('/bin/sh', 'r+') do |pipe|
7937 * pipe.puts('ls')
7938 * pipe.close_write
7939 * $stderr.puts pipe.readlines.size
7940 * end
7941 *
7942 * Output:
7943 *
7944 * 213
7945 *
7946 * <b>Program Subprocess</b>
7947 *
7948 * When argument +cmd+ is an array of strings,
7949 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7950 *
7951 * IO.popen(['du', '..', '.']) do |pipe|
7952 * $stderr.puts pipe.readlines.size
7953 * end
7954 *
7955 * Output:
7956 *
7957 * 1111
7958 *
7959 * <b>Program Subprocess with <tt>argv0</tt></b>
7960 *
7961 * When argument +cmd+ is an array whose first element is a 2-element string array
7962 * and whose remaining elements (if any) are strings:
7963 *
7964 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7965 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7966 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7967 *
7968 * Example (sets <tt>$0</tt> to 'foo'):
7969 *
7970 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7971 *
7972 * <b>Some Special Examples</b>
7973 *
7974 * # Set IO encoding.
7975 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7976 * euc_jp_string = nkf_io.read
7977 * }
7978 *
7979 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7980 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7981 * ls_result_with_error = io.read
7982 * end
7983 *
7984 * # Use mixture of spawn options and IO options.
7985 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7986 * ls_result_with_error = io.read
7987 * end
7988 *
7989 * f = IO.popen("uname")
7990 * p f.readlines
7991 * f.close
7992 * puts "Parent is #{Process.pid}"
7993 * IO.popen("date") {|f| puts f.gets }
7994 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7995 * p $?
7996 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7997 * f.puts "bar"; f.close_write; puts f.gets
7998 * }
7999 *
8000 * Output (from last section):
8001 *
8002 * ["Linux\n"]
8003 * Parent is 21346
8004 * Thu Jan 15 22:41:19 JST 2009
8005 * 21346 is here, f is #<IO:fd 3>
8006 * 21352 is here, f is nil
8007 * #<Process::Status: pid 21352 exit 0>
8008 * <foo>bar;zot;
8009 *
8010 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8011 *
8012 */
8013
8014static VALUE
8015rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8016{
8017 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8018
8019 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8020 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8021 switch (argc) {
8022 case 2:
8023 pmode = argv[1];
8024 case 1:
8025 pname = argv[0];
8026 break;
8027 default:
8028 {
8029 int ex = !NIL_P(opt);
8030 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8031 }
8032 }
8033 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8034}
8035
8036VALUE
8037rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8038{
8039 const char *modestr;
8040 VALUE tmp, execarg_obj = Qnil;
8041 int oflags;
8042 enum rb_io_mode fmode;
8043 struct rb_io_encoding convconfig;
8044
8045 tmp = rb_check_array_type(pname);
8046 if (!NIL_P(tmp)) {
8047 long len = RARRAY_LEN(tmp);
8048#if SIZEOF_LONG > SIZEOF_INT
8049 if (len > INT_MAX) {
8050 rb_raise(rb_eArgError, "too many arguments");
8051 }
8052#endif
8053 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8054 RB_GC_GUARD(tmp);
8055 }
8056 else {
8057 StringValue(pname);
8058 execarg_obj = Qnil;
8059 if (!is_popen_fork(pname))
8060 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8061 }
8062 if (!NIL_P(execarg_obj)) {
8063 if (!NIL_P(opt))
8064 opt = rb_execarg_extract_options(execarg_obj, opt);
8065 if (!NIL_P(env))
8066 rb_execarg_setenv(execarg_obj, env);
8067 }
8068 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8069 modestr = rb_io_oflags_modestr(oflags);
8070
8071 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8072}
8073
8074static VALUE
8075popen_finish(VALUE port, VALUE klass)
8076{
8077 if (NIL_P(port)) {
8078 /* child */
8079 if (rb_block_given_p()) {
8080 rb_protect(rb_yield, Qnil, NULL);
8081 rb_io_flush(rb_ractor_stdout());
8082 rb_io_flush(rb_ractor_stderr());
8083 _exit(EXIT_SUCCESS);
8084 }
8085 return Qnil;
8086 }
8087 RBASIC_SET_CLASS(port, klass);
8088 if (rb_block_given_p()) {
8089 return rb_ensure(rb_yield, port, pipe_close, port);
8090 }
8091 return port;
8092}
8093
8094#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8095struct popen_writer_arg {
8096 char *const *argv;
8097 struct popen_arg popen;
8098};
8099
8100static int
8101exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8102{
8103 struct popen_writer_arg *pw = arg;
8104 pw->popen.modef = FMODE_WRITABLE;
8105 popen_redirect(&pw->popen);
8106 execv(pw->argv[0], pw->argv);
8107 strlcpy(errmsg, strerror(errno), buflen);
8108 return -1;
8109}
8110#endif
8111
8112FILE *
8113ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8114{
8115#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8116# ifdef HAVE_WORKING_FORK
8117 struct popen_writer_arg pw;
8118 int *const write_pair = pw.popen.pair;
8119# else
8120 int write_pair[2];
8121# endif
8122
8123#ifdef HAVE_PIPE2
8124 int result = pipe2(write_pair, O_CLOEXEC);
8125#else
8126 int result = pipe(write_pair);
8127#endif
8128
8129 *pid = -1;
8130 if (result == 0) {
8131# ifdef HAVE_WORKING_FORK
8132 pw.argv = argv;
8133 int status;
8134 char errmsg[80] = {'\0'};
8135 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8136# else
8137 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8138 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8139# endif
8140 close(write_pair[0]);
8141 if (*pid < 0) {
8142 close(write_pair[1]);
8143 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8144 }
8145 else {
8146 return fdopen(write_pair[1], "w");
8147 }
8148 }
8149#endif
8150 return NULL;
8151}
8152
8153static VALUE
8154rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8155{
8156 int oflags;
8157 enum rb_io_mode fmode;
8158 struct rb_io_encoding convconfig;
8159 mode_t perm;
8160
8161 FilePathValue(fname);
8162
8163 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8164 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8165
8166 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8167
8168 return io;
8169}
8170
8171/*
8172 * Document-method: File::open
8173 *
8174 * call-seq:
8175 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8176 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8177 *
8178 * Creates a new File object, via File.new with the given arguments.
8179 *
8180 * With no block given, returns the File object.
8181 *
8182 * With a block given, calls the block with the File object
8183 * and returns the block's value.
8184 *
8185 */
8186
8187/*
8188 * Document-method: IO::open
8189 *
8190 * call-seq:
8191 * IO.open(fd, mode = 'r', **opts) -> io
8192 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8193 *
8194 * Creates a new \IO object, via IO.new with the given arguments.
8195 *
8196 * With no block given, returns the \IO object.
8197 *
8198 * With a block given, calls the block with the \IO object
8199 * and returns the block's value.
8200 *
8201 */
8202
8203static VALUE
8204rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8205{
8207
8208 if (rb_block_given_p()) {
8209 return rb_ensure(rb_yield, io, io_close, io);
8210 }
8211
8212 return io;
8213}
8214
8215/*
8216 * call-seq:
8217 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8218 *
8219 * Opens the file at the given path with the given mode and permissions;
8220 * returns the integer file descriptor.
8221 *
8222 * If the file is to be readable, it must exist;
8223 * if the file is to be writable and does not exist,
8224 * it is created with the given permissions:
8225 *
8226 * File.write('t.tmp', '') # => 0
8227 * IO.sysopen('t.tmp') # => 8
8228 * IO.sysopen('t.tmp', 'w') # => 9
8229 *
8230 *
8231 */
8232
8233static VALUE
8234rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8235{
8236 VALUE fname, vmode, vperm;
8237 VALUE intmode;
8238 int oflags, fd;
8239 mode_t perm;
8240
8241 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8242 FilePathValue(fname);
8243
8244 if (NIL_P(vmode))
8245 oflags = O_RDONLY;
8246 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8247 oflags = NUM2INT(intmode);
8248 else {
8249 StringValue(vmode);
8250 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8251 }
8252 if (NIL_P(vperm)) perm = 0666;
8253 else perm = NUM2MODET(vperm);
8254
8255 RB_GC_GUARD(fname) = rb_str_new4(fname);
8256 fd = rb_sysopen(fname, oflags, perm);
8257 return INT2NUM(fd);
8258}
8259
8260/*
8261 * call-seq:
8262 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8263 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8264 *
8265 * Creates an IO object connected to the given file.
8266 *
8267 * With no block given, file stream is returned:
8268 *
8269 * open('t.txt') # => #<File:t.txt>
8270 *
8271 * With a block given, calls the block with the open file stream,
8272 * then closes the stream:
8273 *
8274 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8275 *
8276 * Output:
8277 *
8278 * #<File:t.txt>
8279 *
8280 * See File.open for details.
8281 *
8282 */
8283
8284static VALUE
8285rb_f_open(int argc, VALUE *argv, VALUE _)
8286{
8287 ID to_open = 0;
8288 int redirect = FALSE;
8289
8290 if (argc >= 1) {
8291 CONST_ID(to_open, "to_open");
8292 if (rb_respond_to(argv[0], to_open)) {
8293 redirect = TRUE;
8294 }
8295 else {
8296 VALUE tmp = argv[0];
8297 FilePathValue(tmp);
8298 if (NIL_P(tmp)) {
8299 redirect = TRUE;
8300 }
8301 else {
8302 argv[0] = tmp;
8303 }
8304 }
8305 }
8306 if (redirect) {
8307 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8308
8309 if (rb_block_given_p()) {
8310 return rb_ensure(rb_yield, io, io_close, io);
8311 }
8312 return io;
8313 }
8314 return rb_io_s_open(argc, argv, rb_cFile);
8315}
8316
8317static VALUE
8318rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8319 const struct rb_io_encoding *convconfig, mode_t perm)
8320{
8321 return rb_file_open_generic(io_alloc(klass), filename,
8322 oflags, fmode, convconfig, perm);
8323}
8324
8325static VALUE
8326rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8327{
8328 int oflags;
8329 enum rb_io_mode fmode;
8330 struct rb_io_encoding convconfig;
8331 mode_t perm;
8332
8333 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8334 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8335 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8336}
8337
8338static VALUE
8339io_reopen(VALUE io, VALUE nfile)
8340{
8341 rb_io_t *fptr, *orig;
8342 int fd, fd2;
8343 rb_off_t pos = 0;
8344
8345 nfile = rb_io_get_io(nfile);
8346 GetOpenFile(io, fptr);
8347 GetOpenFile(nfile, orig);
8348
8349 if (fptr == orig) return io;
8350 if (RUBY_IO_EXTERNAL_P(fptr)) {
8351 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8352 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8353 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8354 rb_raise(rb_eArgError,
8355 "%s can't change access mode from \"%s\" to \"%s\"",
8356 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8357 rb_io_fmode_modestr(orig->mode));
8358 }
8359 }
8360 if (fptr->mode & FMODE_WRITABLE) {
8361 if (io_fflush(fptr) < 0)
8362 rb_sys_fail_on_write(fptr);
8363 }
8364 else {
8365 flush_before_seek(fptr, true);
8366 }
8367 if (orig->mode & FMODE_READABLE) {
8368 pos = io_tell(orig);
8369 }
8370 if (orig->mode & FMODE_WRITABLE) {
8371 if (io_fflush(orig) < 0)
8372 rb_sys_fail_on_write(fptr);
8373 }
8374
8375 /* copy rb_io_t structure */
8376 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8377 fptr->encs = orig->encs;
8378 fptr->pid = orig->pid;
8379 fptr->lineno = orig->lineno;
8380 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8381 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8382 fptr_copy_finalizer(fptr, orig);
8383
8384 fd = fptr->fd;
8385 fd2 = orig->fd;
8386 if (fd != fd2) {
8387 // Interrupt all usage of the old file descriptor:
8388 rb_thread_io_close_interrupt(fptr);
8389 rb_thread_io_close_wait(fptr);
8390
8391 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8392 /* need to keep FILE objects of stdin, stdout and stderr */
8393 if (rb_cloexec_dup2(fd2, fd) < 0)
8394 rb_sys_fail_path(orig->pathv);
8395 rb_update_max_fd(fd);
8396 }
8397 else {
8398 fclose(fptr->stdio_file);
8399 fptr->stdio_file = 0;
8400 fptr->fd = -1;
8401 if (rb_cloexec_dup2(fd2, fd) < 0)
8402 rb_sys_fail_path(orig->pathv);
8403 rb_update_max_fd(fd);
8404 fptr->fd = fd;
8405 }
8406
8407 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8408 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8409 rb_sys_fail_path(fptr->pathv);
8410 }
8411 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8412 rb_sys_fail_path(orig->pathv);
8413 }
8414 }
8415 }
8416
8417 if (fptr->mode & FMODE_BINMODE) {
8418 rb_io_binmode(io);
8419 }
8420
8421 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8422 return io;
8423}
8424
8425#ifdef _WIN32
8426int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8427#else
8428static int
8429rb_freopen(VALUE fname, const char *mode, FILE *fp)
8430{
8431 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8432 RB_GC_GUARD(fname);
8433 return errno;
8434 }
8435 return 0;
8436}
8437#endif
8438
8439/*
8440 * call-seq:
8441 * reopen(other_io) -> self
8442 * reopen(path, mode = 'r', **opts) -> self
8443 *
8444 * Reassociates the stream with another stream,
8445 * which may be of a different class.
8446 * This method may be used to redirect an existing stream
8447 * to a new destination.
8448 *
8449 * With argument +other_io+ given, reassociates with that stream:
8450 *
8451 * # Redirect $stdin from a file.
8452 * f = File.open('t.txt')
8453 * $stdin.reopen(f)
8454 * f.close
8455 *
8456 * # Redirect $stdout to a file.
8457 * f = File.open('t.tmp', 'w')
8458 * $stdout.reopen(f)
8459 * f.close
8460 *
8461 * With argument +path+ given, reassociates with a new stream to that file path:
8462 *
8463 * $stdin.reopen('t.txt')
8464 * $stdout.reopen('t.tmp', 'w')
8465 *
8466 * Optional keyword arguments +opts+ specify:
8467 *
8468 * - {Open Options}[rdoc-ref:IO@Open+Options].
8469 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8470 *
8471 */
8472
8473static VALUE
8474rb_io_reopen(int argc, VALUE *argv, VALUE file)
8475{
8476 VALUE fname, nmode, opt;
8477 int oflags;
8478 rb_io_t *fptr;
8479
8480 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8481 VALUE tmp = rb_io_check_io(fname);
8482 if (!NIL_P(tmp)) {
8483 return io_reopen(file, tmp);
8484 }
8485 }
8486
8487 FilePathValue(fname);
8488 rb_io_taint_check(file);
8489 fptr = RFILE(file)->fptr;
8490 if (!fptr) {
8491 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8492 }
8493
8494 if (!NIL_P(nmode) || !NIL_P(opt)) {
8495 enum rb_io_mode fmode;
8496 struct rb_io_encoding convconfig;
8497
8498 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8499 if (RUBY_IO_EXTERNAL_P(fptr) &&
8500 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8501 (fptr->mode & FMODE_READWRITE)) {
8502 rb_raise(rb_eArgError,
8503 "%s can't change access mode from \"%s\" to \"%s\"",
8504 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8505 rb_io_fmode_modestr(fmode));
8506 }
8507 fptr->mode = fmode;
8508 fptr->encs = convconfig;
8509 }
8510 else {
8511 oflags = rb_io_fmode_oflags(fptr->mode);
8512 }
8513
8514 fptr->pathv = fname;
8515 if (fptr->fd < 0) {
8516 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8517 fptr->stdio_file = 0;
8518 return file;
8519 }
8520
8521 if (fptr->mode & FMODE_WRITABLE) {
8522 if (io_fflush(fptr) < 0)
8523 rb_sys_fail_on_write(fptr);
8524 }
8525 fptr->rbuf.off = fptr->rbuf.len = 0;
8526
8527 if (fptr->stdio_file) {
8528 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8529 rb_io_oflags_modestr(oflags),
8530 fptr->stdio_file);
8531 if (e) rb_syserr_fail_path(e, fptr->pathv);
8532 fptr->fd = fileno(fptr->stdio_file);
8533 rb_fd_fix_cloexec(fptr->fd);
8534#ifdef USE_SETVBUF
8535 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8536 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8537#endif
8538 if (fptr->stdio_file == stderr) {
8539 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8540 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8541 }
8542 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8543 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8544 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8545 }
8546 }
8547 else {
8548 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8549 int err = 0;
8550 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8551 err = errno;
8552 (void)close(tmpfd);
8553 if (err) {
8554 rb_syserr_fail_path(err, fptr->pathv);
8555 }
8556 }
8557
8558 return file;
8559}
8560
8561/* :nodoc: */
8562static VALUE
8563rb_io_init_copy(VALUE dest, VALUE io)
8564{
8565 rb_io_t *fptr, *orig;
8566 int fd;
8567 VALUE write_io;
8568 rb_off_t pos;
8569
8570 io = rb_io_get_io(io);
8571 if (!OBJ_INIT_COPY(dest, io)) return dest;
8572 GetOpenFile(io, orig);
8573 MakeOpenFile(dest, fptr);
8574
8575 rb_io_flush(io);
8576
8577 /* copy rb_io_t structure */
8578 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8579 fptr->encs = orig->encs;
8580 fptr->pid = orig->pid;
8581 fptr->lineno = orig->lineno;
8582 fptr->timeout = orig->timeout;
8583
8584 ccan_list_head_init(&fptr->blocking_operations);
8585 fptr->closing_ec = NULL;
8586 fptr->wakeup_mutex = Qnil;
8587 fptr->fork_generation = GET_VM()->fork_gen;
8588
8589 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8590 fptr_copy_finalizer(fptr, orig);
8591
8592 fd = ruby_dup(orig->fd);
8593 fptr->fd = fd;
8594 pos = io_tell(orig);
8595 if (0 <= pos)
8596 io_seek(fptr, pos, SEEK_SET);
8597 if (fptr->mode & FMODE_BINMODE) {
8598 rb_io_binmode(dest);
8599 }
8600
8601 write_io = GetWriteIO(io);
8602 if (io != write_io) {
8603 write_io = rb_obj_dup(write_io);
8604 fptr->tied_io_for_writing = write_io;
8605 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8606 }
8607
8608 return dest;
8609}
8610
8611/*
8612 * call-seq:
8613 * printf(format_string, *objects) -> nil
8614 *
8615 * Formats and writes +objects+ to the stream.
8616 *
8617 * For details on +format_string+, see
8618 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8619 *
8620 */
8621
8622VALUE
8623rb_io_printf(int argc, const VALUE *argv, VALUE out)
8624{
8625 rb_io_write(out, rb_f_sprintf(argc, argv));
8626 return Qnil;
8627}
8628
8629/*
8630 * call-seq:
8631 * printf(format_string, *objects) -> nil
8632 * printf(io, format_string, *objects) -> nil
8633 *
8634 * Equivalent to:
8635 *
8636 * io.write(sprintf(format_string, *objects))
8637 *
8638 * For details on +format_string+, see
8639 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8640 *
8641 * With the single argument +format_string+, formats +objects+ into the string,
8642 * then writes the formatted string to $stdout:
8643 *
8644 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8645 *
8646 * Output (on $stdout):
8647 *
8648 * 0024 24 24.00#
8649 *
8650 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8651 * then writes the formatted string to +io+:
8652 *
8653 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8654 *
8655 * Output (on $stderr):
8656 *
8657 * 0024 24 24.00# => nil
8658 *
8659 * With no arguments, does nothing.
8660 *
8661 */
8662
8663static VALUE
8664rb_f_printf(int argc, VALUE *argv, VALUE _)
8665{
8666 VALUE out;
8667
8668 if (argc == 0) return Qnil;
8669 if (RB_TYPE_P(argv[0], T_STRING)) {
8670 out = rb_ractor_stdout();
8671 }
8672 else {
8673 out = argv[0];
8674 argv++;
8675 argc--;
8676 }
8677 rb_io_write(out, rb_f_sprintf(argc, argv));
8678
8679 return Qnil;
8680}
8681
8682extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8683
8684static void
8685deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8686{
8687 rb_deprecated_str_setter(val, id, &val);
8688 if (!NIL_P(val)) {
8689 if (rb_str_equal(val, rb_default_rs)) {
8690 val = rb_default_rs;
8691 }
8692 else {
8693 val = rb_str_frozen_bare_string(val);
8694 }
8695 }
8696 *var = val;
8697}
8698
8699/*
8700 * call-seq:
8701 * print(*objects) -> nil
8702 *
8703 * Writes the given objects to the stream; returns +nil+.
8704 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8705 * (<tt>$\</tt>), if it is not +nil+.
8706 * See {Line IO}[rdoc-ref:IO@Line+IO].
8707 *
8708 * With argument +objects+ given, for each object:
8709 *
8710 * - Converts via its method +to_s+ if not a string.
8711 * - Writes to the stream.
8712 * - If not the last object, writes the output field separator
8713 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8714 *
8715 * With default separators:
8716 *
8717 * f = File.open('t.tmp', 'w+')
8718 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8719 * p $OUTPUT_RECORD_SEPARATOR
8720 * p $OUTPUT_FIELD_SEPARATOR
8721 * f.print(*objects)
8722 * f.rewind
8723 * p f.read
8724 * f.close
8725 *
8726 * Output:
8727 *
8728 * nil
8729 * nil
8730 * "00.00/10+0izerozero"
8731 *
8732 * With specified separators:
8733 *
8734 * $\ = "\n"
8735 * $, = ','
8736 * f.rewind
8737 * f.print(*objects)
8738 * f.rewind
8739 * p f.read
8740 *
8741 * Output:
8742 *
8743 * "0,0.0,0/1,0+0i,zero,zero\n"
8744 *
8745 * With no argument given, writes the content of <tt>$_</tt>
8746 * (which is usually the most recent user input):
8747 *
8748 * f = File.open('t.tmp', 'w+')
8749 * gets # Sets $_ to the most recent user input.
8750 * f.print
8751 * f.close
8752 *
8753 */
8754
8755VALUE
8756rb_io_print(int argc, const VALUE *argv, VALUE out)
8757{
8758 int i;
8759 VALUE line;
8760
8761 /* if no argument given, print `$_' */
8762 if (argc == 0) {
8763 argc = 1;
8764 line = rb_lastline_get();
8765 argv = &line;
8766 }
8767 if (argc > 1 && !NIL_P(rb_output_fs)) {
8768 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8769 }
8770 for (i=0; i<argc; i++) {
8771 if (!NIL_P(rb_output_fs) && i>0) {
8772 rb_io_write(out, rb_output_fs);
8773 }
8774 rb_io_write(out, argv[i]);
8775 }
8776 if (argc > 0 && !NIL_P(rb_output_rs)) {
8777 rb_io_write(out, rb_output_rs);
8778 }
8779
8780 return Qnil;
8781}
8782
8783/*
8784 * call-seq:
8785 * print(*objects) -> nil
8786 *
8787 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8788 * this method is the straightforward way to write to <tt>$stdout</tt>.
8789 *
8790 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8791 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8792 * <tt>$\</tt>), if it is not +nil+.
8793 *
8794 * With argument +objects+ given, for each object:
8795 *
8796 * - Converts via its method +to_s+ if not a string.
8797 * - Writes to <tt>stdout</tt>.
8798 * - If not the last object, writes the output field separator
8799 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8800 *
8801 * With default separators:
8802 *
8803 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8804 * $OUTPUT_RECORD_SEPARATOR
8805 * $OUTPUT_FIELD_SEPARATOR
8806 * print(*objects)
8807 *
8808 * Output:
8809 *
8810 * nil
8811 * nil
8812 * 00.00/10+0izerozero
8813 *
8814 * With specified separators:
8815 *
8816 * $OUTPUT_RECORD_SEPARATOR = "\n"
8817 * $OUTPUT_FIELD_SEPARATOR = ','
8818 * print(*objects)
8819 *
8820 * Output:
8821 *
8822 * 0,0.0,0/1,0+0i,zero,zero
8823 *
8824 * With no argument given, writes the content of <tt>$_</tt>
8825 * (which is usually the most recent user input):
8826 *
8827 * gets # Sets $_ to the most recent user input.
8828 * print # Prints $_.
8829 *
8830 */
8831
8832static VALUE
8833rb_f_print(int argc, const VALUE *argv, VALUE _)
8834{
8835 rb_io_print(argc, argv, rb_ractor_stdout());
8836 return Qnil;
8837}
8838
8839/*
8840 * call-seq:
8841 * putc(object) -> object
8842 *
8843 * Writes a character to the stream.
8844 * See {Character IO}[rdoc-ref:IO@Character+IO].
8845 *
8846 * If +object+ is numeric, converts to integer if necessary,
8847 * then writes the character whose code is the
8848 * least significant byte;
8849 * if +object+ is a string, writes the first character:
8850 *
8851 * $stdout.putc "A"
8852 * $stdout.putc 65
8853 *
8854 * Output:
8855 *
8856 * AA
8857 *
8858 */
8859
8860static VALUE
8861rb_io_putc(VALUE io, VALUE ch)
8862{
8863 VALUE str;
8864 if (RB_TYPE_P(ch, T_STRING)) {
8865 str = rb_str_substr(ch, 0, 1);
8866 }
8867 else {
8868 char c = NUM2CHR(ch);
8869 str = rb_str_new(&c, 1);
8870 }
8871 rb_io_write(io, str);
8872 return ch;
8873}
8874
8875#define forward(obj, id, argc, argv) \
8876 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8877#define forward_public(obj, id, argc, argv) \
8878 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8879#define forward_current(id, argc, argv) \
8880 forward_public(ARGF.current_file, id, argc, argv)
8881
8882/*
8883 * call-seq:
8884 * putc(int) -> int
8885 *
8886 * Equivalent to:
8887 *
8888 * $stdout.putc(int)
8889 *
8890 * See IO#putc for important information regarding multi-byte characters.
8891 *
8892 */
8893
8894static VALUE
8895rb_f_putc(VALUE recv, VALUE ch)
8896{
8897 VALUE r_stdout = rb_ractor_stdout();
8898 if (recv == r_stdout) {
8899 return rb_io_putc(recv, ch);
8900 }
8901 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8902}
8903
8904
8905int
8906rb_str_end_with_asciichar(VALUE str, int c)
8907{
8908 long len = RSTRING_LEN(str);
8909 const char *ptr = RSTRING_PTR(str);
8910 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8911 int n;
8912
8913 if (len == 0) return 0;
8914 if ((n = rb_enc_mbminlen(enc)) == 1) {
8915 return ptr[len - 1] == c;
8916 }
8917 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8918}
8919
8920static VALUE
8921io_puts_ary(VALUE ary, VALUE out, int recur)
8922{
8923 VALUE tmp;
8924 long i;
8925
8926 if (recur) {
8927 tmp = rb_str_new2("[...]");
8928 rb_io_puts(1, &tmp, out);
8929 return Qtrue;
8930 }
8931 ary = rb_check_array_type(ary);
8932 if (NIL_P(ary)) return Qfalse;
8933 for (i=0; i<RARRAY_LEN(ary); i++) {
8934 tmp = RARRAY_AREF(ary, i);
8935 rb_io_puts(1, &tmp, out);
8936 }
8937 return Qtrue;
8938}
8939
8940/*
8941 * call-seq:
8942 * puts(*objects) -> nil
8943 *
8944 * Writes the given +objects+ to the stream, which must be open for writing;
8945 * returns +nil+.\
8946 * Writes a newline after each that does not already end with a newline sequence.
8947 * If called without arguments, writes a newline.
8948 * See {Line IO}[rdoc-ref:IO@Line+IO].
8949 *
8950 * Note that each added newline is the character <tt>"\n"<//tt>,
8951 * not the output record separator (<tt>$\</tt>).
8952 *
8953 * Treatment for each object:
8954 *
8955 * - String: writes the string.
8956 * - Neither string nor array: writes <tt>object.to_s</tt>.
8957 * - Array: writes each element of the array; arrays may be nested.
8958 *
8959 * To keep these examples brief, we define this helper method:
8960 *
8961 * def show(*objects)
8962 * # Puts objects to file.
8963 * f = File.new('t.tmp', 'w+')
8964 * f.puts(objects)
8965 * # Return file content.
8966 * f.rewind
8967 * p f.read
8968 * f.close
8969 * end
8970 *
8971 * # Strings without newlines.
8972 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8973 * # Strings, some with newlines.
8974 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8975 *
8976 * # Neither strings nor arrays:
8977 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8978 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8979 *
8980 * # Array of strings.
8981 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8982 * # Nested arrays.
8983 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8984 *
8985 */
8986
8987VALUE
8988rb_io_puts(int argc, const VALUE *argv, VALUE out)
8989{
8990 VALUE line, args[2];
8991
8992 /* if no argument given, print newline. */
8993 if (argc == 0) {
8994 rb_io_write(out, rb_default_rs);
8995 return Qnil;
8996 }
8997 for (int i = 0; i < argc; i++) {
8998 // Convert the argument to a string:
8999 if (RB_TYPE_P(argv[i], T_STRING)) {
9000 line = argv[i];
9001 }
9002 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9003 continue;
9004 }
9005 else {
9006 line = rb_obj_as_string(argv[i]);
9007 }
9008
9009 // Write the line:
9010 int n = 0;
9011 if (RSTRING_LEN(line) == 0) {
9012 args[n++] = rb_default_rs;
9013 }
9014 else {
9015 args[n++] = line;
9016 if (!rb_str_end_with_asciichar(line, '\n')) {
9017 args[n++] = rb_default_rs;
9018 }
9019 }
9020
9021 rb_io_writev(out, n, args);
9022 }
9023
9024 return Qnil;
9025}
9026
9027/*
9028 * call-seq:
9029 * puts(*objects) -> nil
9030 *
9031 * Equivalent to
9032 *
9033 * $stdout.puts(objects)
9034 */
9035
9036static VALUE
9037rb_f_puts(int argc, VALUE *argv, VALUE recv)
9038{
9039 VALUE r_stdout = rb_ractor_stdout();
9040 if (recv == r_stdout) {
9041 return rb_io_puts(argc, argv, recv);
9042 }
9043 return forward(r_stdout, rb_intern("puts"), argc, argv);
9044}
9045
9046static VALUE
9047rb_p_write(VALUE str)
9048{
9049 VALUE args[2];
9050 args[0] = str;
9051 args[1] = rb_default_rs;
9052 VALUE r_stdout = rb_ractor_stdout();
9053 if (RB_TYPE_P(r_stdout, T_FILE) &&
9054 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9055 io_writev(2, args, r_stdout);
9056 }
9057 else {
9058 rb_io_writev(r_stdout, 2, args);
9059 }
9060 return Qnil;
9061}
9062
9063void
9064rb_p(VALUE obj) /* for debug print within C code */
9065{
9066 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9067}
9068
9069static VALUE
9070rb_p_result(int argc, const VALUE *argv)
9071{
9072 VALUE ret = Qnil;
9073
9074 if (argc == 1) {
9075 ret = argv[0];
9076 }
9077 else if (argc > 1) {
9078 ret = rb_ary_new4(argc, argv);
9079 }
9080 VALUE r_stdout = rb_ractor_stdout();
9081 if (RB_TYPE_P(r_stdout, T_FILE)) {
9082 rb_uninterruptible(rb_io_flush, r_stdout);
9083 }
9084 return ret;
9085}
9086
9087/*
9088 * call-seq:
9089 * p(object) -> obj
9090 * p(*objects) -> array of objects
9091 * p -> nil
9092 *
9093 * For each object +obj+, executes:
9094 *
9095 * $stdout.write(obj.inspect, "\n")
9096 *
9097 * With one object given, returns the object;
9098 * with multiple objects given, returns an array containing the objects;
9099 * with no object given, returns +nil+.
9100 *
9101 * Examples:
9102 *
9103 * r = Range.new(0, 4)
9104 * p r # => 0..4
9105 * p [r, r, r] # => [0..4, 0..4, 0..4]
9106 * p # => nil
9107 *
9108 * Output:
9109 *
9110 * 0..4
9111 * [0..4, 0..4, 0..4]
9112 *
9113 * Kernel#p is designed for debugging purposes.
9114 * Ruby implementations may define Kernel#p to be uninterruptible
9115 * in whole or in part.
9116 * On CRuby, Kernel#p's writing of data is uninterruptible.
9117 */
9118
9119static VALUE
9120rb_f_p(int argc, VALUE *argv, VALUE self)
9121{
9122 int i;
9123 for (i=0; i<argc; i++) {
9124 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9125 rb_uninterruptible(rb_p_write, inspected);
9126 }
9127 return rb_p_result(argc, argv);
9128}
9129
9130/*
9131 * call-seq:
9132 * display(port = $>) -> nil
9133 *
9134 * Writes +self+ on the given port:
9135 *
9136 * 1.display
9137 * "cat".display
9138 * [ 4, 5, 6 ].display
9139 * puts
9140 *
9141 * Output:
9142 *
9143 * 1cat[4, 5, 6]
9144 *
9145 */
9146
9147static VALUE
9148rb_obj_display(int argc, VALUE *argv, VALUE self)
9149{
9150 VALUE out;
9151
9152 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9153 rb_io_write(out, self);
9154
9155 return Qnil;
9156}
9157
9158static int
9159rb_stderr_to_original_p(VALUE err)
9160{
9161 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9162}
9163
9164void
9165rb_write_error2(const char *mesg, long len)
9166{
9167 VALUE out = rb_ractor_stderr();
9168 if (rb_stderr_to_original_p(out)) {
9169#ifdef _WIN32
9170 if (isatty(fileno(stderr))) {
9171 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9172 }
9173#endif
9174 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9175 /* failed to write to stderr, what can we do? */
9176 return;
9177 }
9178 }
9179 else {
9180 rb_io_write(out, rb_str_new(mesg, len));
9181 }
9182}
9183
9184void
9185rb_write_error(const char *mesg)
9186{
9187 rb_write_error2(mesg, strlen(mesg));
9188}
9189
9190void
9191rb_write_error_str(VALUE mesg)
9192{
9193 VALUE out = rb_ractor_stderr();
9194 /* a stopgap measure for the time being */
9195 if (rb_stderr_to_original_p(out)) {
9196 size_t len = (size_t)RSTRING_LEN(mesg);
9197#ifdef _WIN32
9198 if (isatty(fileno(stderr))) {
9199 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9200 }
9201#endif
9202 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9203 RB_GC_GUARD(mesg);
9204 return;
9205 }
9206 }
9207 else {
9208 /* may unlock GVL, and */
9209 rb_io_write(out, mesg);
9210 }
9211}
9212
9213int
9214rb_stderr_tty_p(void)
9215{
9216 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9217 return isatty(fileno(stderr));
9218 return 0;
9219}
9220
9221static void
9222must_respond_to(ID mid, VALUE val, ID id)
9223{
9224 if (!rb_respond_to(val, mid)) {
9225 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9226 rb_id2str(id), rb_id2str(mid),
9227 rb_obj_class(val));
9228 }
9229}
9230
9231static void
9232stdin_setter(VALUE val, ID id, VALUE *ptr)
9233{
9235}
9236
9237static VALUE
9238stdin_getter(ID id, VALUE *ptr)
9239{
9240 return rb_ractor_stdin();
9241}
9242
9243static void
9244stdout_setter(VALUE val, ID id, VALUE *ptr)
9245{
9246 must_respond_to(id_write, val, id);
9248}
9249
9250static VALUE
9251stdout_getter(ID id, VALUE *ptr)
9252{
9253 return rb_ractor_stdout();
9254}
9255
9256static void
9257stderr_setter(VALUE val, ID id, VALUE *ptr)
9258{
9259 must_respond_to(id_write, val, id);
9261}
9262
9263static VALUE
9264stderr_getter(ID id, VALUE *ptr)
9265{
9266 return rb_ractor_stderr();
9267}
9268
9269static VALUE
9270allocate_and_open_new_file(VALUE klass)
9271{
9272 VALUE self = io_alloc(klass);
9273 rb_io_make_open_file(self);
9274 return self;
9275}
9276
9277VALUE
9278rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9279{
9280 int state;
9281 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9282 if (state) {
9283 /* if we raised an exception allocating an IO object, but the caller
9284 intended to transfer ownership of this FD to us, close the fd before
9285 raising the exception. Otherwise, we would leak a FD - the caller
9286 expects GC to close the file, but we never got around to assigning
9287 it to a rb_io. */
9288 if (!(mode & FMODE_EXTERNAL)) {
9289 maygvl_close(descriptor, 0);
9290 }
9291 rb_jump_tag(state);
9292 }
9293
9294
9295 rb_io_t *io = RFILE(self)->fptr;
9296 io->self = self;
9297 io->fd = descriptor;
9298 io->mode = mode;
9299
9300 /* At this point, Ruby fully owns the descriptor, and will close it when
9301 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9302 in the rest of this method. */
9303
9304 if (NIL_P(path)) {
9305 io->pathv = Qnil;
9306 }
9307 else {
9308 StringValue(path);
9309 io->pathv = rb_str_new_frozen(path);
9310 }
9311
9312 io->timeout = timeout;
9313
9314 ccan_list_head_init(&io->blocking_operations);
9315 io->closing_ec = NULL;
9316 io->wakeup_mutex = Qnil;
9317 io->fork_generation = GET_VM()->fork_gen;
9318
9319 if (encoding) {
9320 io->encs = *encoding;
9321 }
9322
9323 rb_update_max_fd(descriptor);
9324
9325 return self;
9326}
9327
9328static VALUE
9329prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9330{
9331 VALUE path_value = Qnil;
9332 rb_encoding *e;
9333 struct rb_io_encoding convconfig;
9334
9335 if (path) {
9336 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9337 }
9338
9339 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9340 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9341 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9344#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9345 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9346 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9347 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9348#endif
9349 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9350 convconfig.ecopts = Qnil;
9351
9352 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9353 rb_io_t*io = RFILE(self)->fptr;
9354
9355 if (!io_check_tty(io)) {
9356#ifdef __CYGWIN__
9357 io->mode |= FMODE_BINMODE;
9358 setmode(fd, O_BINARY);
9359#endif
9360 }
9361
9362 return self;
9363}
9364
9365VALUE
9366rb_io_fdopen(int fd, int oflags, const char *path)
9367{
9368 VALUE klass = rb_cIO;
9369
9370 if (path && strcmp(path, "-")) klass = rb_cFile;
9371 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9372}
9373
9374static VALUE
9375prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9376{
9377 rb_io_t *fptr;
9378 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9379
9380 GetOpenFile(io, fptr);
9382#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9383 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9384 if (fmode & FMODE_READABLE) {
9386 }
9387#endif
9388 fptr->stdio_file = f;
9389
9390 return io;
9391}
9392
9393VALUE
9394rb_io_prep_stdin(void)
9395{
9396 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9397}
9398
9399VALUE
9400rb_io_prep_stdout(void)
9401{
9402 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9403}
9404
9405VALUE
9406rb_io_prep_stderr(void)
9407{
9408 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9409}
9410
9411FILE *
9413{
9414 if (!fptr->stdio_file) {
9415 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9416 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9417 }
9418 return fptr->stdio_file;
9419}
9420
9421static inline void
9422rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9423{
9424 buf->ptr = NULL;
9425 buf->off = 0;
9426 buf->len = 0;
9427 buf->capa = 0;
9428}
9429
9430static inline rb_io_t *
9431rb_io_fptr_new(void)
9432{
9433 rb_io_t *fp = ALLOC(rb_io_t);
9434 fp->self = Qnil;
9435 fp->fd = -1;
9436 fp->stdio_file = NULL;
9437 fp->mode = 0;
9438 fp->pid = 0;
9439 fp->lineno = 0;
9440 fp->pathv = Qnil;
9441 fp->finalize = 0;
9442 rb_io_buffer_init(&fp->wbuf);
9443 rb_io_buffer_init(&fp->rbuf);
9444 rb_io_buffer_init(&fp->cbuf);
9445 fp->readconv = NULL;
9446 fp->writeconv = NULL;
9448 fp->writeconv_pre_ecflags = 0;
9450 fp->writeconv_initialized = 0;
9451 fp->tied_io_for_writing = 0;
9452 fp->encs.enc = NULL;
9453 fp->encs.enc2 = NULL;
9454 fp->encs.ecflags = 0;
9455 fp->encs.ecopts = Qnil;
9456 fp->write_lock = Qnil;
9457 fp->timeout = Qnil;
9458 ccan_list_head_init(&fp->blocking_operations);
9459 fp->closing_ec = NULL;
9460 fp->wakeup_mutex = Qnil;
9461 fp->fork_generation = GET_VM()->fork_gen;
9462 return fp;
9463}
9464
9465rb_io_t *
9466rb_io_make_open_file(VALUE obj)
9467{
9468 rb_io_t *fp = 0;
9469
9470 Check_Type(obj, T_FILE);
9471 if (RFILE(obj)->fptr) {
9472 rb_io_close(obj);
9473 rb_io_fptr_finalize(RFILE(obj)->fptr);
9474 RFILE(obj)->fptr = 0;
9475 }
9476 fp = rb_io_fptr_new();
9477 fp->self = obj;
9478 RFILE(obj)->fptr = fp;
9479 return fp;
9480}
9481
9482static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9483
9484/*
9485 * call-seq:
9486 * IO.new(fd, mode = 'r', **opts) -> io
9487 *
9488 * Creates and returns a new \IO object (file stream) from a file descriptor.
9489 *
9490 * \IO.new may be useful for interaction with low-level libraries.
9491 * For higher-level interactions, it may be simpler to create
9492 * the file stream using File.open.
9493 *
9494 * Argument +fd+ must be a valid file descriptor (integer):
9495 *
9496 * path = 't.tmp'
9497 * fd = IO.sysopen(path) # => 3
9498 * IO.new(fd) # => #<IO:fd 3>
9499 *
9500 * The new \IO object does not inherit encoding
9501 * (because the integer file descriptor does not have an encoding):
9502 *
9503 * File.read('t.ja') # => "こんにちは"
9504 * fd = IO.sysopen('t.ja', 'rb')
9505 * io = IO.new(fd)
9506 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9507 *
9508 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9509 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9510 *
9511 * IO.new(fd, 'w') # => #<IO:fd 3>
9512 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9513 *
9514 * Optional keyword arguments +opts+ specify:
9515 *
9516 * - {Open Options}[rdoc-ref:IO@Open+Options].
9517 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9518 *
9519 * Examples:
9520 *
9521 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9522 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9523 *
9524 */
9525
9526static VALUE
9527rb_io_initialize(int argc, VALUE *argv, VALUE io)
9528{
9529 VALUE fnum, vmode;
9530 VALUE opt;
9531
9532 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9533 return io_initialize(io, fnum, vmode, opt);
9534}
9535
9536static VALUE
9537io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9538{
9539 rb_io_t *fp;
9540 int fd, oflags = O_RDONLY;
9541 enum rb_io_mode fmode;
9542 struct rb_io_encoding convconfig;
9543#if defined(HAVE_FCNTL) && defined(F_GETFL)
9544 int ofmode;
9545#else
9546 struct stat st;
9547#endif
9548
9549 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9550
9551 fd = NUM2INT(fnum);
9552 if (rb_reserved_fd_p(fd)) {
9553 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9554 }
9555#if defined(HAVE_FCNTL) && defined(F_GETFL)
9556 oflags = fcntl(fd, F_GETFL);
9557 if (oflags == -1) rb_sys_fail(0);
9558#else
9559 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9560#endif
9561 rb_update_max_fd(fd);
9562#if defined(HAVE_FCNTL) && defined(F_GETFL)
9563 ofmode = rb_io_oflags_fmode(oflags);
9564 if (NIL_P(vmode)) {
9565 fmode = ofmode;
9566 }
9567 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9568 VALUE error = INT2FIX(EINVAL);
9570 }
9571#endif
9572 VALUE path = Qnil;
9573
9574 if (!NIL_P(opt)) {
9575 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9576 fmode |= FMODE_EXTERNAL;
9577 }
9578
9579 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9580 if (!NIL_P(path)) {
9581 StringValue(path);
9582 path = rb_str_new_frozen(path);
9583 }
9584 }
9585
9586 MakeOpenFile(io, fp);
9587 fp->self = io;
9588 fp->fd = fd;
9589 fp->mode = fmode;
9590 fp->encs = convconfig;
9591 fp->pathv = path;
9592 fp->timeout = Qnil;
9593 ccan_list_head_init(&fp->blocking_operations);
9594 fp->closing_ec = NULL;
9595 fp->wakeup_mutex = Qnil;
9596 fp->fork_generation = GET_VM()->fork_gen;
9597 clear_codeconv(fp);
9598 io_check_tty(fp);
9599 if (fileno(stdin) == fd)
9600 fp->stdio_file = stdin;
9601 else if (fileno(stdout) == fd)
9602 fp->stdio_file = stdout;
9603 else if (fileno(stderr) == fd)
9604 fp->stdio_file = stderr;
9605
9606 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9607 return io;
9608}
9609
9610/*
9611 * call-seq:
9612 * set_encoding_by_bom -> encoding or nil
9613 *
9614 * If the stream begins with a BOM
9615 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9616 * consumes the BOM and sets the external encoding accordingly;
9617 * returns the result encoding if found, or +nil+ otherwise:
9618 *
9619 * File.write('t.tmp', "\u{FEFF}abc")
9620 * io = File.open('t.tmp', 'rb')
9621 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9622 * io.close
9623 *
9624 * File.write('t.tmp', 'abc')
9625 * io = File.open('t.tmp', 'rb')
9626 * io.set_encoding_by_bom # => nil
9627 * io.close
9628 *
9629 * Raises an exception if the stream is not binmode
9630 * or its encoding has already been set.
9631 *
9632 */
9633
9634static VALUE
9635rb_io_set_encoding_by_bom(VALUE io)
9636{
9637 rb_io_t *fptr;
9638
9639 GetOpenFile(io, fptr);
9640 if (!(fptr->mode & FMODE_BINMODE)) {
9641 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9642 }
9643 if (fptr->encs.enc2) {
9644 rb_raise(rb_eArgError, "encoding conversion is set");
9645 }
9646 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9647 rb_raise(rb_eArgError, "encoding is set to %s already",
9648 rb_enc_name(fptr->encs.enc));
9649 }
9650 if (!io_set_encoding_by_bom(io)) return Qnil;
9651 return rb_enc_from_encoding(fptr->encs.enc);
9652}
9653
9654/*
9655 * call-seq:
9656 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9657 *
9658 * Opens the file at the given +path+ according to the given +mode+;
9659 * creates and returns a new File object for that file.
9660 *
9661 * The new File object is buffered mode (or non-sync mode), unless
9662 * +filename+ is a tty.
9663 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9664 *
9665 * Argument +path+ must be a valid file path:
9666 *
9667 * f = File.new('/etc/fstab')
9668 * f.close
9669 * f = File.new('t.txt')
9670 * f.close
9671 *
9672 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9673 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9674 *
9675 * f = File.new('t.tmp', 'w')
9676 * f.close
9677 * f = File.new('t.tmp', File::RDONLY)
9678 * f.close
9679 *
9680 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9681 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9682 *
9683 * f = File.new('t.tmp', File::CREAT, 0644)
9684 * f.close
9685 * f = File.new('t.tmp', File::CREAT, 0444)
9686 * f.close
9687 *
9688 * Optional keyword arguments +opts+ specify:
9689 *
9690 * - {Open Options}[rdoc-ref:IO@Open+Options].
9691 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9692 *
9693 */
9694
9695static VALUE
9696rb_file_initialize(int argc, VALUE *argv, VALUE io)
9697{
9698 if (RFILE(io)->fptr) {
9699 rb_raise(rb_eRuntimeError, "reinitializing File");
9700 }
9701 VALUE fname, vmode, vperm, opt;
9702 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9703 if (posargc < 3) { /* perm is File only */
9704 VALUE fd = rb_check_to_int(fname);
9705
9706 if (!NIL_P(fd)) {
9707 return io_initialize(io, fd, vmode, opt);
9708 }
9709 }
9710 return rb_open_file(io, fname, vmode, vperm, opt);
9711}
9712
9713/* :nodoc: */
9714static VALUE
9715rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9716{
9717 if (rb_block_given_p()) {
9718 VALUE cname = rb_obj_as_string(klass);
9719
9720 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9721 cname, cname);
9722 }
9723 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9724}
9725
9726
9727/*
9728 * call-seq:
9729 * IO.for_fd(fd, mode = 'r', **opts) -> io
9730 *
9731 * Synonym for IO.new.
9732 *
9733 */
9734
9735static VALUE
9736rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9737{
9738 VALUE io = rb_obj_alloc(klass);
9739 rb_io_initialize(argc, argv, io);
9740 return io;
9741}
9742
9743/*
9744 * call-seq:
9745 * ios.autoclose? -> true or false
9746 *
9747 * Returns +true+ if the underlying file descriptor of _ios_ will be
9748 * closed at its finalization or at calling #close, otherwise +false+.
9749 */
9750
9751static VALUE
9752rb_io_autoclose_p(VALUE io)
9753{
9754 rb_io_t *fptr = RFILE(io)->fptr;
9755 rb_io_check_closed(fptr);
9756 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9757}
9758
9759/*
9760 * call-seq:
9761 * io.autoclose = bool -> true or false
9762 *
9763 * Sets auto-close flag.
9764 *
9765 * f = File.open(File::NULL)
9766 * IO.for_fd(f.fileno).close
9767 * f.gets # raises Errno::EBADF
9768 *
9769 * f = File.open(File::NULL)
9770 * g = IO.for_fd(f.fileno)
9771 * g.autoclose = false
9772 * g.close
9773 * f.gets # won't cause Errno::EBADF
9774 */
9775
9776static VALUE
9777rb_io_set_autoclose(VALUE io, VALUE autoclose)
9778{
9779 rb_io_t *fptr;
9780 GetOpenFile(io, fptr);
9781 if (!RTEST(autoclose))
9782 fptr->mode |= FMODE_EXTERNAL;
9783 else
9784 fptr->mode &= ~FMODE_EXTERNAL;
9785 return autoclose;
9786}
9787
9788static VALUE
9789io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9790{
9791 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9792
9793 if (!RB_TEST(result)) {
9794 return Qnil;
9795 }
9796
9797 int mask = RB_NUM2INT(result);
9798
9799 if (mask & event) {
9800 if (return_io)
9801 return io;
9802 else
9803 return result;
9804 }
9805 else {
9806 return Qfalse;
9807 }
9808}
9809
9810/*
9811 * call-seq:
9812 * io.wait_readable -> truthy or falsy
9813 * io.wait_readable(timeout) -> truthy or falsy
9814 *
9815 * Waits until IO is readable and returns a truthy value, or a falsy
9816 * value when times out. Returns a truthy value immediately when
9817 * buffered data is available.
9818 */
9819
9820static VALUE
9821io_wait_readable(int argc, VALUE *argv, VALUE io)
9822{
9823 rb_io_t *fptr;
9824
9825 RB_IO_POINTER(io, fptr);
9827
9828 if (rb_io_read_pending(fptr)) return Qtrue;
9829
9830 rb_check_arity(argc, 0, 1);
9831 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9832
9833 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9834}
9835
9836/*
9837 * call-seq:
9838 * io.wait_writable -> truthy or falsy
9839 * io.wait_writable(timeout) -> truthy or falsy
9840 *
9841 * Waits until IO is writable and returns a truthy value or a falsy
9842 * value when times out.
9843 */
9844static VALUE
9845io_wait_writable(int argc, VALUE *argv, VALUE io)
9846{
9847 rb_io_t *fptr;
9848
9849 RB_IO_POINTER(io, fptr);
9851
9852 rb_check_arity(argc, 0, 1);
9853 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9854
9855 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9856}
9857
9858/*
9859 * call-seq:
9860 * io.wait_priority -> truthy or falsy
9861 * io.wait_priority(timeout) -> truthy or falsy
9862 *
9863 * Waits until IO is priority and returns a truthy value or a falsy
9864 * value when times out. Priority data is sent and received using
9865 * the Socket::MSG_OOB flag and is typically limited to streams.
9866 */
9867static VALUE
9868io_wait_priority(int argc, VALUE *argv, VALUE io)
9869{
9870 rb_io_t *fptr = NULL;
9871
9872 RB_IO_POINTER(io, fptr);
9874
9875 if (rb_io_read_pending(fptr)) return Qtrue;
9876
9877 rb_check_arity(argc, 0, 1);
9878 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9879
9880 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9881}
9882
9883static int
9884wait_mode_sym(VALUE mode)
9885{
9886 if (mode == ID2SYM(rb_intern("r"))) {
9887 return RB_WAITFD_IN;
9888 }
9889 if (mode == ID2SYM(rb_intern("read"))) {
9890 return RB_WAITFD_IN;
9891 }
9892 if (mode == ID2SYM(rb_intern("readable"))) {
9893 return RB_WAITFD_IN;
9894 }
9895 if (mode == ID2SYM(rb_intern("w"))) {
9896 return RB_WAITFD_OUT;
9897 }
9898 if (mode == ID2SYM(rb_intern("write"))) {
9899 return RB_WAITFD_OUT;
9900 }
9901 if (mode == ID2SYM(rb_intern("writable"))) {
9902 return RB_WAITFD_OUT;
9903 }
9904 if (mode == ID2SYM(rb_intern("rw"))) {
9905 return RB_WAITFD_IN|RB_WAITFD_OUT;
9906 }
9907 if (mode == ID2SYM(rb_intern("read_write"))) {
9908 return RB_WAITFD_IN|RB_WAITFD_OUT;
9909 }
9910 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9911 return RB_WAITFD_IN|RB_WAITFD_OUT;
9912 }
9913
9914 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9915}
9916
9917static inline enum rb_io_event
9918io_event_from_value(VALUE value)
9919{
9920 int events = RB_NUM2INT(value);
9921
9922 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9923
9924 return events;
9925}
9926
9927/*
9928 * call-seq:
9929 * io.wait(events, timeout) -> event mask, false or nil
9930 * io.wait(*event_symbols[, timeout]) -> self, true, or false
9931 *
9932 * Waits until the IO becomes ready for the specified events and returns the
9933 * subset of events that become ready, or a falsy value when times out.
9934 *
9935 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9936 * +IO::PRIORITY+.
9937 *
9938 * Returns an event mask (truthy value) immediately when buffered data is
9939 * available.
9940 *
9941 * The second form: if one or more event symbols (+:read+, +:write+, or
9942 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
9943 * corresponding to those symbols. In this form, +timeout+ is optional, the
9944 * order of the arguments is arbitrary, and returns +io+ if any of the
9945 * events is ready.
9946 */
9947
9948static VALUE
9949io_wait(int argc, VALUE *argv, VALUE io)
9950{
9951 VALUE timeout = Qundef;
9952 enum rb_io_event events = 0;
9953 int return_io = 0;
9954
9955 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9956 // We'd prefer to return the actual mask, but this form would return the io itself:
9957 return_io = 1;
9958
9959 // Slow/messy path:
9960 for (int i = 0; i < argc; i += 1) {
9961 if (RB_SYMBOL_P(argv[i])) {
9962 events |= wait_mode_sym(argv[i]);
9963 }
9964 else if (UNDEF_P(timeout)) {
9965 rb_time_interval(timeout = argv[i]);
9966 }
9967 else {
9968 rb_raise(rb_eArgError, "timeout given more than once");
9969 }
9970 }
9971
9972 if (UNDEF_P(timeout)) timeout = Qnil;
9973
9974 if (events == 0) {
9975 events = RUBY_IO_READABLE;
9976 }
9977 }
9978 else /* argc == 2 and neither are symbols */ {
9979 // This is the fast path:
9980 events = io_event_from_value(argv[0]);
9981 timeout = argv[1];
9982 }
9983
9984 if (events & RUBY_IO_READABLE) {
9985 rb_io_t *fptr = NULL;
9986 RB_IO_POINTER(io, fptr);
9987
9988 if (rb_io_read_pending(fptr)) {
9989 // This was the original behaviour:
9990 if (return_io) return Qtrue;
9991 // New behaviour always returns an event mask:
9992 else return RB_INT2NUM(RUBY_IO_READABLE);
9993 }
9994 }
9995
9996 return io_wait_event(io, events, timeout, return_io);
9997}
9998
9999static void
10000argf_mark_and_move(void *ptr)
10001{
10002 struct argf *p = ptr;
10003 rb_gc_mark_and_move(&p->filename);
10004 rb_gc_mark_and_move(&p->current_file);
10005 rb_gc_mark_and_move(&p->argv);
10006 rb_gc_mark_and_move(&p->inplace);
10007 rb_gc_mark_and_move(&p->encs.ecopts);
10008}
10009
10010static size_t
10011argf_memsize(const void *ptr)
10012{
10013 const struct argf *p = ptr;
10014 size_t size = sizeof(*p);
10015 return size;
10016}
10017
10018static const rb_data_type_t argf_type = {
10019 "ARGF",
10020 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10021 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
10022};
10023
10024static inline void
10025argf_init(VALUE argf, struct argf *p, VALUE v)
10026{
10027 p->filename = Qnil;
10028 p->current_file = Qnil;
10029 p->lineno = 0;
10030 RB_OBJ_WRITE(argf, &p->argv, v);
10031}
10032
10033static VALUE
10034argf_alloc(VALUE klass)
10035{
10036 struct argf *p;
10037 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10038
10039 argf_init(argf, p, Qnil);
10040 return argf;
10041}
10042
10043#undef rb_argv
10044
10045/* :nodoc: */
10046static VALUE
10047argf_initialize(VALUE argf, VALUE argv)
10048{
10049 memset(&ARGF, 0, sizeof(ARGF));
10050 argf_init(argf, &ARGF, argv);
10051
10052 return argf;
10053}
10054
10055/* :nodoc: */
10056static VALUE
10057argf_initialize_copy(VALUE argf, VALUE orig)
10058{
10059 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10060 ARGF = argf_of(orig);
10061 rb_gc_writebarrier_remember(argf);
10062 ARGF_SET(argv, rb_obj_dup(ARGF.argv));
10063 return argf;
10064}
10065
10066/*
10067 * call-seq:
10068 * ARGF.lineno = integer -> integer
10069 *
10070 * Sets the line number of ARGF as a whole to the given Integer.
10071 *
10072 * ARGF sets the line number automatically as you read data, so normally
10073 * you will not need to set it explicitly. To access the current line number
10074 * use ARGF.lineno.
10075 *
10076 * For example:
10077 *
10078 * ARGF.lineno #=> 0
10079 * ARGF.readline #=> "This is line 1\n"
10080 * ARGF.lineno #=> 1
10081 * ARGF.lineno = 0 #=> 0
10082 * ARGF.lineno #=> 0
10083 */
10084static VALUE
10085argf_set_lineno(VALUE argf, VALUE val)
10086{
10087 ARGF.lineno = NUM2INT(val);
10088 ARGF.last_lineno = ARGF.lineno;
10089 return val;
10090}
10091
10092/*
10093 * call-seq:
10094 * ARGF.lineno -> integer
10095 *
10096 * Returns the current line number of ARGF as a whole. This value
10097 * can be set manually with ARGF.lineno=.
10098 *
10099 * For example:
10100 *
10101 * ARGF.lineno #=> 0
10102 * ARGF.readline #=> "This is line 1\n"
10103 * ARGF.lineno #=> 1
10104 */
10105static VALUE
10106argf_lineno(VALUE argf)
10107{
10108 return INT2FIX(ARGF.lineno);
10109}
10110
10111static VALUE
10112argf_forward(int argc, VALUE *argv, VALUE argf)
10113{
10114 return forward_current(rb_frame_this_func(), argc, argv);
10115}
10116
10117#define next_argv() argf_next_argv(argf)
10118#define ARGF_GENERIC_INPUT_P() \
10119 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10120#define ARGF_FORWARD(argc, argv) do {\
10121 if (ARGF_GENERIC_INPUT_P())\
10122 return argf_forward((argc), (argv), argf);\
10123} while (0)
10124#define NEXT_ARGF_FORWARD(argc, argv) do {\
10125 if (!next_argv()) return Qnil;\
10126 ARGF_FORWARD((argc), (argv));\
10127} while (0)
10128
10129static void
10130argf_close(VALUE argf)
10131{
10132 VALUE file = ARGF.current_file;
10133 if (file == rb_stdin) return;
10134 if (RB_TYPE_P(file, T_FILE)) {
10135 rb_io_set_write_io(file, Qnil);
10136 }
10137 io_close(file);
10138 ARGF.init_p = -1;
10139}
10140
10141static int
10142argf_next_argv(VALUE argf)
10143{
10144 char *fn;
10145 rb_io_t *fptr;
10146 int stdout_binmode = 0;
10147 enum rb_io_mode fmode;
10148
10149 VALUE r_stdout = rb_ractor_stdout();
10150
10151 if (RB_TYPE_P(r_stdout, T_FILE)) {
10152 GetOpenFile(r_stdout, fptr);
10153 if (fptr->mode & FMODE_BINMODE)
10154 stdout_binmode = 1;
10155 }
10156
10157 if (ARGF.init_p == 0) {
10158 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10159 ARGF.next_p = 1;
10160 }
10161 else {
10162 ARGF.next_p = -1;
10163 }
10164 ARGF.init_p = 1;
10165 }
10166 else {
10167 if (NIL_P(ARGF.argv)) {
10168 ARGF.next_p = -1;
10169 }
10170 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10171 ARGF.next_p = 1;
10172 }
10173 }
10174
10175 if (ARGF.next_p == 1) {
10176 if (ARGF.init_p == 1) argf_close(argf);
10177 retry:
10178 if (RARRAY_LEN(ARGF.argv) > 0) {
10179 VALUE filename = rb_ary_shift(ARGF.argv);
10180 FilePathValue(filename);
10181 ARGF_SET(filename, filename);
10182 filename = rb_str_encode_ospath(filename);
10183 fn = StringValueCStr(filename);
10184 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10185 ARGF_SET(current_file, rb_stdin);
10186 if (ARGF.inplace) {
10187 rb_warn("Can't do inplace edit for stdio; skipping");
10188 goto retry;
10189 }
10190 }
10191 else {
10192 VALUE write_io = Qnil;
10193 int fr = rb_sysopen(filename, O_RDONLY, 0);
10194
10195 if (ARGF.inplace) {
10196 struct stat st;
10197#ifndef NO_SAFE_RENAME
10198 struct stat st2;
10199#endif
10200 VALUE str;
10201 int fw;
10202
10203 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10204 rb_io_close(r_stdout);
10205 }
10206 fstat(fr, &st);
10207 str = filename;
10208 if (!NIL_P(ARGF.inplace)) {
10209 VALUE suffix = ARGF.inplace;
10210 str = rb_str_dup(str);
10211 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10212 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10213 rb_enc_get(suffix), 0, Qnil))) {
10214 rb_str_append(str, suffix);
10215 }
10216#ifdef NO_SAFE_RENAME
10217 (void)close(fr);
10218 (void)unlink(RSTRING_PTR(str));
10219 if (rename(fn, RSTRING_PTR(str)) < 0) {
10220 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10221 filename, str, strerror(errno));
10222 goto retry;
10223 }
10224 fr = rb_sysopen(str, O_RDONLY, 0);
10225#else
10226 if (rename(fn, RSTRING_PTR(str)) < 0) {
10227 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10228 filename, str, strerror(errno));
10229 close(fr);
10230 goto retry;
10231 }
10232#endif
10233 }
10234 else {
10235#ifdef NO_SAFE_RENAME
10236 rb_fatal("Can't do inplace edit without backup");
10237#else
10238 if (unlink(fn) < 0) {
10239 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10240 filename, strerror(errno));
10241 close(fr);
10242 goto retry;
10243 }
10244#endif
10245 }
10246 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10247#ifndef NO_SAFE_RENAME
10248 fstat(fw, &st2);
10249#ifdef HAVE_FCHMOD
10250 fchmod(fw, st.st_mode);
10251#else
10252 chmod(fn, st.st_mode);
10253#endif
10254 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10255 int err;
10256#ifdef HAVE_FCHOWN
10257 err = fchown(fw, st.st_uid, st.st_gid);
10258#else
10259 err = chown(fn, st.st_uid, st.st_gid);
10260#endif
10261 if (err && getuid() == 0 && st2.st_uid == 0) {
10262 const char *wkfn = RSTRING_PTR(filename);
10263 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10264 filename, str, strerror(errno));
10265 (void)close(fr);
10266 (void)close(fw);
10267 (void)unlink(wkfn);
10268 goto retry;
10269 }
10270 }
10271#endif
10272 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10273 rb_ractor_stdout_set(write_io);
10274 if (stdout_binmode) rb_io_binmode(rb_stdout);
10275 }
10276 fmode = FMODE_READABLE;
10277 if (!ARGF.binmode) {
10278 fmode |= DEFAULT_TEXTMODE;
10279 }
10280 ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
10281 if (!NIL_P(write_io)) {
10282 rb_io_set_write_io(ARGF.current_file, write_io);
10283 }
10284 RB_GC_GUARD(filename);
10285 }
10286 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10287 GetOpenFile(ARGF.current_file, fptr);
10288 if (ARGF.encs.enc) {
10289 fptr->encs = ARGF.encs;
10290 clear_codeconv(fptr);
10291 }
10292 else {
10293 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10294 if (!ARGF.binmode) {
10296#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10297 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10298#endif
10299 }
10300 }
10301 ARGF.next_p = 0;
10302 }
10303 else {
10304 ARGF.next_p = 1;
10305 return FALSE;
10306 }
10307 }
10308 else if (ARGF.next_p == -1) {
10309 ARGF_SET(current_file, rb_stdin);
10310 ARGF_SET(filename, rb_str_new2("-"));
10311 if (ARGF.inplace) {
10312 rb_warn("Can't do inplace edit for stdio");
10313 rb_ractor_stdout_set(orig_stdout);
10314 }
10315 }
10316 if (ARGF.init_p == -1) ARGF.init_p = 1;
10317 return TRUE;
10318}
10319
10320static VALUE
10321argf_getline(int argc, VALUE *argv, VALUE argf)
10322{
10323 VALUE line;
10324 long lineno = ARGF.lineno;
10325
10326 retry:
10327 if (!next_argv()) return Qnil;
10328 if (ARGF_GENERIC_INPUT_P()) {
10329 line = forward_current(idGets, argc, argv);
10330 }
10331 else {
10332 if (argc == 0 && rb_rs == rb_default_rs) {
10333 line = rb_io_gets(ARGF.current_file);
10334 }
10335 else {
10336 line = rb_io_getline(argc, argv, ARGF.current_file);
10337 }
10338 if (NIL_P(line) && ARGF.next_p != -1) {
10339 argf_close(argf);
10340 ARGF.next_p = 1;
10341 goto retry;
10342 }
10343 }
10344 if (!NIL_P(line)) {
10345 ARGF.lineno = ++lineno;
10346 ARGF.last_lineno = ARGF.lineno;
10347 }
10348 return line;
10349}
10350
10351static VALUE
10352argf_lineno_getter(ID id, VALUE *var)
10353{
10354 VALUE argf = *var;
10355 return INT2FIX(ARGF.last_lineno);
10356}
10357
10358static void
10359argf_lineno_setter(VALUE val, ID id, VALUE *var)
10360{
10361 VALUE argf = *var;
10362 int n = NUM2INT(val);
10363 ARGF.last_lineno = ARGF.lineno = n;
10364}
10365
10366void
10367rb_reset_argf_lineno(long n)
10368{
10369 ARGF.last_lineno = ARGF.lineno = n;
10370}
10371
10372static VALUE argf_gets(int, VALUE *, VALUE);
10373
10374/*
10375 * call-seq:
10376 * gets(sep=$/ [, getline_args]) -> string or nil
10377 * gets(limit [, getline_args]) -> string or nil
10378 * gets(sep, limit [, getline_args]) -> string or nil
10379 *
10380 * Returns (and assigns to <code>$_</code>) the next line from the list
10381 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10382 * no files are present on the command line. Returns +nil+ at end of
10383 * file. The optional argument specifies the record separator. The
10384 * separator is included with the contents of each record. A separator
10385 * of +nil+ reads the entire contents, and a zero-length separator
10386 * reads the input one paragraph at a time, where paragraphs are
10387 * divided by two consecutive newlines. If the first argument is an
10388 * integer, or optional second argument is given, the returning string
10389 * would not be longer than the given value in bytes. If multiple
10390 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10391 * the contents one file at a time.
10392 *
10393 * ARGV << "testfile"
10394 * print while gets
10395 *
10396 * <em>produces:</em>
10397 *
10398 * This is line one
10399 * This is line two
10400 * This is line three
10401 * And so on...
10402 *
10403 * The style of programming using <code>$_</code> as an implicit
10404 * parameter is gradually losing favor in the Ruby community.
10405 */
10406
10407static VALUE
10408rb_f_gets(int argc, VALUE *argv, VALUE recv)
10409{
10410 if (recv == argf) {
10411 return argf_gets(argc, argv, argf);
10412 }
10413 return forward(argf, idGets, argc, argv);
10414}
10415
10416/*
10417 * call-seq:
10418 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10419 * ARGF.gets(limit [, getline_args]) -> string or nil
10420 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10421 *
10422 * Returns the next line from the current file in ARGF.
10423 *
10424 * By default lines are assumed to be separated by <code>$/</code>;
10425 * to use a different character as a separator, supply it as a String
10426 * for the _sep_ argument.
10427 *
10428 * The optional _limit_ argument specifies how many characters of each line
10429 * to return. By default all characters are returned.
10430 *
10431 * See IO.readlines for details about getline_args.
10432 *
10433 */
10434static VALUE
10435argf_gets(int argc, VALUE *argv, VALUE argf)
10436{
10437 VALUE line;
10438
10439 line = argf_getline(argc, argv, argf);
10440 rb_lastline_set(line);
10441
10442 return line;
10443}
10444
10445VALUE
10447{
10448 VALUE line;
10449
10450 if (rb_rs != rb_default_rs) {
10451 return rb_f_gets(0, 0, argf);
10452 }
10453
10454 retry:
10455 if (!next_argv()) return Qnil;
10456 line = rb_io_gets(ARGF.current_file);
10457 if (NIL_P(line) && ARGF.next_p != -1) {
10458 rb_io_close(ARGF.current_file);
10459 ARGF.next_p = 1;
10460 goto retry;
10461 }
10462 rb_lastline_set(line);
10463 if (!NIL_P(line)) {
10464 ARGF.lineno++;
10465 ARGF.last_lineno = ARGF.lineno;
10466 }
10467
10468 return line;
10469}
10470
10471static VALUE argf_readline(int, VALUE *, VALUE);
10472
10473/*
10474 * call-seq:
10475 * readline(sep = $/, chomp: false) -> string
10476 * readline(limit, chomp: false) -> string
10477 * readline(sep, limit, chomp: false) -> string
10478 *
10479 * Equivalent to method Kernel#gets, except that it raises an exception
10480 * if called at end-of-stream:
10481 *
10482 * $ cat t.txt | ruby -e "p readlines; readline"
10483 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10484 * in `readline': end of file reached (EOFError)
10485 *
10486 * Optional keyword argument +chomp+ specifies whether line separators
10487 * are to be omitted.
10488 */
10489
10490static VALUE
10491rb_f_readline(int argc, VALUE *argv, VALUE recv)
10492{
10493 if (recv == argf) {
10494 return argf_readline(argc, argv, argf);
10495 }
10496 return forward(argf, rb_intern("readline"), argc, argv);
10497}
10498
10499
10500/*
10501 * call-seq:
10502 * ARGF.readline(sep=$/) -> string
10503 * ARGF.readline(limit) -> string
10504 * ARGF.readline(sep, limit) -> string
10505 *
10506 * Returns the next line from the current file in ARGF.
10507 *
10508 * By default lines are assumed to be separated by <code>$/</code>;
10509 * to use a different character as a separator, supply it as a String
10510 * for the _sep_ argument.
10511 *
10512 * The optional _limit_ argument specifies how many characters of each line
10513 * to return. By default all characters are returned.
10514 *
10515 * An EOFError is raised at the end of the file.
10516 */
10517static VALUE
10518argf_readline(int argc, VALUE *argv, VALUE argf)
10519{
10520 VALUE line;
10521
10522 if (!next_argv()) rb_eof_error();
10523 ARGF_FORWARD(argc, argv);
10524 line = argf_gets(argc, argv, argf);
10525 if (NIL_P(line)) {
10526 rb_eof_error();
10527 }
10528
10529 return line;
10530}
10531
10532static VALUE argf_readlines(int, VALUE *, VALUE);
10533
10534/*
10535 * call-seq:
10536 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10537 * readlines(limit, chomp: false, **enc_opts) -> array
10538 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10539 *
10540 * Returns an array containing the lines returned by calling
10541 * Kernel#gets until the end-of-stream is reached;
10542 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10543 *
10544 * With only string argument +sep+ given,
10545 * returns the remaining lines as determined by line separator +sep+,
10546 * or +nil+ if none;
10547 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10548 *
10549 * # Default separator.
10550 * $ cat t.txt | ruby -e "p readlines"
10551 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10552 *
10553 * # Specified separator.
10554 * $ cat t.txt | ruby -e "p readlines 'li'"
10555 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10556 *
10557 * # Get-all separator.
10558 * $ cat t.txt | ruby -e "p readlines nil"
10559 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10560 *
10561 * # Get-paragraph separator.
10562 * $ cat t.txt | ruby -e "p readlines ''"
10563 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10564 *
10565 * With only integer argument +limit+ given,
10566 * limits the number of bytes in the line;
10567 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10568 *
10569 * $cat t.txt | ruby -e "p readlines 10"
10570 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10571 *
10572 * $cat t.txt | ruby -e "p readlines 11"
10573 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10574 *
10575 * $cat t.txt | ruby -e "p readlines 12"
10576 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10577 *
10578 * With arguments +sep+ and +limit+ given,
10579 * combines the two behaviors
10580 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10581 *
10582 * Optional keyword argument +chomp+ specifies whether line separators
10583 * are to be omitted:
10584 *
10585 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10586 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10587 *
10588 * Optional keyword arguments +enc_opts+ specify encoding options;
10589 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10590 *
10591 */
10592
10593static VALUE
10594rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10595{
10596 if (recv == argf) {
10597 return argf_readlines(argc, argv, argf);
10598 }
10599 return forward(argf, rb_intern("readlines"), argc, argv);
10600}
10601
10602/*
10603 * call-seq:
10604 * ARGF.readlines(sep = $/, chomp: false) -> array
10605 * ARGF.readlines(limit, chomp: false) -> array
10606 * ARGF.readlines(sep, limit, chomp: false) -> array
10607 *
10608 * ARGF.to_a(sep = $/, chomp: false) -> array
10609 * ARGF.to_a(limit, chomp: false) -> array
10610 * ARGF.to_a(sep, limit, chomp: false) -> array
10611 *
10612 * Reads each file in ARGF in its entirety, returning an Array containing
10613 * lines from the files. Lines are assumed to be separated by _sep_.
10614 *
10615 * lines = ARGF.readlines
10616 * lines[0] #=> "This is line one\n"
10617 *
10618 * See +IO.readlines+ for a full description of all options.
10619 */
10620static VALUE
10621argf_readlines(int argc, VALUE *argv, VALUE argf)
10622{
10623 long lineno = ARGF.lineno;
10624 VALUE lines, ary;
10625
10626 ary = rb_ary_new();
10627 while (next_argv()) {
10628 if (ARGF_GENERIC_INPUT_P()) {
10629 lines = forward_current(rb_intern("readlines"), argc, argv);
10630 }
10631 else {
10632 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10633 argf_close(argf);
10634 }
10635 ARGF.next_p = 1;
10636 rb_ary_concat(ary, lines);
10637 ARGF.lineno = lineno + RARRAY_LEN(ary);
10638 ARGF.last_lineno = ARGF.lineno;
10639 }
10640 ARGF.init_p = 0;
10641 return ary;
10642}
10643
10644/*
10645 * call-seq:
10646 * `command` -> string
10647 *
10648 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10649 * sets global variable <tt>$?</tt> to the process status.
10650 *
10651 * This method has potential security vulnerabilities if called with untrusted input;
10652 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10653 *
10654 * Examples:
10655 *
10656 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10657 * $ `echo oops && exit 99` # => "oops\n"
10658 * $ $? # => #<Process::Status: pid 17088 exit 99>
10659 * $ $?.exitstatus # => 99
10660 *
10661 * The built-in syntax <tt>%x{...}</tt> uses this method.
10662 *
10663 */
10664
10665static VALUE
10666rb_f_backquote(VALUE obj, VALUE str)
10667{
10668 VALUE port;
10669 VALUE result;
10670 rb_io_t *fptr;
10671
10672 StringValue(str);
10673 rb_last_status_clear();
10674 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10675 if (NIL_P(port)) return rb_str_new(0,0);
10676
10677 GetOpenFile(port, fptr);
10678 result = read_all(fptr, remain_size(fptr), Qnil);
10679 rb_io_close(port);
10680 rb_io_fptr_cleanup_all(fptr);
10681 RB_GC_GUARD(port);
10682
10683 return result;
10684}
10685
10686#ifdef HAVE_SYS_SELECT_H
10687#include <sys/select.h>
10688#endif
10689
10690static VALUE
10691select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10692{
10693 VALUE res, list;
10694 rb_fdset_t *rp, *wp, *ep;
10695 rb_io_t *fptr;
10696 long i;
10697 int max = 0, n;
10698 int pending = 0;
10699 struct timeval timerec;
10700
10701 if (!NIL_P(read)) {
10702 Check_Type(read, T_ARRAY);
10703 for (i=0; i<RARRAY_LEN(read); i++) {
10704 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10705 rb_fd_set(fptr->fd, &fds[0]);
10706 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10707 pending++;
10708 rb_fd_set(fptr->fd, &fds[3]);
10709 }
10710 if (max < fptr->fd) max = fptr->fd;
10711 }
10712 if (pending) { /* no blocking if there's buffered data */
10713 timerec.tv_sec = timerec.tv_usec = 0;
10714 tp = &timerec;
10715 }
10716 rp = &fds[0];
10717 }
10718 else
10719 rp = 0;
10720
10721 if (!NIL_P(write)) {
10722 Check_Type(write, T_ARRAY);
10723 for (i=0; i<RARRAY_LEN(write); i++) {
10724 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10725 GetOpenFile(write_io, fptr);
10726 rb_fd_set(fptr->fd, &fds[1]);
10727 if (max < fptr->fd) max = fptr->fd;
10728 }
10729 wp = &fds[1];
10730 }
10731 else
10732 wp = 0;
10733
10734 if (!NIL_P(except)) {
10735 Check_Type(except, T_ARRAY);
10736 for (i=0; i<RARRAY_LEN(except); i++) {
10737 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10738 VALUE write_io = GetWriteIO(io);
10739 GetOpenFile(io, fptr);
10740 rb_fd_set(fptr->fd, &fds[2]);
10741 if (max < fptr->fd) max = fptr->fd;
10742 if (io != write_io) {
10743 GetOpenFile(write_io, fptr);
10744 rb_fd_set(fptr->fd, &fds[2]);
10745 if (max < fptr->fd) max = fptr->fd;
10746 }
10747 }
10748 ep = &fds[2];
10749 }
10750 else {
10751 ep = 0;
10752 }
10753
10754 max++;
10755
10756 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10757 if (n < 0) {
10758 rb_sys_fail(0);
10759 }
10760 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10761
10762 res = rb_ary_new2(3);
10763 rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
10764 rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
10765 rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
10766
10767 if (rp) {
10768 list = RARRAY_AREF(res, 0);
10769 for (i=0; i< RARRAY_LEN(read); i++) {
10770 VALUE obj = rb_ary_entry(read, i);
10771 VALUE io = rb_io_get_io(obj);
10772 GetOpenFile(io, fptr);
10773 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10774 rb_fd_isset(fptr->fd, &fds[3])) {
10775 rb_ary_push(list, obj);
10776 }
10777 }
10778 }
10779
10780 if (wp) {
10781 list = RARRAY_AREF(res, 1);
10782 for (i=0; i< RARRAY_LEN(write); i++) {
10783 VALUE obj = rb_ary_entry(write, i);
10784 VALUE io = rb_io_get_io(obj);
10785 VALUE write_io = GetWriteIO(io);
10786 GetOpenFile(write_io, fptr);
10787 if (rb_fd_isset(fptr->fd, &fds[1])) {
10788 rb_ary_push(list, obj);
10789 }
10790 }
10791 }
10792
10793 if (ep) {
10794 list = RARRAY_AREF(res, 2);
10795 for (i=0; i< RARRAY_LEN(except); i++) {
10796 VALUE obj = rb_ary_entry(except, i);
10797 VALUE io = rb_io_get_io(obj);
10798 VALUE write_io = GetWriteIO(io);
10799 GetOpenFile(io, fptr);
10800 if (rb_fd_isset(fptr->fd, &fds[2])) {
10801 rb_ary_push(list, obj);
10802 }
10803 else if (io != write_io) {
10804 GetOpenFile(write_io, fptr);
10805 if (rb_fd_isset(fptr->fd, &fds[2])) {
10806 rb_ary_push(list, obj);
10807 }
10808 }
10809 }
10810 }
10811
10812 return res; /* returns an empty array on interrupt */
10813}
10814
10816 VALUE read, write, except;
10817 struct timeval *timeout;
10818 rb_fdset_t fdsets[4];
10819};
10820
10821static VALUE
10822select_call(VALUE arg)
10823{
10824 struct select_args *p = (struct select_args *)arg;
10825
10826 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10827}
10828
10829static VALUE
10830select_end(VALUE arg)
10831{
10832 struct select_args *p = (struct select_args *)arg;
10833 int i;
10834
10835 for (i = 0; i < numberof(p->fdsets); ++i)
10836 rb_fd_term(&p->fdsets[i]);
10837 return Qnil;
10838}
10839
10840static VALUE sym_normal, sym_sequential, sym_random,
10841 sym_willneed, sym_dontneed, sym_noreuse;
10842
10843#ifdef HAVE_POSIX_FADVISE
10844struct io_advise_struct {
10845 int fd;
10846 int advice;
10847 rb_off_t offset;
10848 rb_off_t len;
10849};
10850
10851static VALUE
10852io_advise_internal(void *arg)
10853{
10854 struct io_advise_struct *ptr = arg;
10855 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10856}
10857
10858static VALUE
10859io_advise_sym_to_const(VALUE sym)
10860{
10861#ifdef POSIX_FADV_NORMAL
10862 if (sym == sym_normal)
10863 return INT2NUM(POSIX_FADV_NORMAL);
10864#endif
10865
10866#ifdef POSIX_FADV_RANDOM
10867 if (sym == sym_random)
10868 return INT2NUM(POSIX_FADV_RANDOM);
10869#endif
10870
10871#ifdef POSIX_FADV_SEQUENTIAL
10872 if (sym == sym_sequential)
10873 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10874#endif
10875
10876#ifdef POSIX_FADV_WILLNEED
10877 if (sym == sym_willneed)
10878 return INT2NUM(POSIX_FADV_WILLNEED);
10879#endif
10880
10881#ifdef POSIX_FADV_DONTNEED
10882 if (sym == sym_dontneed)
10883 return INT2NUM(POSIX_FADV_DONTNEED);
10884#endif
10885
10886#ifdef POSIX_FADV_NOREUSE
10887 if (sym == sym_noreuse)
10888 return INT2NUM(POSIX_FADV_NOREUSE);
10889#endif
10890
10891 return Qnil;
10892}
10893
10894static VALUE
10895do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10896{
10897 int rv;
10898 struct io_advise_struct ias;
10899 VALUE num_adv;
10900
10901 num_adv = io_advise_sym_to_const(advice);
10902
10903 /*
10904 * The platform doesn't support this hint. We don't raise exception, instead
10905 * silently ignore it. Because IO::advise is only hint.
10906 */
10907 if (NIL_P(num_adv))
10908 return Qnil;
10909
10910 ias.fd = fptr->fd;
10911 ias.advice = NUM2INT(num_adv);
10912 ias.offset = offset;
10913 ias.len = len;
10914
10915 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10916 if (rv && rv != ENOSYS) {
10917 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10918 it returns the error code. */
10919 VALUE message = rb_sprintf("%"PRIsVALUE" "
10920 "(%"PRI_OFFT_PREFIX"d, "
10921 "%"PRI_OFFT_PREFIX"d, "
10922 "%"PRIsVALUE")",
10923 fptr->pathv, offset, len, advice);
10924 rb_syserr_fail_str(rv, message);
10925 }
10926
10927 return Qnil;
10928}
10929
10930#endif /* HAVE_POSIX_FADVISE */
10931
10932static void
10933advice_arg_check(VALUE advice)
10934{
10935 if (!SYMBOL_P(advice))
10936 rb_raise(rb_eTypeError, "advice must be a Symbol");
10937
10938 if (advice != sym_normal &&
10939 advice != sym_sequential &&
10940 advice != sym_random &&
10941 advice != sym_willneed &&
10942 advice != sym_dontneed &&
10943 advice != sym_noreuse) {
10944 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10945 }
10946}
10947
10948/*
10949 * call-seq:
10950 * advise(advice, offset = 0, len = 0) -> nil
10951 *
10952 * Invokes Posix system call
10953 * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
10954 * which announces an intention to access data from the current file
10955 * in a particular manner.
10956 *
10957 * The arguments and results are platform-dependent.
10958 *
10959 * The relevant data is specified by:
10960 *
10961 * - +offset+: The offset of the first byte of data.
10962 * - +len+: The number of bytes to be accessed;
10963 * if +len+ is zero, or is larger than the number of bytes remaining,
10964 * all remaining bytes will be accessed.
10965 *
10966 * Argument +advice+ is one of the following symbols:
10967 *
10968 * - +:normal+: The application has no advice to give
10969 * about its access pattern for the specified data.
10970 * If no advice is given for an open file, this is the default assumption.
10971 * - +:sequential+: The application expects to access the specified data sequentially
10972 * (with lower offsets read before higher ones).
10973 * - +:random+: The specified data will be accessed in random order.
10974 * - +:noreuse+: The specified data will be accessed only once.
10975 * - +:willneed+: The specified data will be accessed in the near future.
10976 * - +:dontneed+: The specified data will not be accessed in the near future.
10977 *
10978 * Not implemented on all platforms.
10979 *
10980 */
10981static VALUE
10982rb_io_advise(int argc, VALUE *argv, VALUE io)
10983{
10984 VALUE advice, offset, len;
10985 rb_off_t off, l;
10986 rb_io_t *fptr;
10987
10988 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10989 advice_arg_check(advice);
10990
10991 io = GetWriteIO(io);
10992 GetOpenFile(io, fptr);
10993
10994 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10995 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10996
10997#ifdef HAVE_POSIX_FADVISE
10998 return do_io_advise(fptr, advice, off, l);
10999#else
11000 ((void)off, (void)l); /* Ignore all hint */
11001 return Qnil;
11002#endif
11003}
11004
11005static int
11006is_pos_inf(VALUE x)
11007{
11008 double f;
11009 if (!RB_FLOAT_TYPE_P(x))
11010 return 0;
11011 f = RFLOAT_VALUE(x);
11012 return isinf(f) && 0 < f;
11013}
11014
11015/*
11016 * call-seq:
11017 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11018 *
11019 * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
11020 * which monitors multiple file descriptors,
11021 * waiting until one or more of the file descriptors
11022 * becomes ready for some class of I/O operation.
11023 *
11024 * Not implemented on all platforms.
11025 *
11026 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11027 * is an array of IO objects.
11028 *
11029 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11030 * interval in seconds.
11031 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11032 * +nil+ and +Float::INFINITY+ means no timeout.
11033 *
11034 * The method monitors the \IO objects given in all three arrays,
11035 * waiting for some to be ready;
11036 * returns a 3-element array whose elements are:
11037 *
11038 * - An array of the objects in +read_ios+ that are ready for reading.
11039 * - An array of the objects in +write_ios+ that are ready for writing.
11040 * - An array of the objects in +error_ios+ have pending exceptions.
11041 *
11042 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11043 *
11044 * \IO.select peeks the buffer of \IO objects for testing readability.
11045 * If the \IO buffer is not empty, \IO.select immediately notifies
11046 * readability. This "peek" only happens for \IO objects. It does not
11047 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11048 *
11049 * The best way to use \IO.select is invoking it after non-blocking
11050 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11051 * raise an exception which is extended by IO::WaitReadable or
11052 * IO::WaitWritable. The modules notify how the caller should wait
11053 * with \IO.select. If IO::WaitReadable is raised, the caller should
11054 * wait for reading. If IO::WaitWritable is raised, the caller should
11055 * wait for writing.
11056 *
11057 * So, blocking read (#readpartial) can be emulated using
11058 * #read_nonblock and \IO.select as follows:
11059 *
11060 * begin
11061 * result = io_like.read_nonblock(maxlen)
11062 * rescue IO::WaitReadable
11063 * IO.select([io_like])
11064 * retry
11065 * rescue IO::WaitWritable
11066 * IO.select(nil, [io_like])
11067 * retry
11068 * end
11069 *
11070 * Especially, the combination of non-blocking methods and \IO.select is
11071 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11072 * has #to_io method to return underlying IO object. IO.select calls
11073 * #to_io to obtain the file descriptor to wait.
11074 *
11075 * This means that readability notified by \IO.select doesn't mean
11076 * readability from OpenSSL::SSL::SSLSocket object.
11077 *
11078 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11079 * some data. \IO.select doesn't see the buffer. So \IO.select can
11080 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11081 *
11082 * However, several more complicated situations exist.
11083 *
11084 * SSL is a protocol which is sequence of records.
11085 * The record consists of multiple bytes.
11086 * So, the remote side of SSL sends a partial record, IO.select
11087 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11088 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11089 *
11090 * Also, the remote side can request SSL renegotiation which forces
11091 * the local SSL engine to write some data.
11092 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11093 * system call and it can block.
11094 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11095 * IO::WaitWritable instead of blocking.
11096 * So, the caller should wait for ready for writability as above
11097 * example.
11098 *
11099 * The combination of non-blocking methods and \IO.select is also useful
11100 * for streams such as tty, pipe socket socket when multiple processes
11101 * read from a stream.
11102 *
11103 * Finally, Linux kernel developers don't guarantee that
11104 * readability of select(2) means readability of following read(2) even
11105 * for a single process;
11106 * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
11107 *
11108 * Invoking \IO.select before IO#readpartial works well as usual.
11109 * However it is not the best way to use \IO.select.
11110 *
11111 * The writability notified by select(2) doesn't show
11112 * how many bytes are writable.
11113 * IO#write method blocks until given whole string is written.
11114 * So, <tt>IO#write(two or more bytes)</tt> can block after
11115 * writability is notified by \IO.select. IO#write_nonblock is required
11116 * to avoid the blocking.
11117 *
11118 * Blocking write (#write) can be emulated using #write_nonblock and
11119 * IO.select as follows: IO::WaitReadable should also be rescued for
11120 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11121 *
11122 * while 0 < string.bytesize
11123 * begin
11124 * written = io_like.write_nonblock(string)
11125 * rescue IO::WaitReadable
11126 * IO.select([io_like])
11127 * retry
11128 * rescue IO::WaitWritable
11129 * IO.select(nil, [io_like])
11130 * retry
11131 * end
11132 * string = string.byteslice(written..-1)
11133 * end
11134 *
11135 * Example:
11136 *
11137 * rp, wp = IO.pipe
11138 * mesg = "ping "
11139 * 100.times {
11140 * # IO.select follows IO#read. Not the best way to use IO.select.
11141 * rs, ws, = IO.select([rp], [wp])
11142 * if r = rs[0]
11143 * ret = r.read(5)
11144 * print ret
11145 * case ret
11146 * when /ping/
11147 * mesg = "pong\n"
11148 * when /pong/
11149 * mesg = "ping "
11150 * end
11151 * end
11152 * if w = ws[0]
11153 * w.write(mesg)
11154 * end
11155 * }
11156 *
11157 * Output:
11158 *
11159 * ping pong
11160 * ping pong
11161 * ping pong
11162 * (snipped)
11163 * ping
11164 *
11165 */
11166
11167static VALUE
11168rb_f_select(int argc, VALUE *argv, VALUE obj)
11169{
11170 VALUE scheduler = rb_fiber_scheduler_current();
11171 if (scheduler != Qnil) {
11172 // It's optionally supported.
11173 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11174 if (!UNDEF_P(result)) return result;
11175 }
11176
11177 VALUE timeout;
11178 struct select_args args;
11179 struct timeval timerec;
11180 int i;
11181
11182 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11183 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11184 args.timeout = 0;
11185 }
11186 else {
11187 timerec = rb_time_interval(timeout);
11188 args.timeout = &timerec;
11189 }
11190
11191 for (i = 0; i < numberof(args.fdsets); ++i)
11192 rb_fd_init(&args.fdsets[i]);
11193
11194 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11195}
11196
11197#ifdef IOCTL_REQ_TYPE
11198 typedef IOCTL_REQ_TYPE ioctl_req_t;
11199#else
11200 typedef int ioctl_req_t;
11201# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11202#endif
11203
11204#ifdef HAVE_IOCTL
11205struct ioctl_arg {
11206 int fd;
11207 ioctl_req_t cmd;
11208 long narg;
11209};
11210
11211static VALUE
11212nogvl_ioctl(void *ptr)
11213{
11214 struct ioctl_arg *arg = ptr;
11215
11216 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11217}
11218
11219static int
11220do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11221{
11222 int retval;
11223 struct ioctl_arg arg;
11224
11225 arg.fd = io->fd;
11226 arg.cmd = cmd;
11227 arg.narg = narg;
11228
11229 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11230
11231 return retval;
11232}
11233#endif
11234
11235#define DEFAULT_IOCTL_NARG_LEN (256)
11236
11237#if defined(__linux__) && defined(_IOC_SIZE)
11238static long
11239linux_iocparm_len(ioctl_req_t cmd)
11240{
11241 long len;
11242
11243 if ((cmd & 0xFFFF0000) == 0) {
11244 /* legacy and unstructured ioctl number. */
11245 return DEFAULT_IOCTL_NARG_LEN;
11246 }
11247
11248 len = _IOC_SIZE(cmd);
11249
11250 /* paranoia check for silly drivers which don't keep ioctl convention */
11251 if (len < DEFAULT_IOCTL_NARG_LEN)
11252 len = DEFAULT_IOCTL_NARG_LEN;
11253
11254 return len;
11255}
11256#endif
11257
11258#ifdef HAVE_IOCTL
11259static long
11260ioctl_narg_len(ioctl_req_t cmd)
11261{
11262 long len;
11263
11264#ifdef IOCPARM_MASK
11265#ifndef IOCPARM_LEN
11266#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11267#endif
11268#endif
11269#ifdef IOCPARM_LEN
11270 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11271#elif defined(__linux__) && defined(_IOC_SIZE)
11272 len = linux_iocparm_len(cmd);
11273#else
11274 /* otherwise guess at what's safe */
11275 len = DEFAULT_IOCTL_NARG_LEN;
11276#endif
11277
11278 return len;
11279}
11280#endif
11281
11282#ifdef HAVE_FCNTL
11283#ifdef __linux__
11284typedef long fcntl_arg_t;
11285#else
11286/* posix */
11287typedef int fcntl_arg_t;
11288#endif
11289
11290static long
11291fcntl_narg_len(ioctl_req_t cmd)
11292{
11293 long len;
11294
11295 switch (cmd) {
11296#ifdef F_DUPFD
11297 case F_DUPFD:
11298 len = sizeof(fcntl_arg_t);
11299 break;
11300#endif
11301#ifdef F_DUP2FD /* bsd specific */
11302 case F_DUP2FD:
11303 len = sizeof(int);
11304 break;
11305#endif
11306#ifdef F_DUPFD_CLOEXEC /* linux specific */
11307 case F_DUPFD_CLOEXEC:
11308 len = sizeof(fcntl_arg_t);
11309 break;
11310#endif
11311#ifdef F_GETFD
11312 case F_GETFD:
11313 len = 1;
11314 break;
11315#endif
11316#ifdef F_SETFD
11317 case F_SETFD:
11318 len = sizeof(fcntl_arg_t);
11319 break;
11320#endif
11321#ifdef F_GETFL
11322 case F_GETFL:
11323 len = 1;
11324 break;
11325#endif
11326#ifdef F_SETFL
11327 case F_SETFL:
11328 len = sizeof(fcntl_arg_t);
11329 break;
11330#endif
11331#ifdef F_GETOWN
11332 case F_GETOWN:
11333 len = 1;
11334 break;
11335#endif
11336#ifdef F_SETOWN
11337 case F_SETOWN:
11338 len = sizeof(fcntl_arg_t);
11339 break;
11340#endif
11341#ifdef F_GETOWN_EX /* linux specific */
11342 case F_GETOWN_EX:
11343 len = sizeof(struct f_owner_ex);
11344 break;
11345#endif
11346#ifdef F_SETOWN_EX /* linux specific */
11347 case F_SETOWN_EX:
11348 len = sizeof(struct f_owner_ex);
11349 break;
11350#endif
11351#ifdef F_GETLK
11352 case F_GETLK:
11353 len = sizeof(struct flock);
11354 break;
11355#endif
11356#ifdef F_SETLK
11357 case F_SETLK:
11358 len = sizeof(struct flock);
11359 break;
11360#endif
11361#ifdef F_SETLKW
11362 case F_SETLKW:
11363 len = sizeof(struct flock);
11364 break;
11365#endif
11366#ifdef F_READAHEAD /* bsd specific */
11367 case F_READAHEAD:
11368 len = sizeof(int);
11369 break;
11370#endif
11371#ifdef F_RDAHEAD /* Darwin specific */
11372 case F_RDAHEAD:
11373 len = sizeof(int);
11374 break;
11375#endif
11376#ifdef F_GETSIG /* linux specific */
11377 case F_GETSIG:
11378 len = 1;
11379 break;
11380#endif
11381#ifdef F_SETSIG /* linux specific */
11382 case F_SETSIG:
11383 len = sizeof(fcntl_arg_t);
11384 break;
11385#endif
11386#ifdef F_GETLEASE /* linux specific */
11387 case F_GETLEASE:
11388 len = 1;
11389 break;
11390#endif
11391#ifdef F_SETLEASE /* linux specific */
11392 case F_SETLEASE:
11393 len = sizeof(fcntl_arg_t);
11394 break;
11395#endif
11396#ifdef F_NOTIFY /* linux specific */
11397 case F_NOTIFY:
11398 len = sizeof(fcntl_arg_t);
11399 break;
11400#endif
11401
11402 default:
11403 len = 256;
11404 break;
11405 }
11406
11407 return len;
11408}
11409#else /* HAVE_FCNTL */
11410static long
11411fcntl_narg_len(ioctl_req_t cmd)
11412{
11413 return 0;
11414}
11415#endif /* HAVE_FCNTL */
11416
11417#define NARG_SENTINEL 17
11418
11419static long
11420setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11421{
11422 long narg = 0;
11423 VALUE arg = *argp;
11424
11425 if (!RTEST(arg)) {
11426 narg = 0;
11427 }
11428 else if (FIXNUM_P(arg)) {
11429 narg = FIX2LONG(arg);
11430 }
11431 else if (arg == Qtrue) {
11432 narg = 1;
11433 }
11434 else {
11435 VALUE tmp = rb_check_string_type(arg);
11436
11437 if (NIL_P(tmp)) {
11438 narg = NUM2LONG(arg);
11439 }
11440 else {
11441 char *ptr;
11442 long len, slen;
11443
11444 *argp = arg = tmp;
11445 len = narg_len(cmd);
11446 rb_str_modify(arg);
11447
11448 slen = RSTRING_LEN(arg);
11449 /* expand for data + sentinel. */
11450 if (slen < len+1) {
11451 rb_str_resize(arg, len+1);
11452 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11453 slen = len+1;
11454 }
11455 /* a little sanity check here */
11456 ptr = RSTRING_PTR(arg);
11457 ptr[slen - 1] = NARG_SENTINEL;
11458 narg = (long)(SIGNED_VALUE)ptr;
11459 }
11460 }
11461
11462 return narg;
11463}
11464
11465static VALUE
11466finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11467{
11468 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11469 if (RB_TYPE_P(arg, T_STRING)) {
11470 char *ptr;
11471 long slen;
11472 RSTRING_GETMEM(arg, ptr, slen);
11473 if (ptr[slen-1] != NARG_SENTINEL)
11474 rb_raise(rb_eArgError, "return value overflowed string");
11475 ptr[slen-1] = '\0';
11476 }
11477
11478 return INT2NUM(retval);
11479}
11480
11481#ifdef HAVE_IOCTL
11482static VALUE
11483rb_ioctl(VALUE io, VALUE req, VALUE arg)
11484{
11485 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11486 rb_io_t *fptr;
11487 long narg;
11488 int retval;
11489
11490 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11491 GetOpenFile(io, fptr);
11492 retval = do_ioctl(fptr, cmd, narg);
11493 return finish_narg(retval, arg, fptr);
11494}
11495
11496/*
11497 * call-seq:
11498 * ioctl(integer_cmd, argument) -> integer
11499 *
11500 * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
11501 * which issues a low-level command to an I/O device.
11502 *
11503 * Issues a low-level command to an I/O device.
11504 * The arguments and returned value are platform-dependent.
11505 * The effect of the call is platform-dependent.
11506 *
11507 * If argument +argument+ is an integer, it is passed directly;
11508 * if it is a string, it is interpreted as a binary sequence of bytes.
11509 *
11510 * Not implemented on all platforms.
11511 *
11512 */
11513
11514static VALUE
11515rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11516{
11517 VALUE req, arg;
11518
11519 rb_scan_args(argc, argv, "11", &req, &arg);
11520 return rb_ioctl(io, req, arg);
11521}
11522#else
11523#define rb_io_ioctl rb_f_notimplement
11524#endif
11525
11526#ifdef HAVE_FCNTL
11527struct fcntl_arg {
11528 int fd;
11529 int cmd;
11530 long narg;
11531};
11532
11533static VALUE
11534nogvl_fcntl(void *ptr)
11535{
11536 struct fcntl_arg *arg = ptr;
11537
11538#if defined(F_DUPFD)
11539 if (arg->cmd == F_DUPFD)
11540 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11541#endif
11542 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11543}
11544
11545static int
11546do_fcntl(struct rb_io *io, int cmd, long narg)
11547{
11548 int retval;
11549 struct fcntl_arg arg;
11550
11551 arg.fd = io->fd;
11552 arg.cmd = cmd;
11553 arg.narg = narg;
11554
11555 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11556 if (retval != -1) {
11557 switch (cmd) {
11558#if defined(F_DUPFD)
11559 case F_DUPFD:
11560#endif
11561#if defined(F_DUPFD_CLOEXEC)
11562 case F_DUPFD_CLOEXEC:
11563#endif
11564 rb_update_max_fd(retval);
11565 }
11566 }
11567
11568 return retval;
11569}
11570
11571static VALUE
11572rb_fcntl(VALUE io, VALUE req, VALUE arg)
11573{
11574 int cmd = NUM2INT(req);
11575 rb_io_t *fptr;
11576 long narg;
11577 int retval;
11578
11579 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11580 GetOpenFile(io, fptr);
11581 retval = do_fcntl(fptr, cmd, narg);
11582 return finish_narg(retval, arg, fptr);
11583}
11584
11585/*
11586 * call-seq:
11587 * fcntl(integer_cmd, argument) -> integer
11588 *
11589 * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
11590 * which provides a mechanism for issuing low-level commands to control or query
11591 * a file-oriented I/O stream. Arguments and results are platform
11592 * dependent.
11593 *
11594 * If +argument+ is a number, its value is passed directly;
11595 * if it is a string, it is interpreted as a binary sequence of bytes.
11596 * (Array#pack might be a useful way to build this string.)
11597 *
11598 * Not implemented on all platforms.
11599 *
11600 */
11601
11602static VALUE
11603rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11604{
11605 VALUE req, arg;
11606
11607 rb_scan_args(argc, argv, "11", &req, &arg);
11608 return rb_fcntl(io, req, arg);
11609}
11610#else
11611#define rb_io_fcntl rb_f_notimplement
11612#endif
11613
11614#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11615/*
11616 * call-seq:
11617 * syscall(integer_callno, *arguments) -> integer
11618 *
11619 * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
11620 * which calls a specified function.
11621 *
11622 * Calls the operating system function identified by +integer_callno+;
11623 * returns the result of the function or raises SystemCallError if it failed.
11624 * The effect of the call is platform-dependent.
11625 * The arguments and returned value are platform-dependent.
11626 *
11627 * For each of +arguments+: if it is an integer, it is passed directly;
11628 * if it is a string, it is interpreted as a binary sequence of bytes.
11629 * There may be as many as nine such arguments.
11630 *
11631 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11632 * are platform-dependent.
11633 *
11634 * Note: Method +syscall+ is essentially unsafe and unportable.
11635 * The DL (Fiddle) library is preferred for safer and a bit
11636 * more portable programming.
11637 *
11638 * Not implemented on all platforms.
11639 *
11640 */
11641
11642static VALUE
11643rb_f_syscall(int argc, VALUE *argv, VALUE _)
11644{
11645 VALUE arg[8];
11646#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11647# define SYSCALL __syscall
11648# define NUM2SYSCALLID(x) NUM2LONG(x)
11649# define RETVAL2NUM(x) LONG2NUM(x)
11650# if SIZEOF_LONG == 8
11651 long num, retval = -1;
11652# elif SIZEOF_LONG_LONG == 8
11653 long long num, retval = -1;
11654# else
11655# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11656# endif
11657#elif defined(__linux__)
11658# define SYSCALL syscall
11659# define NUM2SYSCALLID(x) NUM2LONG(x)
11660# define RETVAL2NUM(x) LONG2NUM(x)
11661 /*
11662 * Linux man page says, syscall(2) function prototype is below.
11663 *
11664 * int syscall(int number, ...);
11665 *
11666 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11667 */
11668 long num, retval = -1;
11669#else
11670# define SYSCALL syscall
11671# define NUM2SYSCALLID(x) NUM2INT(x)
11672# define RETVAL2NUM(x) INT2NUM(x)
11673 int num, retval = -1;
11674#endif
11675 int i;
11676
11677 if (RTEST(ruby_verbose)) {
11679 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11680 }
11681
11682 if (argc == 0)
11683 rb_raise(rb_eArgError, "too few arguments for syscall");
11684 if (argc > numberof(arg))
11685 rb_raise(rb_eArgError, "too many arguments for syscall");
11686 num = NUM2SYSCALLID(argv[0]); ++argv;
11687 for (i = argc - 1; i--; ) {
11688 VALUE v = rb_check_string_type(argv[i]);
11689
11690 if (!NIL_P(v)) {
11691 StringValue(v);
11692 rb_str_modify(v);
11693 arg[i] = (VALUE)StringValueCStr(v);
11694 }
11695 else {
11696 arg[i] = (VALUE)NUM2LONG(argv[i]);
11697 }
11698 }
11699
11700 switch (argc) {
11701 case 1:
11702 retval = SYSCALL(num);
11703 break;
11704 case 2:
11705 retval = SYSCALL(num, arg[0]);
11706 break;
11707 case 3:
11708 retval = SYSCALL(num, arg[0],arg[1]);
11709 break;
11710 case 4:
11711 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11712 break;
11713 case 5:
11714 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11715 break;
11716 case 6:
11717 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11718 break;
11719 case 7:
11720 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11721 break;
11722 case 8:
11723 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11724 break;
11725 }
11726
11727 if (retval == -1)
11728 rb_sys_fail(0);
11729 return RETVAL2NUM(retval);
11730#undef SYSCALL
11731#undef NUM2SYSCALLID
11732#undef RETVAL2NUM
11733}
11734#else
11735#define rb_f_syscall rb_f_notimplement
11736#endif
11737
11738static VALUE
11739io_new_instance(VALUE args)
11740{
11741 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11742}
11743
11744static rb_encoding *
11745find_encoding(VALUE v)
11746{
11747 rb_encoding *enc = rb_find_encoding(v);
11748 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11749 return enc;
11750}
11751
11752static void
11753io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11754{
11755 rb_encoding *enc, *enc2;
11756 int ecflags = fptr->encs.ecflags;
11757 VALUE ecopts, tmp;
11758
11759 if (!NIL_P(v2)) {
11760 enc2 = find_encoding(v1);
11761 tmp = rb_check_string_type(v2);
11762 if (!NIL_P(tmp)) {
11763 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11764 /* Special case - "-" => no transcoding */
11765 enc = enc2;
11766 enc2 = NULL;
11767 }
11768 else
11769 enc = find_encoding(v2);
11770 if (enc == enc2) {
11771 /* Special case - "-" => no transcoding */
11772 enc2 = NULL;
11773 }
11774 }
11775 else {
11776 enc = find_encoding(v2);
11777 if (enc == enc2) {
11778 /* Special case - "-" => no transcoding */
11779 enc2 = NULL;
11780 }
11781 }
11782 if (enc2 == rb_ascii8bit_encoding()) {
11783 /* If external is ASCII-8BIT, no transcoding */
11784 enc = enc2;
11785 enc2 = NULL;
11786 }
11787 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11788 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11789 }
11790 else {
11791 if (NIL_P(v1)) {
11792 /* Set to default encodings */
11793 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11794 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11795 ecopts = Qnil;
11796 }
11797 else {
11798 tmp = rb_check_string_type(v1);
11799 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11800 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11801 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11802 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11803 }
11804 else {
11805 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11806 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11807 ecopts = Qnil;
11808 }
11809 }
11810 }
11811 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11812 fptr->encs.enc = enc;
11813 fptr->encs.enc2 = enc2;
11814 fptr->encs.ecflags = ecflags;
11815 fptr->encs.ecopts = ecopts;
11816 clear_codeconv(fptr);
11817
11818}
11819
11821 rb_io_t *fptr;
11822 VALUE v1;
11823 VALUE v2;
11824 VALUE opt;
11825};
11826
11827static VALUE
11828io_encoding_set_v(VALUE v)
11829{
11830 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11831 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11832 return Qnil;
11833}
11834
11835static VALUE
11836pipe_pair_close(VALUE rw)
11837{
11838 VALUE *rwp = (VALUE *)rw;
11839 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11840}
11841
11842/*
11843 * call-seq:
11844 * IO.pipe(**opts) -> [read_io, write_io]
11845 * IO.pipe(enc, **opts) -> [read_io, write_io]
11846 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11847 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11848 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11849 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11850 *
11851 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11852 * connected to each other.
11853 *
11854 * If argument +enc_string+ is given, it must be a string containing one of:
11855 *
11856 * - The name of the encoding to be used as the external encoding.
11857 * - The colon-separated names of two encodings to be used as the external
11858 * and internal encodings.
11859 *
11860 * If argument +int_enc+ is given, it must be an Encoding object
11861 * or encoding name string that specifies the internal encoding to be used;
11862 * if argument +ext_enc+ is also given, it must be an Encoding object
11863 * or encoding name string that specifies the external encoding to be used.
11864 *
11865 * The string read from +read_io+ is tagged with the external encoding;
11866 * if an internal encoding is also specified, the string is converted
11867 * to, and tagged with, that encoding.
11868 *
11869 * If any encoding is specified,
11870 * optional hash arguments specify the conversion option.
11871 *
11872 * Optional keyword arguments +opts+ specify:
11873 *
11874 * - {Open Options}[rdoc-ref:IO@Open+Options].
11875 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11876 *
11877 * With no block given, returns the two endpoints in an array:
11878 *
11879 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11880 *
11881 * With a block given, calls the block with the two endpoints;
11882 * closes both endpoints and returns the value of the block:
11883 *
11884 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11885 *
11886 * Output:
11887 *
11888 * #<IO:fd 6>
11889 * #<IO:fd 7>
11890 *
11891 * Not available on all platforms.
11892 *
11893 * In the example below, the two processes close the ends of the pipe
11894 * that they are not using. This is not just a cosmetic nicety. The
11895 * read end of a pipe will not generate an end of file condition if
11896 * there are any writers with the pipe still open. In the case of the
11897 * parent process, the <tt>rd.read</tt> will never return if it
11898 * does not first issue a <tt>wr.close</tt>:
11899 *
11900 * rd, wr = IO.pipe
11901 *
11902 * if fork
11903 * wr.close
11904 * puts "Parent got: <#{rd.read}>"
11905 * rd.close
11906 * Process.wait
11907 * else
11908 * rd.close
11909 * puts 'Sending message to parent'
11910 * wr.write "Hi Dad"
11911 * wr.close
11912 * end
11913 *
11914 * <em>produces:</em>
11915 *
11916 * Sending message to parent
11917 * Parent got: <Hi Dad>
11918 *
11919 */
11920
11921static VALUE
11922rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11923{
11924 int pipes[2], state;
11925 VALUE r, w, args[3], v1, v2;
11926 VALUE opt;
11927 rb_io_t *fptr, *fptr2;
11928 struct io_encoding_set_args ies_args;
11929 enum rb_io_mode fmode = 0;
11930 VALUE ret;
11931
11932 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11933 if (rb_pipe(pipes) < 0)
11934 rb_sys_fail(0);
11935
11936 args[0] = klass;
11937 args[1] = INT2NUM(pipes[0]);
11938 args[2] = INT2FIX(O_RDONLY);
11939 r = rb_protect(io_new_instance, (VALUE)args, &state);
11940 if (state) {
11941 close(pipes[0]);
11942 close(pipes[1]);
11943 rb_jump_tag(state);
11944 }
11945 GetOpenFile(r, fptr);
11946
11947 ies_args.fptr = fptr;
11948 ies_args.v1 = v1;
11949 ies_args.v2 = v2;
11950 ies_args.opt = opt;
11951 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11952 if (state) {
11953 close(pipes[1]);
11954 io_close(r);
11955 rb_jump_tag(state);
11956 }
11957
11958 args[1] = INT2NUM(pipes[1]);
11959 args[2] = INT2FIX(O_WRONLY);
11960 w = rb_protect(io_new_instance, (VALUE)args, &state);
11961 if (state) {
11962 close(pipes[1]);
11963 if (!NIL_P(r)) rb_io_close(r);
11964 rb_jump_tag(state);
11965 }
11966 GetOpenFile(w, fptr2);
11967 rb_io_synchronized(fptr2);
11968
11969 extract_binmode(opt, &fmode);
11970
11971 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11974 }
11975
11976#if DEFAULT_TEXTMODE
11977 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11978 fptr->mode &= ~FMODE_TEXTMODE;
11979 setmode(fptr->fd, O_BINARY);
11980 }
11981#if RUBY_CRLF_ENVIRONMENT
11984 }
11985#endif
11986#endif
11987 fptr->mode |= fmode;
11988#if DEFAULT_TEXTMODE
11989 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11990 fptr2->mode &= ~FMODE_TEXTMODE;
11991 setmode(fptr2->fd, O_BINARY);
11992 }
11993#endif
11994 fptr2->mode |= fmode;
11995
11996 ret = rb_assoc_new(r, w);
11997 if (rb_block_given_p()) {
11998 VALUE rw[2];
11999 rw[0] = r;
12000 rw[1] = w;
12001 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12002 }
12003 return ret;
12004}
12005
12007 int argc;
12008 VALUE *argv;
12009 VALUE io;
12010};
12011
12012static void
12013open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12014{
12015 VALUE path, v;
12016 VALUE vmode = Qnil, vperm = Qnil;
12017
12018 path = *argv++;
12019 argc--;
12020 FilePathValue(path);
12021 arg->io = 0;
12022 arg->argc = argc;
12023 arg->argv = argv;
12024 if (NIL_P(opt)) {
12025 vmode = INT2NUM(O_RDONLY);
12026 vperm = INT2FIX(0666);
12027 }
12028 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12029 int n;
12030
12031 v = rb_to_array_type(v);
12032 n = RARRAY_LENINT(v);
12033 rb_check_arity(n, 0, 3); /* rb_io_open */
12034 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12035 }
12036 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12037}
12038
12039static VALUE
12040io_s_foreach(VALUE v)
12041{
12042 struct getline_arg *arg = (void *)v;
12043 VALUE str;
12044
12045 if (arg->limit == 0)
12046 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12047 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12048 rb_lastline_set(str);
12049 rb_yield(str);
12050 }
12052 return Qnil;
12053}
12054
12055/*
12056 * call-seq:
12057 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12058 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12059 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12060 * IO.foreach(...) -> an_enumerator
12061 *
12062 * Calls the block with each successive line read from the stream.
12063 *
12064 * The first argument must be a string that is the path to a file.
12065 *
12066 * With only argument +path+ given, parses lines from the file at the given +path+,
12067 * as determined by the default line separator,
12068 * and calls the block with each successive line:
12069 *
12070 * File.foreach('t.txt') {|line| p line }
12071 *
12072 * Output: the same as above.
12073 *
12074 * For both forms, command and path, the remaining arguments are the same.
12075 *
12076 * With argument +sep+ given, parses lines as determined by that line separator
12077 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12078 *
12079 * File.foreach('t.txt', 'li') {|line| p line }
12080 *
12081 * Output:
12082 *
12083 * "First li"
12084 * "ne\nSecond li"
12085 * "ne\n\nThird li"
12086 * "ne\nFourth li"
12087 * "ne\n"
12088 *
12089 * Each paragraph:
12090 *
12091 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12092 *
12093 * Output:
12094 *
12095 * "First line\nSecond line\n\n"
12096 * "Third line\nFourth line\n"
12097 *
12098 * With argument +limit+ given, parses lines as determined by the default
12099 * line separator and the given line-length limit
12100 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12101 *
12102 * File.foreach('t.txt', 7) {|line| p line }
12103 *
12104 * Output:
12105 *
12106 * "First l"
12107 * "ine\n"
12108 * "Second "
12109 * "line\n"
12110 * "\n"
12111 * "Third l"
12112 * "ine\n"
12113 * "Fourth l"
12114 * "line\n"
12115 *
12116 * With arguments +sep+ and +limit+ given,
12117 * combines the two behaviors
12118 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12119 *
12120 * Optional keyword arguments +opts+ specify:
12121 *
12122 * - {Open Options}[rdoc-ref:IO@Open+Options].
12123 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12124 * - {Line Options}[rdoc-ref:IO@Line+IO].
12125 *
12126 * Returns an Enumerator if no block is given.
12127 *
12128 */
12129
12130static VALUE
12131rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12132{
12133 VALUE opt;
12134 int orig_argc = argc;
12135 struct foreach_arg arg;
12136 struct getline_arg garg;
12137
12138 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12139 RETURN_ENUMERATOR(self, orig_argc, argv);
12140 extract_getline_args(argc-1, argv+1, &garg);
12141 open_key_args(self, argc, argv, opt, &arg);
12142 if (NIL_P(arg.io)) return Qnil;
12143 extract_getline_opts(opt, &garg);
12144 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12145 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12146}
12147
12148static VALUE
12149io_s_readlines(VALUE v)
12150{
12151 struct getline_arg *arg = (void *)v;
12152 return io_readlines(arg, arg->io);
12153}
12154
12155/*
12156 * call-seq:
12157 * IO.readlines(path, sep = $/, **opts) -> array
12158 * IO.readlines(path, limit, **opts) -> array
12159 * IO.readlines(path, sep, limit, **opts) -> array
12160 *
12161 * Returns an array of all lines read from the stream.
12162 *
12163 * The first argument must be a string that is the path to a file.
12164 *
12165 * With only argument +path+ given, parses lines from the file at the given +path+,
12166 * as determined by the default line separator,
12167 * and returns those lines in an array:
12168 *
12169 * IO.readlines('t.txt')
12170 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12171 *
12172 * With argument +sep+ given, parses lines as determined by that line separator
12173 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12174 *
12175 * # Ordinary separator.
12176 * IO.readlines('t.txt', 'li')
12177 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12178 * # Get-paragraphs separator.
12179 * IO.readlines('t.txt', '')
12180 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12181 * # Get-all separator.
12182 * IO.readlines('t.txt', nil)
12183 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12184 *
12185 * With argument +limit+ given, parses lines as determined by the default
12186 * line separator and the given line-length limit
12187 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12188 *
12189 * IO.readlines('t.txt', 7)
12190 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12191 *
12192 * With arguments +sep+ and +limit+ given,
12193 * combines the two behaviors
12194 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12195 *
12196 * Optional keyword arguments +opts+ specify:
12197 *
12198 * - {Open Options}[rdoc-ref:IO@Open+Options].
12199 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12200 * - {Line Options}[rdoc-ref:IO@Line+IO].
12201 *
12202 */
12203
12204static VALUE
12205rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12206{
12207 VALUE opt;
12208 struct foreach_arg arg;
12209 struct getline_arg garg;
12210
12211 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12212 extract_getline_args(argc-1, argv+1, &garg);
12213 open_key_args(io, argc, argv, opt, &arg);
12214 if (NIL_P(arg.io)) return Qnil;
12215 extract_getline_opts(opt, &garg);
12216 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12217 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12218}
12219
12220static VALUE
12221io_s_read(VALUE v)
12222{
12223 struct foreach_arg *arg = (void *)v;
12224 return io_read(arg->argc, arg->argv, arg->io);
12225}
12226
12227struct seek_arg {
12228 VALUE io;
12229 VALUE offset;
12230 int mode;
12231};
12232
12233static VALUE
12234seek_before_access(VALUE argp)
12235{
12236 struct seek_arg *arg = (struct seek_arg *)argp;
12237 rb_io_binmode(arg->io);
12238 return rb_io_seek(arg->io, arg->offset, arg->mode);
12239}
12240
12241/*
12242 * call-seq:
12243 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12244 *
12245 * Opens the stream, reads and returns some or all of its content,
12246 * and closes the stream; returns +nil+ if no bytes were read.
12247 *
12248 * The first argument must be a string that is the path to a file.
12249 *
12250 * With only argument +path+ given, reads in text mode and returns the entire content
12251 * of the file at the given path:
12252 *
12253 * File.read('t.txt')
12254 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
12255 * File.read('t.ja')
12256 * # => "こんにちは"
12257 * File.read('t.dat')
12258 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12259 *
12260 * On Windows, text mode can terminate reading and leave bytes in the file
12261 * unread when encountering certain special bytes. Consider using
12262 * IO.binread if all bytes in the file should be read.
12263 *
12264 * With argument +length+, returns +length+ bytes if available:
12265 *
12266 * File.read('t.txt', 7)
12267 * # => "First l"
12268 * File.read('t.ja', 7)
12269 * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
12270 * File.read('t.dat', 7)
12271 * # => "\xFE\xFF\x99\x90\x99\x91\x99"
12272 *
12273 * Returns all bytes if +length+ is larger than the files size:
12274 *
12275 * File.read('t.txt', 700)
12276 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12277 * File.read('t.ja', 700)
12278 * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
12279 * File.read('t.dat', 700)
12280 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12281 *
12282 * With arguments +length+ and +offset+, returns +length+ bytes
12283 * if available, beginning at the given +offset+:
12284 *
12285 * File.read('t.txt', 10, 2)
12286 * # => "rst line\r\n"
12287 * File.read('t.ja', 10, 2)
12288 * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
12289 * File.read('t.dat', 10, 2)
12290 * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12291 *
12292 * Returns +nil+ if +offset+ is past the end of the stream:
12293 *
12294 * File.read('t.txt', 10, 200)
12295 * # => nil
12296 *
12297 * Optional keyword arguments +opts+ specify:
12298 *
12299 * - {Open Options}[rdoc-ref:IO@Open+Options].
12300 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12301 *
12302 */
12303
12304static VALUE
12305rb_io_s_read(int argc, VALUE *argv, VALUE io)
12306{
12307 VALUE opt, offset;
12308 long off;
12309 struct foreach_arg arg;
12310
12311 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12312 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12313 rb_raise(rb_eArgError, "negative offset %ld given", off);
12314 }
12315 open_key_args(io, argc, argv, opt, &arg);
12316 if (NIL_P(arg.io)) return Qnil;
12317 if (!NIL_P(offset)) {
12318 struct seek_arg sarg;
12319 int state = 0;
12320 sarg.io = arg.io;
12321 sarg.offset = offset;
12322 sarg.mode = SEEK_SET;
12323 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12324 if (state) {
12325 rb_io_close(arg.io);
12326 rb_jump_tag(state);
12327 }
12328 if (arg.argc == 2) arg.argc = 1;
12329 }
12330 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12331}
12332
12333/*
12334 * call-seq:
12335 * IO.binread(path, length = nil, offset = 0) -> string or nil
12336 *
12337 * Behaves like IO.read, except that the stream is opened in binary mode
12338 * with ASCII-8BIT encoding.
12339 *
12340 */
12341
12342static VALUE
12343rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12344{
12345 VALUE offset;
12346 struct foreach_arg arg;
12347 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12348 enum {
12349 oflags = O_RDONLY
12350#ifdef O_BINARY
12351 |O_BINARY
12352#endif
12353 };
12354 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12355
12356 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12357 FilePathValue(argv[0]);
12358 convconfig.enc = rb_ascii8bit_encoding();
12359 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12360 if (NIL_P(arg.io)) return Qnil;
12361 arg.argv = argv+1;
12362 arg.argc = (argc > 1) ? 1 : 0;
12363 if (!NIL_P(offset)) {
12364 struct seek_arg sarg;
12365 int state = 0;
12366 sarg.io = arg.io;
12367 sarg.offset = offset;
12368 sarg.mode = SEEK_SET;
12369 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12370 if (state) {
12371 rb_io_close(arg.io);
12372 rb_jump_tag(state);
12373 }
12374 }
12375 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12376}
12377
12378static VALUE
12379io_s_write0(VALUE v)
12380{
12381 struct write_arg *arg = (void *)v;
12382 return io_write(arg->io,arg->str,arg->nosync);
12383}
12384
12385static VALUE
12386io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12387{
12388 VALUE string, offset, opt;
12389 struct foreach_arg arg;
12390 struct write_arg warg;
12391
12392 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12393
12394 if (NIL_P(opt)) opt = rb_hash_new();
12395 else opt = rb_hash_dup(opt);
12396
12397
12398 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12399 int mode = O_WRONLY|O_CREAT;
12400#ifdef O_BINARY
12401 if (binary) mode |= O_BINARY;
12402#endif
12403 if (NIL_P(offset)) mode |= O_TRUNC;
12404 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12405 }
12406 open_key_args(klass, argc, argv, opt, &arg);
12407
12408#ifndef O_BINARY
12409 if (binary) rb_io_binmode_m(arg.io);
12410#endif
12411
12412 if (NIL_P(arg.io)) return Qnil;
12413 if (!NIL_P(offset)) {
12414 struct seek_arg sarg;
12415 int state = 0;
12416 sarg.io = arg.io;
12417 sarg.offset = offset;
12418 sarg.mode = SEEK_SET;
12419 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12420 if (state) {
12421 rb_io_close(arg.io);
12422 rb_jump_tag(state);
12423 }
12424 }
12425
12426 warg.io = arg.io;
12427 warg.str = string;
12428 warg.nosync = 0;
12429
12430 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12431}
12432
12433/*
12434 * call-seq:
12435 * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
12436 *
12437 * Opens the stream, writes the given +data+ to it,
12438 * and closes the stream; returns the number of bytes written.
12439 *
12440 * The first argument must be a string that is the path to a file.
12441 *
12442 * With only arguments +path+ and +data+ given,
12443 * writes the given data to the file at that path:
12444 *
12445 * path = 't.tmp'
12446 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
12447 * File.write(path, 'こんにちは') # => 15
12448 * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
12449 *
12450 * When +offset+ is zero (the default), the entire file content is overwritten:
12451 *
12452 * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12453 * File.write(path, 'foo')
12454 * File.read(path) # => "foo"
12455 *
12456 * When +offset+ in within the file content, the file content is partly overwritten,
12457 * beginning at byte +offset+:
12458 *
12459 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12460 * File.write(path, 'LINE', 6)
12461 * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
12462 *
12463 * When the file contains multi-byte characters,
12464 * the effect of writing may disturb some characters:
12465 *
12466 * File.write(path, "こんにちは")
12467 * File.write(path, 'FOO', 3) # Replace one 3-byte character.
12468 * File.read(path) # => "こFOOにちは"
12469 * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
12470 * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
12471 *
12472 * If +offset+ is outside the file content,
12473 * the file is padded with null characters <tt>"\u0000"</tt>:
12474 *
12475 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12476 * File.write(path, 'FOO', 55)
12477 * File.read(path)
12478 * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
12479 *
12480 * Optional keyword arguments +opts+ specify:
12481 *
12482 * - {Open Options}[rdoc-ref:IO@Open+Options].
12483 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12484 *
12485 */
12486
12487static VALUE
12488rb_io_s_write(int argc, VALUE *argv, VALUE io)
12489{
12490 return io_s_write(argc, argv, io, 0);
12491}
12492
12493/*
12494 * call-seq:
12495 * IO.binwrite(path, string, offset = 0, **opts) -> integer
12496 *
12497 * Behaves like IO.write, except that the stream is opened in binary mode
12498 * with ASCII-8BIT encoding.
12499 *
12500 */
12501
12502static VALUE
12503rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12504{
12505 return io_s_write(argc, argv, io, 1);
12506}
12507
12509 VALUE src;
12510 VALUE dst;
12511 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12512 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12513
12514 rb_io_t *src_fptr;
12515 rb_io_t *dst_fptr;
12516 unsigned close_src : 1;
12517 unsigned close_dst : 1;
12518 int error_no;
12519 rb_off_t total;
12520 const char *syserr;
12521 const char *notimp;
12522 VALUE th;
12523 struct stat src_stat;
12524 struct stat dst_stat;
12525#ifdef HAVE_FCOPYFILE
12526 copyfile_state_t copyfile_state;
12527#endif
12528};
12529
12530static void *
12531exec_interrupts(void *arg)
12532{
12533 VALUE th = (VALUE)arg;
12534 rb_thread_execute_interrupts(th);
12535 return NULL;
12536}
12537
12538/*
12539 * returns TRUE if the preceding system call was interrupted
12540 * so we can continue. If the thread was interrupted, we
12541 * reacquire the GVL to execute interrupts before continuing.
12542 */
12543static int
12544maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12545{
12546 switch (errno) {
12547 case EINTR:
12548#if defined(ERESTART)
12549 case ERESTART:
12550#endif
12551 if (rb_thread_interrupted(stp->th)) {
12552 if (has_gvl)
12553 rb_thread_execute_interrupts(stp->th);
12554 else
12555 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12556 }
12557 return TRUE;
12558 }
12559 return FALSE;
12560}
12561
12563 VALUE scheduler;
12564
12565 rb_io_t *fptr;
12566 short events;
12567
12568 VALUE result;
12569};
12570
12571static void *
12572fiber_scheduler_wait_for(void * _arguments)
12573{
12574 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12575
12576 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12577
12578 return NULL;
12579}
12580
12581#if USE_POLL
12582# define IOWAIT_SYSCALL "poll"
12583STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12584STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12585static int
12586nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12587{
12589 if (scheduler != Qnil) {
12590 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12591 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12592 return RTEST(args.result);
12593 }
12594
12595 int fd = fptr->fd;
12596 if (fd == -1) return 0;
12597
12598 struct pollfd fds;
12599
12600 fds.fd = fd;
12601 fds.events = events;
12602
12603 int timeout_milliseconds = -1;
12604
12605 if (timeout) {
12606 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12607 }
12608
12609 return poll(&fds, 1, timeout_milliseconds);
12610}
12611#else /* !USE_POLL */
12612# define IOWAIT_SYSCALL "select"
12613static int
12614nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12615{
12617 if (scheduler != Qnil) {
12618 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12619 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12620 return RTEST(args.result);
12621 }
12622
12623 int fd = fptr->fd;
12624
12625 if (fd == -1) {
12626 errno = EBADF;
12627 return -1;
12628 }
12629
12630 rb_fdset_t fds;
12631 int ret;
12632
12633 rb_fd_init(&fds);
12634 rb_fd_set(fd, &fds);
12635
12636 switch (events) {
12637 case RB_WAITFD_IN:
12638 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12639 break;
12640 case RB_WAITFD_OUT:
12641 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12642 break;
12643 default:
12644 VM_UNREACHABLE(nogvl_wait_for);
12645 }
12646
12647 rb_fd_term(&fds);
12648
12649 // On timeout, this returns 0.
12650 return ret;
12651}
12652#endif /* !USE_POLL */
12653
12654static int
12655maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12656{
12657 int ret;
12658
12659 do {
12660 if (has_gvl) {
12662 }
12663 else {
12664 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12665 }
12666 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12667
12668 if (ret < 0) {
12669 stp->syserr = IOWAIT_SYSCALL;
12670 stp->error_no = errno;
12671 return ret;
12672 }
12673 return 0;
12674}
12675
12676static int
12677nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12678{
12679 int ret;
12680
12681 do {
12682 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12683 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12684
12685 if (ret < 0) {
12686 stp->syserr = IOWAIT_SYSCALL;
12687 stp->error_no = errno;
12688 return ret;
12689 }
12690 return 0;
12691}
12692
12693#ifdef USE_COPY_FILE_RANGE
12694
12695static ssize_t
12696simple_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)
12697{
12698#ifdef HAVE_COPY_FILE_RANGE
12699 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12700#else
12701 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12702#endif
12703}
12704
12705static int
12706nogvl_copy_file_range(struct copy_stream_struct *stp)
12707{
12708 ssize_t ss;
12709 rb_off_t src_size;
12710 rb_off_t copy_length, src_offset, *src_offset_ptr;
12711
12712 if (!S_ISREG(stp->src_stat.st_mode))
12713 return 0;
12714
12715 src_size = stp->src_stat.st_size;
12716 src_offset = stp->src_offset;
12717 if (src_offset >= (rb_off_t)0) {
12718 src_offset_ptr = &src_offset;
12719 }
12720 else {
12721 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12722 }
12723
12724 copy_length = stp->copy_length;
12725 if (copy_length < (rb_off_t)0) {
12726 if (src_offset < (rb_off_t)0) {
12727 rb_off_t current_offset;
12728 errno = 0;
12729 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12730 if (current_offset < (rb_off_t)0 && errno) {
12731 stp->syserr = "lseek";
12732 stp->error_no = errno;
12733 return (int)current_offset;
12734 }
12735 copy_length = src_size - current_offset;
12736 }
12737 else {
12738 copy_length = src_size - src_offset;
12739 }
12740 }
12741
12742 retry_copy_file_range:
12743# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12744 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12745 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12746# else
12747 ss = (ssize_t)copy_length;
12748# endif
12749 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12750 if (0 < ss) {
12751 stp->total += ss;
12752 copy_length -= ss;
12753 if (0 < copy_length) {
12754 goto retry_copy_file_range;
12755 }
12756 }
12757 if (ss < 0) {
12758 if (maygvl_copy_stream_continue_p(0, stp)) {
12759 goto retry_copy_file_range;
12760 }
12761 switch (errno) {
12762 case EINVAL:
12763 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12764 docker container) */
12765#ifdef ENOSYS
12766 case ENOSYS:
12767#endif
12768#ifdef EXDEV
12769 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12770#endif
12771 return 0;
12772 case EAGAIN:
12773#if EWOULDBLOCK != EAGAIN
12774 case EWOULDBLOCK:
12775#endif
12776 {
12777 int ret = nogvl_copy_stream_wait_write(stp);
12778 if (ret < 0) return ret;
12779 }
12780 goto retry_copy_file_range;
12781 case EBADF:
12782 {
12783 int e = errno;
12784 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12785
12786 if (flags != -1 && flags & O_APPEND) {
12787 return 0;
12788 }
12789 errno = e;
12790 }
12791 }
12792 stp->syserr = "copy_file_range";
12793 stp->error_no = errno;
12794 return (int)ss;
12795 }
12796 return 1;
12797}
12798#endif
12799
12800#ifdef HAVE_FCOPYFILE
12801static int
12802nogvl_fcopyfile(struct copy_stream_struct *stp)
12803{
12804 rb_off_t cur, ss = 0;
12805 const rb_off_t src_offset = stp->src_offset;
12806 int ret;
12807
12808 if (stp->copy_length >= (rb_off_t)0) {
12809 /* copy_length can't be specified in fcopyfile(3) */
12810 return 0;
12811 }
12812
12813 if (!S_ISREG(stp->src_stat.st_mode))
12814 return 0;
12815
12816 if (!S_ISREG(stp->dst_stat.st_mode))
12817 return 0;
12818 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12819 return 0;
12820 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12821 /* fcopyfile(3) appends src IO to dst IO and then truncates
12822 * dst IO to src IO's original size. */
12823 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12824 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12825 if (end > (rb_off_t)0) return 0;
12826 }
12827
12828 if (src_offset > (rb_off_t)0) {
12829 rb_off_t r;
12830
12831 /* get current offset */
12832 errno = 0;
12833 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12834 if (cur < (rb_off_t)0 && errno) {
12835 stp->error_no = errno;
12836 return 1;
12837 }
12838
12839 errno = 0;
12840 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12841 if (r < (rb_off_t)0 && errno) {
12842 stp->error_no = errno;
12843 return 1;
12844 }
12845 }
12846
12847 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12848 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12849 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12850
12851 if (ret == 0) { /* success */
12852 stp->total = ss;
12853 if (src_offset > (rb_off_t)0) {
12854 rb_off_t r;
12855 errno = 0;
12856 /* reset offset */
12857 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12858 if (r < (rb_off_t)0 && errno) {
12859 stp->error_no = errno;
12860 return 1;
12861 }
12862 }
12863 }
12864 else {
12865 switch (errno) {
12866 case ENOTSUP:
12867 case EPERM:
12868 case EINVAL:
12869 return 0;
12870 }
12871 stp->syserr = "fcopyfile";
12872 stp->error_no = errno;
12873 return (int)ret;
12874 }
12875 return 1;
12876}
12877#endif
12878
12879#ifdef HAVE_SENDFILE
12880
12881# ifdef __linux__
12882# define USE_SENDFILE
12883
12884# ifdef HAVE_SYS_SENDFILE_H
12885# include <sys/sendfile.h>
12886# endif
12887
12888static ssize_t
12889simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12890{
12891 return sendfile(out_fd, in_fd, offset, (size_t)count);
12892}
12893
12894# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12895/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12896 * without cpuset -l 0.
12897 */
12898# define USE_SENDFILE
12899
12900static ssize_t
12901simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12902{
12903 int r;
12904 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12905 rb_off_t sbytes;
12906# ifdef __APPLE__
12907 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12908 sbytes = count;
12909# else
12910 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12911# endif
12912 if (r != 0 && sbytes == 0) return r;
12913 if (offset) {
12914 *offset += sbytes;
12915 }
12916 else {
12917 lseek(in_fd, sbytes, SEEK_CUR);
12918 }
12919 return (ssize_t)sbytes;
12920}
12921
12922# endif
12923
12924#endif
12925
12926#ifdef USE_SENDFILE
12927static int
12928nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12929{
12930 ssize_t ss;
12931 rb_off_t src_size;
12932 rb_off_t copy_length;
12933 rb_off_t src_offset;
12934 int use_pread;
12935
12936 if (!S_ISREG(stp->src_stat.st_mode))
12937 return 0;
12938
12939 src_size = stp->src_stat.st_size;
12940#ifndef __linux__
12941 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12942 return 0;
12943#endif
12944
12945 src_offset = stp->src_offset;
12946 use_pread = src_offset >= (rb_off_t)0;
12947
12948 copy_length = stp->copy_length;
12949 if (copy_length < (rb_off_t)0) {
12950 if (use_pread)
12951 copy_length = src_size - src_offset;
12952 else {
12953 rb_off_t cur;
12954 errno = 0;
12955 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12956 if (cur < (rb_off_t)0 && errno) {
12957 stp->syserr = "lseek";
12958 stp->error_no = errno;
12959 return (int)cur;
12960 }
12961 copy_length = src_size - cur;
12962 }
12963 }
12964
12965 retry_sendfile:
12966# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12967 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12968 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12969# else
12970 ss = (ssize_t)copy_length;
12971# endif
12972 if (use_pread) {
12973 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12974 }
12975 else {
12976 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12977 }
12978 if (0 < ss) {
12979 stp->total += ss;
12980 copy_length -= ss;
12981 if (0 < copy_length) {
12982 goto retry_sendfile;
12983 }
12984 }
12985 if (ss < 0) {
12986 if (maygvl_copy_stream_continue_p(0, stp))
12987 goto retry_sendfile;
12988 switch (errno) {
12989 case EINVAL:
12990#ifdef ENOSYS
12991 case ENOSYS:
12992#endif
12993#ifdef EOPNOTSUP
12994 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12995 see also: [Feature #16965] */
12996 case EOPNOTSUP:
12997#endif
12998 return 0;
12999 case EAGAIN:
13000#if EWOULDBLOCK != EAGAIN
13001 case EWOULDBLOCK:
13002#endif
13003 {
13004 int ret;
13005#ifndef __linux__
13006 /*
13007 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13008 * select() reports regular files to always be "ready", so
13009 * there is no need to select() on it.
13010 * Other OSes may have the same limitation for sendfile() which
13011 * allow us to bypass maygvl_copy_stream_wait_read()...
13012 */
13013 ret = maygvl_copy_stream_wait_read(0, stp);
13014 if (ret < 0) return ret;
13015#endif
13016 ret = nogvl_copy_stream_wait_write(stp);
13017 if (ret < 0) return ret;
13018 }
13019 goto retry_sendfile;
13020 }
13021 stp->syserr = "sendfile";
13022 stp->error_no = errno;
13023 return (int)ss;
13024 }
13025 return 1;
13026}
13027#endif
13028
13029static ssize_t
13030maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13031{
13032 if (has_gvl)
13033 return rb_io_read_memory(fptr, buf, count);
13034 else
13035 return read(fptr->fd, buf, count);
13036}
13037
13038static ssize_t
13039maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13040{
13041 ssize_t ss;
13042 retry_read:
13043 if (offset < (rb_off_t)0) {
13044 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13045 }
13046 else {
13047 ss = pread(stp->src_fptr->fd, buf, len, offset);
13048 }
13049 if (ss == 0) {
13050 return 0;
13051 }
13052 if (ss < 0) {
13053 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13054 goto retry_read;
13055 switch (errno) {
13056 case EAGAIN:
13057#if EWOULDBLOCK != EAGAIN
13058 case EWOULDBLOCK:
13059#endif
13060 {
13061 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13062 if (ret < 0) return ret;
13063 }
13064 goto retry_read;
13065#ifdef ENOSYS
13066 case ENOSYS:
13067 stp->notimp = "pread";
13068 return ss;
13069#endif
13070 }
13071 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13072 stp->error_no = errno;
13073 }
13074 return ss;
13075}
13076
13077static int
13078nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13079{
13080 ssize_t ss;
13081 int off = 0;
13082 while (len) {
13083 ss = write(stp->dst_fptr->fd, buf+off, len);
13084 if (ss < 0) {
13085 if (maygvl_copy_stream_continue_p(0, stp))
13086 continue;
13087 if (io_again_p(errno)) {
13088 int ret = nogvl_copy_stream_wait_write(stp);
13089 if (ret < 0) return ret;
13090 continue;
13091 }
13092 stp->syserr = "write";
13093 stp->error_no = errno;
13094 return (int)ss;
13095 }
13096 off += (int)ss;
13097 len -= (int)ss;
13098 stp->total += ss;
13099 }
13100 return 0;
13101}
13102
13103static void
13104nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13105{
13106 char buf[1024*16];
13107 size_t len;
13108 ssize_t ss;
13109 int ret;
13110 rb_off_t copy_length;
13111 rb_off_t src_offset;
13112 int use_eof;
13113 int use_pread;
13114
13115 copy_length = stp->copy_length;
13116 use_eof = copy_length < (rb_off_t)0;
13117 src_offset = stp->src_offset;
13118 use_pread = src_offset >= (rb_off_t)0;
13119
13120 if (use_pread && stp->close_src) {
13121 rb_off_t r;
13122 errno = 0;
13123 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13124 if (r < (rb_off_t)0 && errno) {
13125 stp->syserr = "lseek";
13126 stp->error_no = errno;
13127 return;
13128 }
13129 src_offset = (rb_off_t)-1;
13130 use_pread = 0;
13131 }
13132
13133 while (use_eof || 0 < copy_length) {
13134 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13135 len = (size_t)copy_length;
13136 }
13137 else {
13138 len = sizeof(buf);
13139 }
13140 if (use_pread) {
13141 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13142 if (0 < ss)
13143 src_offset += ss;
13144 }
13145 else {
13146 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13147 }
13148 if (ss <= 0) /* EOF or error */
13149 return;
13150
13151 ret = nogvl_copy_stream_write(stp, buf, ss);
13152 if (ret < 0)
13153 return;
13154
13155 if (!use_eof)
13156 copy_length -= ss;
13157 }
13158}
13159
13160static void *
13161nogvl_copy_stream_func(void *arg)
13162{
13163 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13164#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13165 int ret;
13166#endif
13167
13168#ifdef USE_COPY_FILE_RANGE
13169 ret = nogvl_copy_file_range(stp);
13170 if (ret != 0)
13171 goto finish; /* error or success */
13172#endif
13173
13174#ifdef HAVE_FCOPYFILE
13175 ret = nogvl_fcopyfile(stp);
13176 if (ret != 0)
13177 goto finish; /* error or success */
13178#endif
13179
13180#ifdef USE_SENDFILE
13181 ret = nogvl_copy_stream_sendfile(stp);
13182 if (ret != 0)
13183 goto finish; /* error or success */
13184#endif
13185
13186 nogvl_copy_stream_read_write(stp);
13187
13188#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13189 finish:
13190#endif
13191 return 0;
13192}
13193
13194static VALUE
13195copy_stream_fallback_body(VALUE arg)
13196{
13197 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13198 const int buflen = 16*1024;
13199 VALUE n;
13200 VALUE buf = rb_str_buf_new(buflen);
13201 rb_off_t rest = stp->copy_length;
13202 rb_off_t off = stp->src_offset;
13203 ID read_method = id_readpartial;
13204
13205 if (!stp->src_fptr) {
13206 if (!rb_respond_to(stp->src, read_method)) {
13207 read_method = id_read;
13208 }
13209 }
13210
13211 while (1) {
13212 long numwrote;
13213 long l;
13214 rb_str_make_independent(buf);
13215 if (stp->copy_length < (rb_off_t)0) {
13216 l = buflen;
13217 }
13218 else {
13219 if (rest == 0) {
13220 rb_str_resize(buf, 0);
13221 break;
13222 }
13223 l = buflen < rest ? buflen : (long)rest;
13224 }
13225 if (!stp->src_fptr) {
13226 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13227
13228 if (read_method == id_read && NIL_P(rc))
13229 break;
13230 }
13231 else {
13232 ssize_t ss;
13233 rb_str_resize(buf, buflen);
13234 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13235 rb_str_resize(buf, ss > 0 ? ss : 0);
13236 if (ss < 0)
13237 return Qnil;
13238 if (ss == 0)
13239 rb_eof_error();
13240 if (off >= (rb_off_t)0)
13241 off += ss;
13242 }
13243 n = rb_io_write(stp->dst, buf);
13244 numwrote = NUM2LONG(n);
13245 stp->total += numwrote;
13246 rest -= numwrote;
13247 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13248 break;
13249 }
13250 }
13251
13252 return Qnil;
13253}
13254
13255static VALUE
13256copy_stream_fallback(struct copy_stream_struct *stp)
13257{
13258 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13259 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13260 }
13261 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13262 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13263 rb_eEOFError, (VALUE)0);
13264 return Qnil;
13265}
13266
13267static VALUE
13268copy_stream_body(VALUE arg)
13269{
13270 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13271 VALUE src_io = stp->src, dst_io = stp->dst;
13272 const int common_oflags = 0
13273#ifdef O_NOCTTY
13274 | O_NOCTTY
13275#endif
13276 ;
13277
13278 stp->th = rb_thread_current();
13279
13280 stp->total = 0;
13281
13282 if (src_io == argf ||
13283 !(RB_TYPE_P(src_io, T_FILE) ||
13284 RB_TYPE_P(src_io, T_STRING) ||
13285 rb_respond_to(src_io, rb_intern("to_path")))) {
13286 stp->src_fptr = NULL;
13287 }
13288 else {
13289 int stat_ret;
13290 VALUE tmp_io = rb_io_check_io(src_io);
13291 if (!NIL_P(tmp_io)) {
13292 src_io = tmp_io;
13293 }
13294 else if (!RB_TYPE_P(src_io, T_FILE)) {
13295 VALUE args[2];
13296 FilePathValue(src_io);
13297 args[0] = src_io;
13298 args[1] = INT2NUM(O_RDONLY|common_oflags);
13299 src_io = rb_class_new_instance(2, args, rb_cFile);
13300 stp->src = src_io;
13301 stp->close_src = 1;
13302 }
13303 RB_IO_POINTER(src_io, stp->src_fptr);
13304 rb_io_check_byte_readable(stp->src_fptr);
13305
13306 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13307 if (stat_ret < 0) {
13308 stp->syserr = "fstat";
13309 stp->error_no = errno;
13310 return Qnil;
13311 }
13312 }
13313
13314 if (dst_io == argf ||
13315 !(RB_TYPE_P(dst_io, T_FILE) ||
13316 RB_TYPE_P(dst_io, T_STRING) ||
13317 rb_respond_to(dst_io, rb_intern("to_path")))) {
13318 stp->dst_fptr = NULL;
13319 }
13320 else {
13321 int stat_ret;
13322 VALUE tmp_io = rb_io_check_io(dst_io);
13323 if (!NIL_P(tmp_io)) {
13324 dst_io = GetWriteIO(tmp_io);
13325 }
13326 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13327 VALUE args[3];
13328 FilePathValue(dst_io);
13329 args[0] = dst_io;
13330 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13331 args[2] = INT2FIX(0666);
13332 dst_io = rb_class_new_instance(3, args, rb_cFile);
13333 stp->dst = dst_io;
13334 stp->close_dst = 1;
13335 }
13336 else {
13337 dst_io = GetWriteIO(dst_io);
13338 stp->dst = dst_io;
13339 }
13340 RB_IO_POINTER(dst_io, stp->dst_fptr);
13341 rb_io_check_writable(stp->dst_fptr);
13342
13343 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13344 if (stat_ret < 0) {
13345 stp->syserr = "fstat";
13346 stp->error_no = errno;
13347 return Qnil;
13348 }
13349 }
13350
13351#ifdef O_BINARY
13352 if (stp->src_fptr)
13353 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13354#endif
13355 if (stp->dst_fptr)
13356 io_ascii8bit_binmode(stp->dst_fptr);
13357
13358 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13359 size_t len = stp->src_fptr->rbuf.len;
13360 VALUE str;
13361 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13362 len = (size_t)stp->copy_length;
13363 }
13364 str = rb_str_buf_new(len);
13365 rb_str_resize(str,len);
13366 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13367 if (stp->dst_fptr) { /* IO or filename */
13368 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13369 rb_sys_fail_on_write(stp->dst_fptr);
13370 }
13371 else /* others such as StringIO */
13372 rb_io_write(dst_io, str);
13373 rb_str_resize(str, 0);
13374 stp->total += len;
13375 if (stp->copy_length >= (rb_off_t)0)
13376 stp->copy_length -= len;
13377 }
13378
13379 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13380 rb_raise(rb_eIOError, "flush failed");
13381 }
13382
13383 if (stp->copy_length == 0)
13384 return Qnil;
13385
13386 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13387 return copy_stream_fallback(stp);
13388 }
13389
13390 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13391 return Qnil;
13392}
13393
13394static VALUE
13395copy_stream_finalize(VALUE arg)
13396{
13397 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13398
13399#ifdef HAVE_FCOPYFILE
13400 if (stp->copyfile_state) {
13401 copyfile_state_free(stp->copyfile_state);
13402 }
13403#endif
13404
13405 if (stp->close_src) {
13406 rb_io_close_m(stp->src);
13407 }
13408 if (stp->close_dst) {
13409 rb_io_close_m(stp->dst);
13410 }
13411 if (stp->syserr) {
13412 rb_syserr_fail(stp->error_no, stp->syserr);
13413 }
13414 if (stp->notimp) {
13415 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13416 }
13417 return Qnil;
13418}
13419
13420/*
13421 * call-seq:
13422 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13423 *
13424 * Copies from the given +src+ to the given +dst+,
13425 * returning the number of bytes copied.
13426 *
13427 * - The given +src+ must be one of the following:
13428 *
13429 * - The path to a readable file, from which source data is to be read.
13430 * - An \IO-like object, opened for reading and capable of responding
13431 * to method +:readpartial+ or method +:read+.
13432 *
13433 * - The given +dst+ must be one of the following:
13434 *
13435 * - The path to a writable file, to which data is to be written.
13436 * - An \IO-like object, opened for writing and capable of responding
13437 * to method +:write+.
13438 *
13439 * The examples here use file <tt>t.txt</tt> as source:
13440 *
13441 * File.read('t.txt')
13442 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13443 * File.read('t.txt').size # => 47
13444 *
13445 * If only arguments +src+ and +dst+ are given,
13446 * the entire source stream is copied:
13447 *
13448 * # Paths.
13449 * IO.copy_stream('t.txt', 't.tmp') # => 47
13450 *
13451 * # IOs (recall that a File is also an IO).
13452 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13453 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13454 * IO.copy_stream(src_io, dst_io) # => 47
13455 * src_io.close
13456 * dst_io.close
13457 *
13458 * With argument +src_length+ a non-negative integer,
13459 * no more than that many bytes are copied:
13460 *
13461 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13462 * File.read('t.tmp') # => "First line"
13463 *
13464 * With argument +src_offset+ also given,
13465 * the source stream is read beginning at that offset:
13466 *
13467 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13468 * IO.read('t.tmp') # => "Second line"
13469 *
13470 */
13471static VALUE
13472rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13473{
13474 VALUE src, dst, length, src_offset;
13475 struct copy_stream_struct st;
13476
13477 MEMZERO(&st, struct copy_stream_struct, 1);
13478
13479 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13480
13481 st.src = src;
13482 st.dst = dst;
13483
13484 st.src_fptr = NULL;
13485 st.dst_fptr = NULL;
13486
13487 if (NIL_P(length))
13488 st.copy_length = (rb_off_t)-1;
13489 else
13490 st.copy_length = NUM2OFFT(length);
13491
13492 if (NIL_P(src_offset))
13493 st.src_offset = (rb_off_t)-1;
13494 else
13495 st.src_offset = NUM2OFFT(src_offset);
13496
13497 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13498
13499 return OFFT2NUM(st.total);
13500}
13501
13502/*
13503 * call-seq:
13504 * external_encoding -> encoding or nil
13505 *
13506 * Returns the Encoding object that represents the encoding of the stream,
13507 * or +nil+ if the stream is in write mode and no encoding is specified.
13508 *
13509 * See {Encodings}[rdoc-ref:File@Encodings].
13510 *
13511 */
13512
13513static VALUE
13514rb_io_external_encoding(VALUE io)
13515{
13516 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13517
13518 if (fptr->encs.enc2) {
13519 return rb_enc_from_encoding(fptr->encs.enc2);
13520 }
13521 if (fptr->mode & FMODE_WRITABLE) {
13522 if (fptr->encs.enc)
13523 return rb_enc_from_encoding(fptr->encs.enc);
13524 return Qnil;
13525 }
13526 return rb_enc_from_encoding(io_read_encoding(fptr));
13527}
13528
13529/*
13530 * call-seq:
13531 * internal_encoding -> encoding or nil
13532 *
13533 * Returns the Encoding object that represents the encoding of the internal string,
13534 * if conversion is specified,
13535 * or +nil+ otherwise.
13536 *
13537 * See {Encodings}[rdoc-ref:File@Encodings].
13538 *
13539 */
13540
13541static VALUE
13542rb_io_internal_encoding(VALUE io)
13543{
13544 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13545
13546 if (!fptr->encs.enc2) return Qnil;
13547 return rb_enc_from_encoding(io_read_encoding(fptr));
13548}
13549
13550/*
13551 * call-seq:
13552 * set_encoding(ext_enc) -> self
13553 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13554 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13555 *
13556 * See {Encodings}[rdoc-ref:File@Encodings].
13557 *
13558 * Argument +ext_enc+, if given, must be an Encoding object
13559 * or a String with the encoding name;
13560 * it is assigned as the encoding for the stream.
13561 *
13562 * Argument +int_enc+, if given, must be an Encoding object
13563 * or a String with the encoding name;
13564 * it is assigned as the encoding for the internal string.
13565 *
13566 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13567 * containing two colon-separated encoding names;
13568 * corresponding Encoding objects are assigned as the external
13569 * and internal encodings for the stream.
13570 *
13571 * If the external encoding of a string is binary/ASCII-8BIT,
13572 * the internal encoding of the string is set to nil, since no
13573 * transcoding is needed.
13574 *
13575 * Optional keyword arguments +enc_opts+ specify
13576 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13577 *
13578 */
13579
13580static VALUE
13581rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13582{
13583 rb_io_t *fptr;
13584 VALUE v1, v2, opt;
13585
13586 if (!RB_TYPE_P(io, T_FILE)) {
13587 return forward(io, id_set_encoding, argc, argv);
13588 }
13589
13590 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13591 GetOpenFile(io, fptr);
13592 io_encoding_set(fptr, v1, v2, opt);
13593 return io;
13594}
13595
13596void
13597rb_stdio_set_default_encoding(void)
13598{
13599 VALUE val = Qnil;
13600
13601#ifdef _WIN32
13602 if (isatty(fileno(stdin))) {
13603 rb_encoding *external = rb_locale_encoding();
13604 rb_encoding *internal = rb_default_internal_encoding();
13605 if (!internal) internal = rb_default_external_encoding();
13606 io_encoding_set(RFILE(rb_stdin)->fptr,
13607 rb_enc_from_encoding(external),
13608 rb_enc_from_encoding(internal),
13609 Qnil);
13610 }
13611 else
13612#endif
13613 rb_io_set_encoding(1, &val, rb_stdin);
13614 rb_io_set_encoding(1, &val, rb_stdout);
13615 rb_io_set_encoding(1, &val, rb_stderr);
13616}
13617
13618static inline int
13619global_argf_p(VALUE arg)
13620{
13621 return arg == argf;
13622}
13623
13624typedef VALUE (*argf_encoding_func)(VALUE io);
13625
13626static VALUE
13627argf_encoding(VALUE argf, argf_encoding_func func)
13628{
13629 if (!RTEST(ARGF.current_file)) {
13630 return rb_enc_default_external();
13631 }
13632 return func(rb_io_check_io(ARGF.current_file));
13633}
13634
13635/*
13636 * call-seq:
13637 * ARGF.external_encoding -> encoding
13638 *
13639 * Returns the external encoding for files read from ARGF as an Encoding
13640 * object. The external encoding is the encoding of the text as stored in a
13641 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13642 * represent this text within Ruby.
13643 *
13644 * To set the external encoding use ARGF.set_encoding.
13645 *
13646 * For example:
13647 *
13648 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13649 *
13650 */
13651static VALUE
13652argf_external_encoding(VALUE argf)
13653{
13654 return argf_encoding(argf, rb_io_external_encoding);
13655}
13656
13657/*
13658 * call-seq:
13659 * ARGF.internal_encoding -> encoding
13660 *
13661 * Returns the internal encoding for strings read from ARGF as an
13662 * Encoding object.
13663 *
13664 * If ARGF.set_encoding has been called with two encoding names, the second
13665 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13666 * value is returned. Failing that, if a default external encoding was
13667 * specified on the command-line, that value is used. If the encoding is
13668 * unknown, +nil+ is returned.
13669 */
13670static VALUE
13671argf_internal_encoding(VALUE argf)
13672{
13673 return argf_encoding(argf, rb_io_internal_encoding);
13674}
13675
13676/*
13677 * call-seq:
13678 * ARGF.set_encoding(ext_enc) -> ARGF
13679 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13680 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13681 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13682 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13683 *
13684 * If single argument is specified, strings read from ARGF are tagged with
13685 * the encoding specified.
13686 *
13687 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13688 * the read string is converted from the first encoding (external encoding)
13689 * to the second encoding (internal encoding), then tagged with the second
13690 * encoding.
13691 *
13692 * If two arguments are specified, they must be encoding objects or encoding
13693 * names. Again, the first specifies the external encoding; the second
13694 * specifies the internal encoding.
13695 *
13696 * If the external encoding and the internal encoding are specified, the
13697 * optional Hash argument can be used to adjust the conversion process. The
13698 * structure of this hash is explained in the String#encode documentation.
13699 *
13700 * For example:
13701 *
13702 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13703 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13704 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13705 * # to UTF-8.
13706 */
13707static VALUE
13708argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13709{
13710 rb_io_t *fptr;
13711
13712 if (!next_argv()) {
13713 rb_raise(rb_eArgError, "no stream to set encoding");
13714 }
13715 rb_io_set_encoding(argc, argv, ARGF.current_file);
13716 GetOpenFile(ARGF.current_file, fptr);
13717 ARGF.encs = fptr->encs;
13718 RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
13719 return argf;
13720}
13721
13722/*
13723 * call-seq:
13724 * ARGF.tell -> Integer
13725 * ARGF.pos -> Integer
13726 *
13727 * Returns the current offset (in bytes) of the current file in ARGF.
13728 *
13729 * ARGF.pos #=> 0
13730 * ARGF.gets #=> "This is line one\n"
13731 * ARGF.pos #=> 17
13732 *
13733 */
13734static VALUE
13735argf_tell(VALUE argf)
13736{
13737 if (!next_argv()) {
13738 rb_raise(rb_eArgError, "no stream to tell");
13739 }
13740 ARGF_FORWARD(0, 0);
13741 return rb_io_tell(ARGF.current_file);
13742}
13743
13744/*
13745 * call-seq:
13746 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13747 *
13748 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13749 * the value of _whence_. See IO#seek for further details.
13750 */
13751static VALUE
13752argf_seek_m(int argc, VALUE *argv, VALUE argf)
13753{
13754 if (!next_argv()) {
13755 rb_raise(rb_eArgError, "no stream to seek");
13756 }
13757 ARGF_FORWARD(argc, argv);
13758 return rb_io_seek_m(argc, argv, ARGF.current_file);
13759}
13760
13761/*
13762 * call-seq:
13763 * ARGF.pos = position -> Integer
13764 *
13765 * Seeks to the position given by _position_ (in bytes) in ARGF.
13766 *
13767 * For example:
13768 *
13769 * ARGF.pos = 17
13770 * ARGF.gets #=> "This is line two\n"
13771 */
13772static VALUE
13773argf_set_pos(VALUE argf, VALUE offset)
13774{
13775 if (!next_argv()) {
13776 rb_raise(rb_eArgError, "no stream to set position");
13777 }
13778 ARGF_FORWARD(1, &offset);
13779 return rb_io_set_pos(ARGF.current_file, offset);
13780}
13781
13782/*
13783 * call-seq:
13784 * ARGF.rewind -> 0
13785 *
13786 * Positions the current file to the beginning of input, resetting
13787 * ARGF.lineno to zero.
13788 *
13789 * ARGF.readline #=> "This is line one\n"
13790 * ARGF.rewind #=> 0
13791 * ARGF.lineno #=> 0
13792 * ARGF.readline #=> "This is line one\n"
13793 */
13794static VALUE
13795argf_rewind(VALUE argf)
13796{
13797 VALUE ret;
13798 int old_lineno;
13799
13800 if (!next_argv()) {
13801 rb_raise(rb_eArgError, "no stream to rewind");
13802 }
13803 ARGF_FORWARD(0, 0);
13804 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13805 ret = rb_io_rewind(ARGF.current_file);
13806 if (!global_argf_p(argf)) {
13807 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13808 }
13809 return ret;
13810}
13811
13812/*
13813 * call-seq:
13814 * ARGF.fileno -> integer
13815 * ARGF.to_i -> integer
13816 *
13817 * Returns an integer representing the numeric file descriptor for
13818 * the current file. Raises an ArgumentError if there isn't a current file.
13819 *
13820 * ARGF.fileno #=> 3
13821 */
13822static VALUE
13823argf_fileno(VALUE argf)
13824{
13825 if (!next_argv()) {
13826 rb_raise(rb_eArgError, "no stream");
13827 }
13828 ARGF_FORWARD(0, 0);
13829 return rb_io_fileno(ARGF.current_file);
13830}
13831
13832/*
13833 * call-seq:
13834 * ARGF.to_io -> IO
13835 *
13836 * Returns an IO object representing the current file. This will be a
13837 * File object unless the current file is a stream such as STDIN.
13838 *
13839 * For example:
13840 *
13841 * ARGF.to_io #=> #<File:glark.txt>
13842 * ARGF.to_io #=> #<IO:<STDIN>>
13843 */
13844static VALUE
13845argf_to_io(VALUE argf)
13846{
13847 next_argv();
13848 ARGF_FORWARD(0, 0);
13849 return ARGF.current_file;
13850}
13851
13852/*
13853 * call-seq:
13854 * ARGF.eof? -> true or false
13855 * ARGF.eof -> true or false
13856 *
13857 * Returns true if the current file in ARGF is at end of file, i.e. it has
13858 * no data to read. The stream must be opened for reading or an IOError
13859 * will be raised.
13860 *
13861 * $ echo "eof" | ruby argf.rb
13862 *
13863 * ARGF.eof? #=> false
13864 * 3.times { ARGF.readchar }
13865 * ARGF.eof? #=> false
13866 * ARGF.readchar #=> "\n"
13867 * ARGF.eof? #=> true
13868 */
13869
13870static VALUE
13871argf_eof(VALUE argf)
13872{
13873 next_argv();
13874 if (RTEST(ARGF.current_file)) {
13875 if (ARGF.init_p == 0) return Qtrue;
13876 next_argv();
13877 ARGF_FORWARD(0, 0);
13878 if (rb_io_eof(ARGF.current_file)) {
13879 return Qtrue;
13880 }
13881 }
13882 return Qfalse;
13883}
13884
13885/*
13886 * call-seq:
13887 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13888 *
13889 * Reads _length_ bytes from ARGF. The files named on the command line
13890 * are concatenated and treated as a single file by this method, so when
13891 * called without arguments the contents of this pseudo file are returned in
13892 * their entirety.
13893 *
13894 * _length_ must be a non-negative integer or +nil+.
13895 *
13896 * If _length_ is a positive integer, +read+ tries to read
13897 * _length_ bytes without any conversion (binary mode).
13898 * It returns +nil+ if an EOF is encountered before anything can be read.
13899 * Fewer than _length_ bytes are returned if an EOF is encountered during
13900 * the read.
13901 * In the case of an integer _length_, the resulting string is always
13902 * in ASCII-8BIT encoding.
13903 *
13904 * If _length_ is omitted or is +nil+, it reads until EOF
13905 * and the encoding conversion is applied, if applicable.
13906 * A string is returned even if EOF is encountered before any data is read.
13907 *
13908 * If _length_ is zero, it returns an empty string (<code>""</code>).
13909 *
13910 * If the optional _outbuf_ argument is present,
13911 * it must reference a String, which will receive the data.
13912 * The _outbuf_ will contain only the received data after the method call
13913 * even if it is not empty at the beginning.
13914 *
13915 * For example:
13916 *
13917 * $ echo "small" > small.txt
13918 * $ echo "large" > large.txt
13919 * $ ./glark.rb small.txt large.txt
13920 *
13921 * ARGF.read #=> "small\nlarge"
13922 * ARGF.read(200) #=> "small\nlarge"
13923 * ARGF.read(2) #=> "sm"
13924 * ARGF.read(0) #=> ""
13925 *
13926 * Note that this method behaves like the fread() function in C.
13927 * This means it retries to invoke read(2) system calls to read data
13928 * with the specified length.
13929 * If you need the behavior like a single read(2) system call,
13930 * consider ARGF#readpartial or ARGF#read_nonblock.
13931 */
13932
13933static VALUE
13934argf_read(int argc, VALUE *argv, VALUE argf)
13935{
13936 VALUE tmp, str, length;
13937 long len = 0;
13938
13939 rb_scan_args(argc, argv, "02", &length, &str);
13940 if (!NIL_P(length)) {
13941 len = NUM2LONG(argv[0]);
13942 }
13943 if (!NIL_P(str)) {
13944 StringValue(str);
13945 rb_str_resize(str,0);
13946 argv[1] = Qnil;
13947 }
13948
13949 retry:
13950 if (!next_argv()) {
13951 return str;
13952 }
13953 if (ARGF_GENERIC_INPUT_P()) {
13954 tmp = argf_forward(argc, argv, argf);
13955 }
13956 else {
13957 tmp = io_read(argc, argv, ARGF.current_file);
13958 }
13959 if (NIL_P(str)) str = tmp;
13960 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13961 if (NIL_P(tmp) || NIL_P(length)) {
13962 if (ARGF.next_p != -1) {
13963 argf_close(argf);
13964 ARGF.next_p = 1;
13965 goto retry;
13966 }
13967 }
13968 else if (argc >= 1) {
13969 long slen = RSTRING_LEN(str);
13970 if (slen < len) {
13971 argv[0] = LONG2NUM(len - slen);
13972 goto retry;
13973 }
13974 }
13975 return str;
13976}
13977
13979 int argc;
13980 VALUE *argv;
13981 VALUE argf;
13982};
13983
13984static VALUE
13985argf_forward_call(VALUE arg)
13986{
13987 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13988 argf_forward(p->argc, p->argv, p->argf);
13989 return Qnil;
13990}
13991
13992static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13993 int nonblock);
13994
13995/*
13996 * call-seq:
13997 * ARGF.readpartial(maxlen) -> string
13998 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13999 *
14000 * Reads at most _maxlen_ bytes from the ARGF stream.
14001 *
14002 * If the optional _outbuf_ argument is present,
14003 * it must reference a String, which will receive the data.
14004 * The _outbuf_ will contain only the received data after the method call
14005 * even if it is not empty at the beginning.
14006 *
14007 * It raises EOFError on end of ARGF stream.
14008 * Since ARGF stream is a concatenation of multiple files,
14009 * internally EOF is occur for each file.
14010 * ARGF.readpartial returns empty strings for EOFs except the last one and
14011 * raises EOFError for the last one.
14012 *
14013 */
14014
14015static VALUE
14016argf_readpartial(int argc, VALUE *argv, VALUE argf)
14017{
14018 return argf_getpartial(argc, argv, argf, Qnil, 0);
14019}
14020
14021/*
14022 * call-seq:
14023 * ARGF.read_nonblock(maxlen[, options]) -> string
14024 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14025 *
14026 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14027 */
14028
14029static VALUE
14030argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14031{
14032 VALUE opts;
14033
14034 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14035
14036 if (!NIL_P(opts))
14037 argc--;
14038
14039 return argf_getpartial(argc, argv, argf, opts, 1);
14040}
14041
14042static VALUE
14043argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14044{
14045 VALUE tmp, str, length;
14046 int no_exception;
14047
14048 rb_scan_args(argc, argv, "11", &length, &str);
14049 if (!NIL_P(str)) {
14050 StringValue(str);
14051 argv[1] = str;
14052 }
14053 no_exception = no_exception_p(opts);
14054
14055 if (!next_argv()) {
14056 if (!NIL_P(str)) {
14057 rb_str_resize(str, 0);
14058 }
14059 rb_eof_error();
14060 }
14061 if (ARGF_GENERIC_INPUT_P()) {
14062 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14063 struct argf_call_arg arg;
14064 arg.argc = argc;
14065 arg.argv = argv;
14066 arg.argf = argf;
14067 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14068 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14069 }
14070 else {
14071 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14072 }
14073 if (NIL_P(tmp)) {
14074 if (ARGF.next_p == -1) {
14075 return io_nonblock_eof(no_exception);
14076 }
14077 argf_close(argf);
14078 ARGF.next_p = 1;
14079 if (RARRAY_LEN(ARGF.argv) == 0) {
14080 return io_nonblock_eof(no_exception);
14081 }
14082 if (NIL_P(str))
14083 str = rb_str_new(NULL, 0);
14084 return str;
14085 }
14086 return tmp;
14087}
14088
14089/*
14090 * call-seq:
14091 * ARGF.getc -> String or nil
14092 *
14093 * Reads the next character from ARGF and returns it as a String. Returns
14094 * +nil+ at the end of the stream.
14095 *
14096 * ARGF treats the files named on the command line as a single file created
14097 * by concatenating their contents. After returning the last character of the
14098 * first file, it returns the first character of the second file, and so on.
14099 *
14100 * For example:
14101 *
14102 * $ echo "foo" > file
14103 * $ ruby argf.rb file
14104 *
14105 * ARGF.getc #=> "f"
14106 * ARGF.getc #=> "o"
14107 * ARGF.getc #=> "o"
14108 * ARGF.getc #=> "\n"
14109 * ARGF.getc #=> nil
14110 * ARGF.getc #=> nil
14111 */
14112static VALUE
14113argf_getc(VALUE argf)
14114{
14115 VALUE ch;
14116
14117 retry:
14118 if (!next_argv()) return Qnil;
14119 if (ARGF_GENERIC_INPUT_P()) {
14120 ch = forward_current(rb_intern("getc"), 0, 0);
14121 }
14122 else {
14123 ch = rb_io_getc(ARGF.current_file);
14124 }
14125 if (NIL_P(ch) && ARGF.next_p != -1) {
14126 argf_close(argf);
14127 ARGF.next_p = 1;
14128 goto retry;
14129 }
14130
14131 return ch;
14132}
14133
14134/*
14135 * call-seq:
14136 * ARGF.getbyte -> Integer or nil
14137 *
14138 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14139 * the end of the stream.
14140 *
14141 * For example:
14142 *
14143 * $ echo "foo" > file
14144 * $ ruby argf.rb file
14145 *
14146 * ARGF.getbyte #=> 102
14147 * ARGF.getbyte #=> 111
14148 * ARGF.getbyte #=> 111
14149 * ARGF.getbyte #=> 10
14150 * ARGF.getbyte #=> nil
14151 */
14152static VALUE
14153argf_getbyte(VALUE argf)
14154{
14155 VALUE ch;
14156
14157 retry:
14158 if (!next_argv()) return Qnil;
14159 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14160 ch = forward_current(rb_intern("getbyte"), 0, 0);
14161 }
14162 else {
14163 ch = rb_io_getbyte(ARGF.current_file);
14164 }
14165 if (NIL_P(ch) && ARGF.next_p != -1) {
14166 argf_close(argf);
14167 ARGF.next_p = 1;
14168 goto retry;
14169 }
14170
14171 return ch;
14172}
14173
14174/*
14175 * call-seq:
14176 * ARGF.readchar -> String or nil
14177 *
14178 * Reads the next character from ARGF and returns it as a String. Raises
14179 * an EOFError after the last character of the last file has been read.
14180 *
14181 * For example:
14182 *
14183 * $ echo "foo" > file
14184 * $ ruby argf.rb file
14185 *
14186 * ARGF.readchar #=> "f"
14187 * ARGF.readchar #=> "o"
14188 * ARGF.readchar #=> "o"
14189 * ARGF.readchar #=> "\n"
14190 * ARGF.readchar #=> end of file reached (EOFError)
14191 */
14192static VALUE
14193argf_readchar(VALUE argf)
14194{
14195 VALUE ch;
14196
14197 retry:
14198 if (!next_argv()) rb_eof_error();
14199 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14200 ch = forward_current(rb_intern("getc"), 0, 0);
14201 }
14202 else {
14203 ch = rb_io_getc(ARGF.current_file);
14204 }
14205 if (NIL_P(ch) && ARGF.next_p != -1) {
14206 argf_close(argf);
14207 ARGF.next_p = 1;
14208 goto retry;
14209 }
14210
14211 return ch;
14212}
14213
14214/*
14215 * call-seq:
14216 * ARGF.readbyte -> Integer
14217 *
14218 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14219 * an EOFError after the last byte of the last file has been read.
14220 *
14221 * For example:
14222 *
14223 * $ echo "foo" > file
14224 * $ ruby argf.rb file
14225 *
14226 * ARGF.readbyte #=> 102
14227 * ARGF.readbyte #=> 111
14228 * ARGF.readbyte #=> 111
14229 * ARGF.readbyte #=> 10
14230 * ARGF.readbyte #=> end of file reached (EOFError)
14231 */
14232static VALUE
14233argf_readbyte(VALUE argf)
14234{
14235 VALUE c;
14236
14237 NEXT_ARGF_FORWARD(0, 0);
14238 c = argf_getbyte(argf);
14239 if (NIL_P(c)) {
14240 rb_eof_error();
14241 }
14242 return c;
14243}
14244
14245#define FOREACH_ARGF() while (next_argv())
14246
14247static VALUE
14248argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14249{
14250 const VALUE current = ARGF.current_file;
14251 rb_yield_values2(argc, argv);
14252 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14254 }
14255 return Qnil;
14256}
14257
14258#define ARGF_block_call(mid, argc, argv, func, argf) \
14259 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14260 func, argf, rb_keyword_given_p())
14261
14262static void
14263argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14264{
14265 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14266 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14267}
14268
14269static VALUE
14270argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14271{
14272 if (!global_argf_p(argf)) {
14273 ARGF.last_lineno = ++ARGF.lineno;
14274 }
14275 return argf_block_call_i(i, argf, argc, argv, blockarg);
14276}
14277
14278static void
14279argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14280{
14281 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14282 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14283}
14284
14285/*
14286 * call-seq:
14287 * ARGF.each(sep=$/) {|line| block } -> ARGF
14288 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14289 * ARGF.each(...) -> an_enumerator
14290 *
14291 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14292 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14293 * ARGF.each_line(...) -> an_enumerator
14294 *
14295 * Returns an enumerator which iterates over each line (separated by _sep_,
14296 * which defaults to your platform's newline character) of each file in
14297 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14298 * block, otherwise an enumerator is returned.
14299 * The optional _limit_ argument is an Integer specifying the maximum
14300 * length of each line; longer lines will be split according to this limit.
14301 *
14302 * This method allows you to treat the files supplied on the command line as
14303 * a single file consisting of the concatenation of each named file. After
14304 * the last line of the first file has been returned, the first line of the
14305 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14306 * used to determine the filename of the current line and line number of the
14307 * whole input, respectively.
14308 *
14309 * For example, the following code prints out each line of each named file
14310 * prefixed with its line number, displaying the filename once per file:
14311 *
14312 * ARGF.each_line do |line|
14313 * puts ARGF.filename if ARGF.file.lineno == 1
14314 * puts "#{ARGF.file.lineno}: #{line}"
14315 * end
14316 *
14317 * While the following code prints only the first file's name at first, and
14318 * the contents with line number counted through all named files.
14319 *
14320 * ARGF.each_line do |line|
14321 * puts ARGF.filename if ARGF.lineno == 1
14322 * puts "#{ARGF.lineno}: #{line}"
14323 * end
14324 */
14325static VALUE
14326argf_each_line(int argc, VALUE *argv, VALUE argf)
14327{
14328 RETURN_ENUMERATOR(argf, argc, argv);
14329 FOREACH_ARGF() {
14330 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14331 }
14332 return argf;
14333}
14334
14335/*
14336 * call-seq:
14337 * ARGF.each_byte {|byte| block } -> ARGF
14338 * ARGF.each_byte -> an_enumerator
14339 *
14340 * Iterates over each byte of each file in +ARGV+.
14341 * A byte is returned as an Integer in the range 0..255.
14342 *
14343 * This method allows you to treat the files supplied on the command line as
14344 * a single file consisting of the concatenation of each named file. After
14345 * the last byte of the first file has been returned, the first byte of the
14346 * second file is returned. The ARGF.filename method can be used to
14347 * determine the filename of the current byte.
14348 *
14349 * If no block is given, an enumerator is returned instead.
14350 *
14351 * For example:
14352 *
14353 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14354 *
14355 */
14356static VALUE
14357argf_each_byte(VALUE argf)
14358{
14359 RETURN_ENUMERATOR(argf, 0, 0);
14360 FOREACH_ARGF() {
14361 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14362 }
14363 return argf;
14364}
14365
14366/*
14367 * call-seq:
14368 * ARGF.each_char {|char| block } -> ARGF
14369 * ARGF.each_char -> an_enumerator
14370 *
14371 * Iterates over each character of each file in ARGF.
14372 *
14373 * This method allows you to treat the files supplied on the command line as
14374 * a single file consisting of the concatenation of each named file. After
14375 * the last character of the first file has been returned, the first
14376 * character of the second file is returned. The ARGF.filename method can
14377 * be used to determine the name of the file in which the current character
14378 * appears.
14379 *
14380 * If no block is given, an enumerator is returned instead.
14381 */
14382static VALUE
14383argf_each_char(VALUE argf)
14384{
14385 RETURN_ENUMERATOR(argf, 0, 0);
14386 FOREACH_ARGF() {
14387 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14388 }
14389 return argf;
14390}
14391
14392/*
14393 * call-seq:
14394 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14395 * ARGF.each_codepoint -> an_enumerator
14396 *
14397 * Iterates over each codepoint of each file in ARGF.
14398 *
14399 * This method allows you to treat the files supplied on the command line as
14400 * a single file consisting of the concatenation of each named file. After
14401 * the last codepoint of the first file has been returned, the first
14402 * codepoint of the second file is returned. The ARGF.filename method can
14403 * be used to determine the name of the file in which the current codepoint
14404 * appears.
14405 *
14406 * If no block is given, an enumerator is returned instead.
14407 */
14408static VALUE
14409argf_each_codepoint(VALUE argf)
14410{
14411 RETURN_ENUMERATOR(argf, 0, 0);
14412 FOREACH_ARGF() {
14413 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14414 }
14415 return argf;
14416}
14417
14418/*
14419 * call-seq:
14420 * ARGF.filename -> String
14421 * ARGF.path -> String
14422 *
14423 * Returns the current filename. "-" is returned when the current file is
14424 * STDIN.
14425 *
14426 * For example:
14427 *
14428 * $ echo "foo" > foo
14429 * $ echo "bar" > bar
14430 * $ echo "glark" > glark
14431 *
14432 * $ ruby argf.rb foo bar glark
14433 *
14434 * ARGF.filename #=> "foo"
14435 * ARGF.read(5) #=> "foo\nb"
14436 * ARGF.filename #=> "bar"
14437 * ARGF.skip
14438 * ARGF.filename #=> "glark"
14439 */
14440static VALUE
14441argf_filename(VALUE argf)
14442{
14443 next_argv();
14444 return ARGF.filename;
14445}
14446
14447static VALUE
14448argf_filename_getter(ID id, VALUE *var)
14449{
14450 return argf_filename(*var);
14451}
14452
14453/*
14454 * call-seq:
14455 * ARGF.file -> IO or File object
14456 *
14457 * Returns the current file as an IO or File object.
14458 * <code>$stdin</code> is returned when the current file is STDIN.
14459 *
14460 * For example:
14461 *
14462 * $ echo "foo" > foo
14463 * $ echo "bar" > bar
14464 *
14465 * $ ruby argf.rb foo bar
14466 *
14467 * ARGF.file #=> #<File:foo>
14468 * ARGF.read(5) #=> "foo\nb"
14469 * ARGF.file #=> #<File:bar>
14470 */
14471static VALUE
14472argf_file(VALUE argf)
14473{
14474 next_argv();
14475 return ARGF.current_file;
14476}
14477
14478/*
14479 * call-seq:
14480 * ARGF.binmode -> ARGF
14481 *
14482 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14483 * be reset to non-binary mode. This option has the following effects:
14484 *
14485 * * Newline conversion is disabled.
14486 * * Encoding conversion is disabled.
14487 * * Content is treated as ASCII-8BIT.
14488 */
14489static VALUE
14490argf_binmode_m(VALUE argf)
14491{
14492 ARGF.binmode = 1;
14493 next_argv();
14494 ARGF_FORWARD(0, 0);
14495 rb_io_ascii8bit_binmode(ARGF.current_file);
14496 return argf;
14497}
14498
14499/*
14500 * call-seq:
14501 * ARGF.binmode? -> true or false
14502 *
14503 * Returns true if ARGF is being read in binary mode; false otherwise.
14504 * To enable binary mode use ARGF.binmode.
14505 *
14506 * For example:
14507 *
14508 * ARGF.binmode? #=> false
14509 * ARGF.binmode
14510 * ARGF.binmode? #=> true
14511 */
14512static VALUE
14513argf_binmode_p(VALUE argf)
14514{
14515 return RBOOL(ARGF.binmode);
14516}
14517
14518/*
14519 * call-seq:
14520 * ARGF.skip -> ARGF
14521 *
14522 * Sets the current file to the next file in ARGV. If there aren't any more
14523 * files it has no effect.
14524 *
14525 * For example:
14526 *
14527 * $ ruby argf.rb foo bar
14528 * ARGF.filename #=> "foo"
14529 * ARGF.skip
14530 * ARGF.filename #=> "bar"
14531 */
14532static VALUE
14533argf_skip(VALUE argf)
14534{
14535 if (ARGF.init_p && ARGF.next_p == 0) {
14536 argf_close(argf);
14537 ARGF.next_p = 1;
14538 }
14539 return argf;
14540}
14541
14542/*
14543 * call-seq:
14544 * ARGF.close -> ARGF
14545 *
14546 * Closes the current file and skips to the next file in ARGV. If there are
14547 * no more files to open, just closes the current file. STDIN will not be
14548 * closed.
14549 *
14550 * For example:
14551 *
14552 * $ ruby argf.rb foo bar
14553 *
14554 * ARGF.filename #=> "foo"
14555 * ARGF.close
14556 * ARGF.filename #=> "bar"
14557 * ARGF.close
14558 */
14559static VALUE
14560argf_close_m(VALUE argf)
14561{
14562 next_argv();
14563 argf_close(argf);
14564 if (ARGF.next_p != -1) {
14565 ARGF.next_p = 1;
14566 }
14567 ARGF.lineno = 0;
14568 return argf;
14569}
14570
14571/*
14572 * call-seq:
14573 * ARGF.closed? -> true or false
14574 *
14575 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14576 * ARGF.close to actually close the current file.
14577 */
14578static VALUE
14579argf_closed(VALUE argf)
14580{
14581 next_argv();
14582 ARGF_FORWARD(0, 0);
14583 return rb_io_closed_p(ARGF.current_file);
14584}
14585
14586/*
14587 * call-seq:
14588 * ARGF.to_s -> String
14589 *
14590 * Returns "ARGF".
14591 */
14592static VALUE
14593argf_to_s(VALUE argf)
14594{
14595 return rb_str_new2("ARGF");
14596}
14597
14598/*
14599 * call-seq:
14600 * ARGF.inplace_mode -> String
14601 *
14602 * Returns the file extension appended to the names of backup copies of
14603 * modified files under in-place edit mode. This value can be set using
14604 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14605 */
14606static VALUE
14607argf_inplace_mode_get(VALUE argf)
14608{
14609 if (!ARGF.inplace) return Qnil;
14610 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14611 return rb_str_dup(ARGF.inplace);
14612}
14613
14614static VALUE
14615opt_i_get(ID id, VALUE *var)
14616{
14617 return argf_inplace_mode_get(*var);
14618}
14619
14620/*
14621 * call-seq:
14622 * ARGF.inplace_mode = ext -> ARGF
14623 *
14624 * Sets the filename extension for in-place editing mode to the given String.
14625 * The backup copy of each file being edited has this value appended to its
14626 * filename.
14627 *
14628 * For example:
14629 *
14630 * $ ruby argf.rb file.txt
14631 *
14632 * ARGF.inplace_mode = '.bak'
14633 * ARGF.each_line do |line|
14634 * print line.sub("foo","bar")
14635 * end
14636 *
14637 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14638 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14639 * "bar".
14640 */
14641static VALUE
14642argf_inplace_mode_set(VALUE argf, VALUE val)
14643{
14644 if (!RTEST(val)) {
14645 ARGF.inplace = Qfalse;
14646 }
14647 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14648 ARGF.inplace = Qnil;
14649 }
14650 else {
14651 ARGF_SET(inplace, rb_str_new_frozen(val));
14652 }
14653 return argf;
14654}
14655
14656static void
14657opt_i_set(VALUE val, ID id, VALUE *var)
14658{
14659 argf_inplace_mode_set(*var, val);
14660}
14661
14662void
14663ruby_set_inplace_mode(const char *suffix)
14664{
14665 ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
14666}
14667
14668/*
14669 * call-seq:
14670 * ARGF.argv -> ARGV
14671 *
14672 * Returns the +ARGV+ array, which contains the arguments passed to your
14673 * script, one per element.
14674 *
14675 * For example:
14676 *
14677 * $ ruby argf.rb -v glark.txt
14678 *
14679 * ARGF.argv #=> ["-v", "glark.txt"]
14680 *
14681 */
14682static VALUE
14683argf_argv(VALUE argf)
14684{
14685 return ARGF.argv;
14686}
14687
14688static VALUE
14689argf_argv_getter(ID id, VALUE *var)
14690{
14691 return argf_argv(*var);
14692}
14693
14694VALUE
14696{
14697 return ARGF.argv;
14698}
14699
14700/*
14701 * call-seq:
14702 * ARGF.to_write_io -> io
14703 *
14704 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14705 * enabled.
14706 */
14707static VALUE
14708argf_write_io(VALUE argf)
14709{
14710 if (!RTEST(ARGF.current_file)) {
14711 rb_raise(rb_eIOError, "not opened for writing");
14712 }
14713 return GetWriteIO(ARGF.current_file);
14714}
14715
14716/*
14717 * call-seq:
14718 * ARGF.write(*objects) -> integer
14719 *
14720 * Writes each of the given +objects+ if inplace mode.
14721 */
14722static VALUE
14723argf_write(int argc, VALUE *argv, VALUE argf)
14724{
14725 return rb_io_writev(argf_write_io(argf), argc, argv);
14726}
14727
14728void
14729rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14730{
14731 rb_readwrite_syserr_fail(waiting, errno, mesg);
14732}
14733
14734void
14735rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14736{
14737 VALUE arg, c = Qnil;
14738 arg = mesg ? rb_str_new2(mesg) : Qnil;
14739 switch (waiting) {
14740 case RB_IO_WAIT_WRITABLE:
14741 switch (n) {
14742 case EAGAIN:
14743 c = rb_eEAGAINWaitWritable;
14744 break;
14745#if EAGAIN != EWOULDBLOCK
14746 case EWOULDBLOCK:
14747 c = rb_eEWOULDBLOCKWaitWritable;
14748 break;
14749#endif
14750 case EINPROGRESS:
14751 c = rb_eEINPROGRESSWaitWritable;
14752 break;
14753 default:
14755 }
14756 break;
14757 case RB_IO_WAIT_READABLE:
14758 switch (n) {
14759 case EAGAIN:
14760 c = rb_eEAGAINWaitReadable;
14761 break;
14762#if EAGAIN != EWOULDBLOCK
14763 case EWOULDBLOCK:
14764 c = rb_eEWOULDBLOCKWaitReadable;
14765 break;
14766#endif
14767 case EINPROGRESS:
14768 c = rb_eEINPROGRESSWaitReadable;
14769 break;
14770 default:
14772 }
14773 break;
14774 default:
14775 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14776 }
14778}
14779
14780static VALUE
14781get_LAST_READ_LINE(ID _x, VALUE *_y)
14782{
14783 return rb_lastline_get();
14784}
14785
14786static void
14787set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14788{
14789 rb_lastline_set(val);
14790}
14791
14792/*
14793 * Document-class: IOError
14794 *
14795 * Raised when an IO operation fails.
14796 *
14797 * File.open("/etc/hosts") {|f| f << "example"}
14798 * #=> IOError: not opened for writing
14799 *
14800 * File.open("/etc/hosts") {|f| f.close; f.read }
14801 * #=> IOError: closed stream
14802 *
14803 * Note that some IO failures raise <code>SystemCallError</code>s
14804 * and these are not subclasses of IOError:
14805 *
14806 * File.open("does/not/exist")
14807 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14808 */
14809
14810/*
14811 * Document-class: EOFError
14812 *
14813 * Raised by some IO operations when reaching the end of file. Many IO
14814 * methods exist in two forms,
14815 *
14816 * one that returns +nil+ when the end of file is reached, the other
14817 * raises EOFError.
14818 *
14819 * EOFError is a subclass of IOError.
14820 *
14821 * file = File.open("/etc/hosts")
14822 * file.read
14823 * file.gets #=> nil
14824 * file.readline #=> EOFError: end of file reached
14825 * file.close
14826 */
14827
14828/*
14829 * Document-class: ARGF
14830 *
14831 * == \ARGF and +ARGV+
14832 *
14833 * The \ARGF object works with the array at global variable +ARGV+
14834 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14835 *
14836 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14837 *
14838 * Initially, it contains the command-line arguments and options
14839 * that are passed to the Ruby program;
14840 * the program can modify that array as it likes.
14841 *
14842 * - **ARGF** may be thought of as the <b>argument files</b> object.
14843 *
14844 * It can access file streams and/or the <tt>$stdin</tt> stream,
14845 * based on what it finds in +ARGV+.
14846 * This provides a convenient way for the command line
14847 * to specify streams for a Ruby program to read.
14848 *
14849 * == Reading
14850 *
14851 * \ARGF may read from _source_ streams,
14852 * which at any particular time are determined by the content of +ARGV+.
14853 *
14854 * === Simplest Case
14855 *
14856 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14857 * the source is <tt>$stdin</tt>:
14858 *
14859 * - \File +t.rb+:
14860 *
14861 * p ['ARGV', ARGV]
14862 * p ['ARGF.read', ARGF.read]
14863 *
14864 * - Commands and outputs
14865 * (see below for the content of files +foo.txt+ and +bar.txt+):
14866 *
14867 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14868 * ["ARGV", []]
14869 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14870 *
14871 * $ cat foo.txt bar.txt | ruby t.rb
14872 * ["ARGV", []]
14873 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14874 *
14875 * === About the Examples
14876 *
14877 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14878 *
14879 * $ cat foo.txt
14880 * Foo 0
14881 * Foo 1
14882 * $ cat bar.txt
14883 * Bar 0
14884 * Bar 1
14885 * Bar 2
14886 * Bar 3
14887 *
14888 * === Sources in +ARGV+
14889 *
14890 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14891 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14892 * the sources are found in +ARGV+.
14893 *
14894 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14895 * and is one of:
14896 *
14897 * - The string path to a file that may be opened as a stream.
14898 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14899 *
14900 * Each element that is _not_ one of these
14901 * should be removed from +ARGV+ before \ARGF accesses that source.
14902 *
14903 * In the following example:
14904 *
14905 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14906 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14907 *
14908 * Example:
14909 *
14910 * - \File +t.rb+:
14911 *
14912 * # Print arguments (and options, if any) found on command line.
14913 * p ['ARGV', ARGV]
14914 *
14915 * - Command and output:
14916 *
14917 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14918 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14919 *
14920 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14921 *
14922 * - \File +t.rb+:
14923 *
14924 * p "ARGV: #{ARGV}"
14925 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
14926 *
14927 * - Command and output:
14928 *
14929 * $ ruby t.rb foo.txt bar.txt
14930 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14931 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14932 *
14933 * Because the value at +ARGV+ is an ordinary array,
14934 * you can manipulate it to control which sources \ARGF considers:
14935 *
14936 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14937 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14938 *
14939 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14940 * when all sources have been accessed, the array is empty:
14941 *
14942 * - \File +t.rb+:
14943 *
14944 * until ARGV.empty? && ARGF.eof?
14945 * p "ARGV: #{ARGV}"
14946 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14947 * end
14948 *
14949 * - Command and output:
14950 *
14951 * $ ruby t.rb foo.txt bar.txt
14952 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14953 * "Line: Foo 0\n"
14954 * "ARGV: [\"bar.txt\"]"
14955 * "Line: Foo 1\n"
14956 * "ARGV: [\"bar.txt\"]"
14957 * "Line: Bar 0\n"
14958 * "ARGV: []"
14959 * "Line: Bar 1\n"
14960 * "ARGV: []"
14961 * "Line: Bar 2\n"
14962 * "ARGV: []"
14963 * "Line: Bar 3\n"
14964 *
14965 * ==== Filepaths in +ARGV+
14966 *
14967 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14968 *
14969 * This program prints what it reads from files at the paths specified
14970 * on the command line:
14971 *
14972 * - \File +t.rb+:
14973 *
14974 * p ['ARGV', ARGV]
14975 * # Read and print all content from the specified sources.
14976 * p ['ARGF.read', ARGF.read]
14977 *
14978 * - Command and output:
14979 *
14980 * $ ruby t.rb foo.txt bar.txt
14981 * ["ARGV", [foo.txt, bar.txt]
14982 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14983 *
14984 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14985 *
14986 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14987 *
14988 * - \File +t.rb+:
14989 *
14990 * p ['ARGV', ARGV]
14991 * p ['ARGF.read', ARGF.read]
14992 *
14993 * - Command and output:
14994 *
14995 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14996 * ["ARGV", ["-"]]
14997 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14998 *
14999 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
15000 *
15001 * - Command and output:
15002 *
15003 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15004 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15005 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15006 *
15007 * ==== Mixtures and Repetitions in +ARGV+
15008 *
15009 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15010 * and character <tt>'-'</tt>, including repetitions.
15011 *
15012 * ==== Modifications to +ARGV+
15013 *
15014 * The running Ruby program may make any modifications to the +ARGV+ array;
15015 * the current value of +ARGV+ affects \ARGF reading.
15016 *
15017 * ==== Empty +ARGV+
15018 *
15019 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15020 * or raises an exception, depending on the specific method.
15021 *
15022 * === More Read Methods
15023 *
15024 * As seen above, method ARGF#read reads the content of all sources
15025 * into a single string.
15026 * Other \ARGF methods provide other ways to access that content;
15027 * these include:
15028 *
15029 * - Byte access: #each_byte, #getbyte, #readbyte.
15030 * - Character access: #each_char, #getc, #readchar.
15031 * - Codepoint access: #each_codepoint.
15032 * - Line access: #each_line, #gets, #readline, #readlines.
15033 * - Source access: #read, #read_nonblock, #readpartial.
15034 *
15035 * === About \Enumerable
15036 *
15037 * \ARGF includes module Enumerable.
15038 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15039 *
15040 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15041 * _not_ from +ARGV+;
15042 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15043 * not an array of the strings from +ARGV+:
15044 *
15045 * - \File +t.rb+:
15046 *
15047 * p ['ARGV', ARGV]
15048 * p ['ARGF.entries', ARGF.entries]
15049 *
15050 * - Command and output:
15051 *
15052 * $ ruby t.rb foo.txt bar.txt
15053 * ["ARGV", ["foo.txt", "bar.txt"]]
15054 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15055 *
15056 * == Writing
15057 *
15058 * If <i>inplace mode</i> is in effect,
15059 * \ARGF may write to target streams,
15060 * which at any particular time are determined by the content of ARGV.
15061 *
15062 * Methods about inplace mode:
15063 *
15064 * - #inplace_mode
15065 * - #inplace_mode=
15066 * - #to_write_io
15067 *
15068 * Methods for writing:
15069 *
15070 * - #print
15071 * - #printf
15072 * - #putc
15073 * - #puts
15074 * - #write
15075 *
15076 */
15077
15078/*
15079 * An instance of class \IO (commonly called a _stream_)
15080 * represents an input/output stream in the underlying operating system.
15081 * Class \IO is the basis for input and output in Ruby.
15082 *
15083 * Class File is the only class in the Ruby core that is a subclass of \IO.
15084 * Some classes in the Ruby standard library are also subclasses of \IO;
15085 * these include TCPSocket and UDPSocket.
15086 *
15087 * The global constant ARGF (also accessible as <tt>$<</tt>)
15088 * provides an IO-like stream that allows access to all file paths
15089 * found in ARGV (or found in STDIN if ARGV is empty).
15090 * ARGF is not itself a subclass of \IO.
15091 *
15092 * Class StringIO provides an IO-like stream that handles a String.
15093 * StringIO is not itself a subclass of \IO.
15094 *
15095 * Important objects based on \IO include:
15096 *
15097 * - $stdin.
15098 * - $stdout.
15099 * - $stderr.
15100 * - Instances of class File.
15101 *
15102 * An instance of \IO may be created using:
15103 *
15104 * - IO.new: returns a new \IO object for the given integer file descriptor.
15105 * - IO.open: passes a new \IO object to the given block.
15106 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15107 * of a newly-launched subprocess.
15108 * - Kernel#open: Returns a new \IO object connected to a given source:
15109 * stream, file, or subprocess.
15110 *
15111 * Like a File stream, an \IO stream has:
15112 *
15113 * - A read/write mode, which may be read-only, write-only, or read/write;
15114 * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
15115 * - A data mode, which may be text-only or binary;
15116 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15117 * - Internal and external encodings;
15118 * see {Encodings}[rdoc-ref:File@Encodings].
15119 *
15120 * And like other \IO streams, it has:
15121 *
15122 * - A position, which determines where in the stream the next
15123 * read or write is to occur;
15124 * see {Position}[rdoc-ref:IO@Position].
15125 * - A line number, which is a special, line-oriented, "position"
15126 * (different from the position mentioned above);
15127 * see {Line Number}[rdoc-ref:IO@Line+Number].
15128 *
15129 * == Extension <tt>io/console</tt>
15130 *
15131 * Extension <tt>io/console</tt> provides numerous methods
15132 * for interacting with the console;
15133 * requiring it adds numerous methods to class \IO.
15134 *
15135 * == Example Files
15136 *
15137 * Many examples here use these variables:
15138 *
15139 * :include: doc/examples/files.rdoc
15140 *
15141 * == Open Options
15142 *
15143 * A number of \IO methods accept optional keyword arguments
15144 * that determine how a new stream is to be opened:
15145 *
15146 * - +:mode+: Stream mode.
15147 * - +:flags+: Integer file open flags;
15148 * If +mode+ is also given, the two are bitwise-ORed.
15149 * - +:external_encoding+: External encoding for the stream.
15150 * - +:internal_encoding+: Internal encoding for the stream.
15151 * <tt>'-'</tt> is a synonym for the default internal encoding.
15152 * If the value is +nil+ no conversion occurs.
15153 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15154 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15155 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15156 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15157 * when the stream closes; otherwise it remains open.
15158 * - +:path+: If a string value is provided, it is used in #inspect and is available as
15159 * #path method.
15160 *
15161 * Also available are the options offered in String#encode,
15162 * which may control conversion between external and internal encoding.
15163 *
15164 * == Basic \IO
15165 *
15166 * You can perform basic stream \IO with these methods,
15167 * which typically operate on multi-byte strings:
15168 *
15169 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15170 * - IO#write: Writes zero or more strings to the stream;
15171 * each given object that is not already a string is converted via +to_s+.
15172 *
15173 * === Position
15174 *
15175 * An \IO stream has a nonnegative integer _position_,
15176 * which is the byte offset at which the next read or write is to occur.
15177 * A new stream has position zero (and line number zero);
15178 * method +rewind+ resets the position (and line number) to zero.
15179 *
15180 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15181 * Encoding::Converter instances used for that \IO.
15182 *
15183 * The relevant methods:
15184 *
15185 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15186 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15187 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15188 * relative to a given position +whence+
15189 * (indicating the beginning, end, or current position).
15190 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15191 *
15192 * === Open and Closed Streams
15193 *
15194 * A new \IO stream may be open for reading, open for writing, or both.
15195 *
15196 * A stream is automatically closed when claimed by the garbage collector.
15197 *
15198 * Attempted reading or writing on a closed stream raises an exception.
15199 *
15200 * The relevant methods:
15201 *
15202 * - IO#close: Closes the stream for both reading and writing.
15203 * - IO#close_read: Closes the stream for reading.
15204 * - IO#close_write: Closes the stream for writing.
15205 * - IO#closed?: Returns whether the stream is closed.
15206 *
15207 * === End-of-Stream
15208 *
15209 * You can query whether a stream is positioned at its end:
15210 *
15211 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15212 *
15213 * You can reposition to end-of-stream by using method IO#seek:
15214 *
15215 * f = File.new('t.txt')
15216 * f.eof? # => false
15217 * f.seek(0, :END)
15218 * f.eof? # => true
15219 * f.close
15220 *
15221 * Or by reading all stream content (which is slower than using IO#seek):
15222 *
15223 * f.rewind
15224 * f.eof? # => false
15225 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15226 * f.eof? # => true
15227 *
15228 * == Line \IO
15229 *
15230 * Class \IO supports line-oriented
15231 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15232 *
15233 * === Line Input
15234 *
15235 * Class \IO supports line-oriented input for
15236 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15237 *
15238 * ==== \File Line Input
15239 *
15240 * You can read lines from a file using these methods:
15241 *
15242 * - IO.foreach: Reads each line and passes it to the given block.
15243 * - IO.readlines: Reads and returns all lines in an array.
15244 *
15245 * For each of these methods:
15246 *
15247 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15248 * - Line parsing depends on the effective <i>line separator</i>;
15249 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15250 * - The length of each returned line depends on the effective <i>line limit</i>;
15251 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15252 *
15253 * ==== Stream Line Input
15254 *
15255 * You can read lines from an \IO stream using these methods:
15256 *
15257 * - IO#each_line: Reads each remaining line, passing it to the given block.
15258 * - IO#gets: Returns the next line.
15259 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15260 * - IO#readlines: Returns all remaining lines in an array.
15261 *
15262 * For each of these methods:
15263 *
15264 * - Reading may begin mid-line,
15265 * depending on the stream's _position_;
15266 * see {Position}[rdoc-ref:IO@Position].
15267 * - Line parsing depends on the effective <i>line separator</i>;
15268 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15269 * - The length of each returned line depends on the effective <i>line limit</i>;
15270 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15271 *
15272 * ===== Line Separator
15273 *
15274 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15275 * the string that determines what is considered a line;
15276 * it is sometimes called the <i>input record separator</i>.
15277 *
15278 * The default line separator is taken from global variable <tt>$/</tt>,
15279 * whose initial value is <tt>"\n"</tt>.
15280 *
15281 * Generally, the line to be read next is all data
15282 * from the current {position}[rdoc-ref:IO@Position]
15283 * to the next line separator
15284 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15285 *
15286 * f = File.new('t.txt')
15287 * # Method gets with no sep argument returns the next line, according to $/.
15288 * f.gets # => "First line\n"
15289 * f.gets # => "Second line\n"
15290 * f.gets # => "\n"
15291 * f.gets # => "Fourth line\n"
15292 * f.gets # => "Fifth line\n"
15293 * f.close
15294 *
15295 * You can use a different line separator by passing argument +sep+:
15296 *
15297 * f = File.new('t.txt')
15298 * f.gets('l') # => "First l"
15299 * f.gets('li') # => "ine\nSecond li"
15300 * f.gets('lin') # => "ne\n\nFourth lin"
15301 * f.gets # => "e\n"
15302 * f.close
15303 *
15304 * Or by setting global variable <tt>$/</tt>:
15305 *
15306 * f = File.new('t.txt')
15307 * $/ = 'l'
15308 * f.gets # => "First l"
15309 * f.gets # => "ine\nSecond l"
15310 * f.gets # => "ine\n\nFourth l"
15311 * f.close
15312 *
15313 * ===== Special Line Separator Values
15314 *
15315 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15316 * accepts two special values for parameter +sep+:
15317 *
15318 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15319 *
15320 * f = File.new('t.txt')
15321 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15322 * f.close
15323 *
15324 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15325 * (paragraphs being separated by two consecutive line separators):
15326 *
15327 * f = File.new('t.txt')
15328 * f.gets('') # => "First line\nSecond line\n\n"
15329 * f.gets('') # => "Fourth line\nFifth line\n"
15330 * f.close
15331 *
15332 * ===== Line Limit
15333 *
15334 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15335 * uses an integer <i>line limit</i>,
15336 * which restricts the number of bytes that may be returned.
15337 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15338 * than the limit).
15339 *
15340 * The default limit value is <tt>-1</tt>;
15341 * any negative limit value means that there is no limit.
15342 *
15343 * If there is no limit, the line is determined only by +sep+.
15344 *
15345 * # Text with 1-byte characters.
15346 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15347 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15348 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15349 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15350 * # No more than one line.
15351 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15352 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15353 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15354 *
15355 * # Text with 3-byte characters, which will not be split.
15356 * File.read('t.ja') # => "こんにちは"
15357 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15358 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15359 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15360 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15361 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15362 *
15363 * ===== Line Separator and Line Limit
15364 *
15365 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15366 *
15367 * - Returns the next line as determined by line separator +sep+.
15368 * - But returns no more bytes than are allowed by the limit +limit+.
15369 *
15370 * Example:
15371 *
15372 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15373 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15374 *
15375 * ===== Line Number
15376 *
15377 * A readable \IO stream has a non-negative integer <i>line number</i>:
15378 *
15379 * - IO#lineno: Returns the line number.
15380 * - IO#lineno=: Resets and returns the line number.
15381 *
15382 * Unless modified by a call to method IO#lineno=,
15383 * the line number is the number of lines read
15384 * by certain line-oriented methods,
15385 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15386 *
15387 * - IO.foreach: Increments the line number on each call to the block.
15388 * - IO#each_line: Increments the line number on each call to the block.
15389 * - IO#gets: Increments the line number.
15390 * - IO#readline: Increments the line number.
15391 * - IO#readlines: Increments the line number for each line read.
15392 *
15393 * A new stream is initially has line number zero (and position zero);
15394 * method +rewind+ resets the line number (and position) to zero:
15395 *
15396 * f = File.new('t.txt')
15397 * f.lineno # => 0
15398 * f.gets # => "First line\n"
15399 * f.lineno # => 1
15400 * f.rewind
15401 * f.lineno # => 0
15402 * f.close
15403 *
15404 * Reading lines from a stream usually changes its line number:
15405 *
15406 * f = File.new('t.txt', 'r')
15407 * f.lineno # => 0
15408 * f.readline # => "This is line one.\n"
15409 * f.lineno # => 1
15410 * f.readline # => "This is the second line.\n"
15411 * f.lineno # => 2
15412 * f.readline # => "Here's the third line.\n"
15413 * f.lineno # => 3
15414 * f.eof? # => true
15415 * f.close
15416 *
15417 * Iterating over lines in a stream usually changes its line number:
15418 *
15419 * File.open('t.txt') do |f|
15420 * f.each_line do |line|
15421 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15422 * end
15423 * end
15424 *
15425 * Output:
15426 *
15427 * "position=11 eof?=false lineno=1"
15428 * "position=23 eof?=false lineno=2"
15429 * "position=24 eof?=false lineno=3"
15430 * "position=36 eof?=false lineno=4"
15431 * "position=47 eof?=true lineno=5"
15432 *
15433 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15434 * the line number does not affect where the next read or write will occur:
15435 *
15436 * f = File.new('t.txt')
15437 * f.lineno = 1000
15438 * f.lineno # => 1000
15439 * f.gets # => "First line\n"
15440 * f.lineno # => 1001
15441 * f.close
15442 *
15443 * Associated with the line number is the global variable <tt>$.</tt>:
15444 *
15445 * - When a stream is opened, <tt>$.</tt> is not set;
15446 * its value is left over from previous activity in the process:
15447 *
15448 * $. = 41
15449 * f = File.new('t.txt')
15450 * $. = 41
15451 * # => 41
15452 * f.close
15453 *
15454 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15455 *
15456 * f0 = File.new('t.txt')
15457 * f1 = File.new('t.dat')
15458 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15459 * $. # => 5
15460 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15461 * $. # => 1
15462 * f0.close
15463 * f1.close
15464 *
15465 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15466 *
15467 * f = File.new('t.txt')
15468 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15469 * $. # => 5
15470 * f.rewind
15471 * f.seek(0, :SET)
15472 * $. # => 5
15473 * f.close
15474 *
15475 * === Line Output
15476 *
15477 * You can write to an \IO stream line-by-line using this method:
15478 *
15479 * - IO#puts: Writes objects to the stream.
15480 *
15481 * == Character \IO
15482 *
15483 * You can process an \IO stream character-by-character using these methods:
15484 *
15485 * - IO#getc: Reads and returns the next character from the stream.
15486 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15487 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15488 * - IO#putc: Writes a character to the stream.
15489 * - IO#each_char: Reads each remaining character in the stream,
15490 * passing the character to the given block.
15491 *
15492 * == Byte \IO
15493 *
15494 * You can process an \IO stream byte-by-byte using these methods:
15495 *
15496 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15497 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15498 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15499 * - IO#each_byte: Reads each remaining byte in the stream,
15500 * passing the byte to the given block.
15501 *
15502 * == Codepoint \IO
15503 *
15504 * You can process an \IO stream codepoint-by-codepoint:
15505 *
15506 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15507 *
15508 * == What's Here
15509 *
15510 * First, what's elsewhere. Class \IO:
15511 *
15512 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
15513 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
15514 * which provides dozens of additional methods.
15515 *
15516 * Here, class \IO provides methods that are useful for:
15517 *
15518 * - {Creating}[rdoc-ref:IO@Creating]
15519 * - {Reading}[rdoc-ref:IO@Reading]
15520 * - {Writing}[rdoc-ref:IO@Writing]
15521 * - {Positioning}[rdoc-ref:IO@Positioning]
15522 * - {Iterating}[rdoc-ref:IO@Iterating]
15523 * - {Settings}[rdoc-ref:IO@Settings]
15524 * - {Querying}[rdoc-ref:IO@Querying]
15525 * - {Buffering}[rdoc-ref:IO@Buffering]
15526 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15527 * - {Other}[rdoc-ref:IO@Other]
15528 *
15529 * === Creating
15530 *
15531 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15532 * integer file descriptor.
15533 * - ::open: Creates a new \IO object.
15534 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15535 * - ::popen: Creates an \IO object to interact with a subprocess.
15536 * - ::select: Selects which given \IO instances are ready for reading,
15537 * writing, or have pending exceptions.
15538 *
15539 * === Reading
15540 *
15541 * - ::binread: Returns a binary string with all or a subset of bytes
15542 * from the given file.
15543 * - ::read: Returns a string with all or a subset of bytes from the given file.
15544 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15545 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15546 * - #getc: Returns the next character read from +self+ as a string.
15547 * - #gets: Returns the line read from +self+.
15548 * - #pread: Returns all or the next _n_ bytes read from +self+,
15549 * not updating the receiver's offset.
15550 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15551 * for a given _n_.
15552 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15553 * in non-block mode.
15554 * - #readbyte: Returns the next byte read from +self+;
15555 * same as #getbyte, but raises an exception on end-of-stream.
15556 * - #readchar: Returns the next character read from +self+;
15557 * same as #getc, but raises an exception on end-of-stream.
15558 * - #readline: Returns the next line read from +self+;
15559 * same as #getline, but raises an exception of end-of-stream.
15560 * - #readlines: Returns an array of all lines read read from +self+.
15561 * - #readpartial: Returns up to the given number of bytes from +self+.
15562 *
15563 * === Writing
15564 *
15565 * - ::binwrite: Writes the given string to the file at the given filepath,
15566 * in binary mode.
15567 * - ::write: Writes the given string to +self+.
15568 * - #<<: Appends the given string to +self+.
15569 * - #print: Prints last read line or given objects to +self+.
15570 * - #printf: Writes to +self+ based on the given format string and objects.
15571 * - #putc: Writes a character to +self+.
15572 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15573 * - #pwrite: Writes the given string at the given offset,
15574 * not updating the receiver's offset.
15575 * - #write: Writes one or more given strings to +self+.
15576 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15577 *
15578 * === Positioning
15579 *
15580 * - #lineno: Returns the current line number in +self+.
15581 * - #lineno=: Sets the line number is +self+.
15582 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15583 * - #pos=: Sets the byte offset in +self+.
15584 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15585 * - #rewind: Positions +self+ to the beginning of input.
15586 * - #seek: Sets the offset for +self+ relative to given position.
15587 *
15588 * === Iterating
15589 *
15590 * - ::foreach: Yields each line of given file to the block.
15591 * - #each (aliased as #each_line): Calls the given block
15592 * with each successive line in +self+.
15593 * - #each_byte: Calls the given block with each successive byte in +self+
15594 * as an integer.
15595 * - #each_char: Calls the given block with each successive character in +self+
15596 * as a string.
15597 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15598 * as an integer.
15599 *
15600 * === Settings
15601 *
15602 * - #autoclose=: Sets whether +self+ auto-closes.
15603 * - #binmode: Sets +self+ to binary mode.
15604 * - #close: Closes +self+.
15605 * - #close_on_exec=: Sets the close-on-exec flag.
15606 * - #close_read: Closes +self+ for reading.
15607 * - #close_write: Closes +self+ for writing.
15608 * - #set_encoding: Sets the encoding for +self+.
15609 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15610 * Unicode byte-order-mark.
15611 * - #sync=: Sets the sync-mode to the given value.
15612 *
15613 * === Querying
15614 *
15615 * - #autoclose?: Returns whether +self+ auto-closes.
15616 * - #binmode?: Returns whether +self+ is in binary mode.
15617 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15618 * - #closed?: Returns whether +self+ is closed.
15619 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15620 * - #external_encoding: Returns the external encoding object for +self+.
15621 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15622 * - #internal_encoding: Returns the internal encoding object for +self+.
15623 * - #pid: Returns the process ID of a child process associated with +self+,
15624 * if +self+ was created by ::popen.
15625 * - #stat: Returns the File::Stat object containing status information for +self+.
15626 * - #sync: Returns whether +self+ is in sync-mode.
15627 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15628 *
15629 * === Buffering
15630 *
15631 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15632 * - #flush: Flushes any buffered data within +self+ to the underlying
15633 * operating system.
15634 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15635 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15636 * - #ungetc: Prepends buffer for +self+ with given string.
15637 *
15638 * === Low-Level Access
15639 *
15640 * - ::sysopen: Opens the file given by its path,
15641 * returning the integer file descriptor.
15642 * - #advise: Announces the intention to access data from +self+ in a specific way.
15643 * - #fcntl: Passes a low-level command to the file specified
15644 * by the given file descriptor.
15645 * - #ioctl: Passes a low-level command to the device specified
15646 * by the given file descriptor.
15647 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15648 * - #sysseek: Sets the offset for +self+.
15649 * - #syswrite: Writes the given string to +self+ using a low-level write.
15650 *
15651 * === Other
15652 *
15653 * - ::copy_stream: Copies data from a source to a destination,
15654 * each of which is a filepath or an \IO-like object.
15655 * - ::try_convert: Returns a new \IO object resulting from converting
15656 * the given object.
15657 * - #inspect: Returns the string representation of +self+.
15658 *
15659 */
15660
15661void
15662Init_IO(void)
15663{
15664 VALUE rb_cARGF;
15665#ifdef __CYGWIN__
15666#include <sys/cygwin.h>
15667 static struct __cygwin_perfile pf[] =
15668 {
15669 {"", O_RDONLY | O_BINARY},
15670 {"", O_WRONLY | O_BINARY},
15671 {"", O_RDWR | O_BINARY},
15672 {"", O_APPEND | O_BINARY},
15673 {NULL, 0}
15674 };
15675 cygwin_internal(CW_PERFILE, pf);
15676#endif
15677
15680
15681 id_write = rb_intern_const("write");
15682 id_read = rb_intern_const("read");
15683 id_getc = rb_intern_const("getc");
15684 id_flush = rb_intern_const("flush");
15685 id_readpartial = rb_intern_const("readpartial");
15686 id_set_encoding = rb_intern_const("set_encoding");
15687 id_fileno = rb_intern_const("fileno");
15688
15689 rb_define_global_function("syscall", rb_f_syscall, -1);
15690
15691 rb_define_global_function("open", rb_f_open, -1);
15692 rb_define_global_function("printf", rb_f_printf, -1);
15693 rb_define_global_function("print", rb_f_print, -1);
15694 rb_define_global_function("putc", rb_f_putc, 1);
15695 rb_define_global_function("puts", rb_f_puts, -1);
15696 rb_define_global_function("gets", rb_f_gets, -1);
15697 rb_define_global_function("readline", rb_f_readline, -1);
15698 rb_define_global_function("select", rb_f_select, -1);
15699
15700 rb_define_global_function("readlines", rb_f_readlines, -1);
15701
15702 rb_define_global_function("`", rb_f_backquote, 1);
15703
15704 rb_define_global_function("p", rb_f_p, -1);
15705 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15706
15709
15710 /* Can be raised by IO operations when IO#timeout= is set. */
15712
15713 /* Readable event mask for IO#wait. */
15714 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15715 /* Writable event mask for IO#wait. */
15716 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15717 /* Priority event mask for IO#wait. */
15718 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15719
15720 /* exception to wait for reading. see IO.select. */
15722 /* exception to wait for writing. see IO.select. */
15724 /* exception to wait for reading by EAGAIN. see IO.select. */
15725 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15726 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15727 /* exception to wait for writing by EAGAIN. see IO.select. */
15728 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15729 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15730#if EAGAIN == EWOULDBLOCK
15731 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15732 /* same as IO::EAGAINWaitReadable */
15733 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15734 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15735 /* same as IO::EAGAINWaitWritable */
15736 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15737#else
15738 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15739 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15740 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15741 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15742 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15743 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15744#endif
15745 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15746 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15747 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15748 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15749 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15750 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15751
15752#if 0
15753 /* This is necessary only for forcing rdoc handle File::open */
15754 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15755#endif
15756
15757 rb_define_alloc_func(rb_cIO, io_alloc);
15758 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15759 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15760 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15761 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15762 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15763 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15764 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15765 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15766 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15767 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15768 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15769 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15770 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15771 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15772 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15773
15774 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15775
15777 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15778
15779 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15780 rb_vm_register_global_object(rb_default_rs);
15781 rb_rs = rb_default_rs;
15783 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15784 rb_gvar_ractor_local("$/"); // not local but ractor safe
15785 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15786 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15787 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
15788
15789 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15790 rb_gvar_ractor_local("$_");
15791 rb_gvar_box_dynamic("$_");
15792
15793 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15794 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15795
15796 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15797 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15798 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15799 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15800
15801 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15802 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15803 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15804 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15805 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15806
15807 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15808 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15809
15810 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15811 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15812
15813 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15814 rb_define_alias(rb_cIO, "to_i", "fileno");
15815 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15816
15817 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15818 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15819
15820 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15821 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15822 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15823 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15824
15825 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15826 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15827
15828 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15829
15830 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15831 rb_define_method(rb_cIO, "read", io_read, -1);
15832 rb_define_method(rb_cIO, "write", io_write_m, -1);
15833 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15834 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15835 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15836 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15837 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15838 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15839 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15841 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15842 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15843 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15844 /* Set I/O position from the beginning */
15845 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15846 /* Set I/O position from the current position */
15847 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15848 /* Set I/O position from the end */
15849 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15850#ifdef SEEK_DATA
15851 /* Set I/O position to the next location containing data */
15852 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15853#endif
15854#ifdef SEEK_HOLE
15855 /* Set I/O position to the next hole */
15856 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15857#endif
15858 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15859 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15860 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15861 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15862 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15863
15864 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15865 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15866
15867 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15868 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15869 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15870 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15871
15872 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15873 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15874 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15875 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15876 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15877 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15878
15879 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15880 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15881 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15882
15883 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15884 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15885
15886 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15887
15888 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15889 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15890 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15891 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15892
15893 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15894 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15895
15896 rb_define_method(rb_cIO, "wait", io_wait, -1);
15897
15898 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15899 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15900 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15901
15902 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15903 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15904 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15905 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15906
15907 rb_gvar_ractor_local("$stdin");
15908 rb_gvar_ractor_local("$stdout");
15909 rb_gvar_ractor_local("$>");
15910 rb_gvar_ractor_local("$stderr");
15911
15913 rb_stdin = rb_io_prep_stdin();
15915 rb_stdout = rb_io_prep_stdout();
15917 rb_stderr = rb_io_prep_stderr();
15918
15919 orig_stdout = rb_stdout;
15920 orig_stderr = rb_stderr;
15921
15922 /* Holds the original stdin */
15924 /* Holds the original stdout */
15926 /* Holds the original stderr */
15928
15929#if 0
15930 /* Hack to get rdoc to regard ARGF as a class: */
15931 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15932#endif
15933
15934 rb_cARGF = rb_class_new(rb_cObject);
15935 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15936 rb_define_alloc_func(rb_cARGF, argf_alloc);
15937
15939
15940 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15941 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15942 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15943 rb_define_alias(rb_cARGF, "inspect", "to_s");
15944 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15945
15946 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15947 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15948 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15949 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15950 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15951 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15952 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15953 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15954 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15955
15956 rb_define_method(rb_cARGF, "read", argf_read, -1);
15957 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15958 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15959 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15960 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15961 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15962 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15963 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15964 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15965 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15966 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15967 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15968 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15969 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15970 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15971 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15972 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15973 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15974 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15975 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15976
15977 rb_define_method(rb_cARGF, "write", argf_write, -1);
15978 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15979 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15980 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15981 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15982
15983 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15984 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15985 rb_define_method(rb_cARGF, "file", argf_file, 0);
15986 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15987 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15988 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15989
15990 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15991 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15992
15993 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15994 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15995
15996 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15997 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15998 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15999
16000 argf = rb_class_new_instance(0, 0, rb_cARGF);
16001
16003 /*
16004 * ARGF is a stream designed for use in scripts that process files given
16005 * as command-line arguments or passed in via STDIN.
16006 *
16007 * See ARGF (the class) for more details.
16008 */
16010
16011 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16012 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16013 ARGF_SET(filename, rb_str_new2("-"));
16014
16015 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16016 rb_gvar_ractor_local("$-i");
16017
16018 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16019
16020#if defined (_WIN32) || defined(__CYGWIN__)
16021 atexit(pipe_atexit);
16022#endif
16023
16024 Init_File();
16025
16026 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16027
16028 sym_mode = ID2SYM(rb_intern_const("mode"));
16029 sym_perm = ID2SYM(rb_intern_const("perm"));
16030 sym_flags = ID2SYM(rb_intern_const("flags"));
16031 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16032 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16033 sym_encoding = ID2SYM(rb_id_encoding());
16034 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16035 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16036 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16037 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16038 sym_normal = ID2SYM(rb_intern_const("normal"));
16039 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16040 sym_random = ID2SYM(rb_intern_const("random"));
16041 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16042 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16043 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16044 sym_SET = ID2SYM(rb_intern_const("SET"));
16045 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16046 sym_END = ID2SYM(rb_intern_const("END"));
16047#ifdef SEEK_DATA
16048 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16049#endif
16050#ifdef SEEK_HOLE
16051 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16052#endif
16053 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16054 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16055}
16056
16057#include "io.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:117
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1603
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1396
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:781
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1427
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1532
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2771
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:3074
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:3061
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1018
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2850
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1676
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1678
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3898
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:477
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:509
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1437
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:661
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3967
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:14735
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1424
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:4057
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:3973
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:476
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1427
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:14729
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2293
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1425
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:467
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1447
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:60
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3341
VALUE rb_cObject
Object class.
Definition object.c:61
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:646
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2255
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2296
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:2284
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:235
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:553
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:657
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:1313
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:3322
VALUE rb_cFile
File class.
Definition file.c:192
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:3335
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:468
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:456
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition encoding.h:571
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1344
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3938
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:826
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2663
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2124
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1485
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1781
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1825
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1960
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2714
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:2023
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2977
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4343
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4349
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1742
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1792
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1121
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:1088
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:242
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8623
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4327
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:8756
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2383
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9185
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:5199
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5104
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:9366
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:2725
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:9165
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:6414
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6368
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5263
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7416
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10446
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:461
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:204
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:7299
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:7306
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5781
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:2055
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2049
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:3099
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1168
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:682
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:3836
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1682
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1533
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1005
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1520
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1996
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3604
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4306
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3423
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:3778
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2976
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3286
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3405
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:2746
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1720
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1515
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1852
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1483
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:1636
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1466
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3194
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1630
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1489
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2948
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:441
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:2064
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:500
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3485
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:690
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:4125
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:855
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:162
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6500
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:812
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:858
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:782
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1070
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:6633
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
Definition io.h:260
rb_io_event
Type of events that an IO can wait.
Definition io.h:96
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:97
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:99
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:98
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:168
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:252
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:442
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:1016
#define FMODE_TTY
The IO is a TTY.
Definition io.h:192
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:215
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1025
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:1622
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:7116
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:6782
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2928
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:165
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
Definition io.c:9412
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:207
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:465
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:200
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:179
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1683
int capa
Designed capacity of the buffer.
Definition io.h:11
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:436
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1642
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:186
int off
Offset inside of ptr.
Definition io.h:5
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:3002
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:6907
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:789
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
Definition io.h:223
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:243
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
Definition io.c:5701
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:818
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5889
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:887
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2048
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:997
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:229
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:824
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3448
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1578
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:9278
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:835
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1049
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:1698
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:797
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1543
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7403
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1483
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:1085
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:1145
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:1133
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:1121
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2063
#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:1421
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1376
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:409
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:450
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:81
#define RUBY_TYPED_FREE_IMMEDIATELY
Macros to see if each corresponding flag is defined.
Definition rtypeddata.h:122
#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:578
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14695
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9064
#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:458
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:997
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:509
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:747
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:973
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:733
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:72
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:777
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:1009
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
Definition scheduler.c:466
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:985
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
Definition scheduler.c:471
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:753
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
Definition scheduler.c:1029
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:4555
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:230
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:229
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
Decomposed encoding flags (e.g.
Definition io.h:134
int ecflags
Flags.
Definition io.h:144
VALUE ecopts
Flags as Ruby hash.
Definition io.h:152
rb_encoding * enc2
External encoding.
Definition io.h:138
rb_encoding * enc
Internal encoding.
Definition io.h:136
IO buffers.
Definition io.h:109
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:112
int off
Offset inside of ptr.
Definition io.h:115
int len
Length of the buffer.
Definition io.h:118
int capa
Designed capacity of the buffer.
Definition io.h:121
Ruby's IO, metadata and buffers.
Definition io.h:295
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:330
enum rb_io_mode mode
mode flags: FMODE_XXXs
Definition io.h:310
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:326
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:352
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:363
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:348
VALUE self
The IO's Ruby level counterpart.
Definition io.h:298
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:400
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:406
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:302
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:390
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:345
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:376
int fd
file descriptor.
Definition io.h:306
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:337
int lineno
number of lines read
Definition io.h:318
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
Definition io.h:131
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:372
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:359
rb_pid_t pid
child's pid (for pipes)
Definition io.h:314
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:383
VALUE pathv
pathname for file
Definition io.h:322
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:307
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h: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