Ruby: io.c Source File

Ruby 3.3.5p100 (2024-09-03 revision ef084cc8f4958c1b6e4ead99136631bef6d8ddba)

io.c
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
16#include "ruby/fiber/scheduler.h"
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107#endif
108
109#include "ruby/internal/stdbool.h"
110#include "ccan/list/list.h"
111#include "dln.h"
112#include "encindex.h"
113#include "id.h"
114#include "internal.h"
115#include "internal/encoding.h"
116#include "internal/error.h"
117#include "internal/inits.h"
118#include "internal/io.h"
119#include "internal/numeric.h"
120#include "internal/object.h"
121#include "internal/process.h"
122#include "internal/thread.h"
123#include "internal/transcode.h"
124#include "internal/variable.h"
125#include "ruby/io.h"
126#include "ruby/io/buffer.h"
127#include "ruby/missing.h"
128#include "ruby/thread.h"
129#include "ruby/util.h"
130#include "ruby_atomic.h"
131#include "ruby/ractor.h"
132
133#if !USE_POLL
134# include "vm_core.h"
135#endif
136
137#include "builtin.h"
138
139#ifndef O_ACCMODE
140#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
141#endif
142
143#ifndef PIPE_BUF
144# ifdef _POSIX_PIPE_BUF
145# define PIPE_BUF _POSIX_PIPE_BUF
146# else
147# define PIPE_BUF 512 /* is this ok? */
148# endif
149#endif
150
151#ifndef EWOULDBLOCK
152# define EWOULDBLOCK EAGAIN
153#endif
154
155#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
156/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
157off_t __syscall(quad_t number, ...);
158#endif
159
160#define IO_RBUF_CAPA_MIN 8192
161#define IO_CBUF_CAPA_MIN (128*1024)
162#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
163#define IO_WBUF_CAPA_MIN 8192
164
165#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
166
167/* define system APIs */
168#ifdef _WIN32
169#undef open
170#define open rb_w32_uopen
171#undef rename
172#define rename(f, t) rb_w32_urename((f), (t))
173#include "win32/file.h"
174#endif
175
176 VALUE rb_cIO;
177 VALUE rb_eEOFError;
178 VALUE rb_eIOError;
179 VALUE rb_eIOTimeoutError;
180 VALUE rb_mWaitReadable;
181 VALUE rb_mWaitWritable;
182
183static VALUE rb_eEAGAINWaitReadable;
184static VALUE rb_eEAGAINWaitWritable;
185static VALUE rb_eEWOULDBLOCKWaitReadable;
186static VALUE rb_eEWOULDBLOCKWaitWritable;
187static VALUE rb_eEINPROGRESSWaitWritable;
188static VALUE rb_eEINPROGRESSWaitReadable;
189
190 VALUE rb_stdin, rb_stdout, rb_stderr;
191static VALUE orig_stdout, orig_stderr;
192
193 VALUE rb_output_fs;
194 VALUE rb_rs;
195 VALUE rb_output_rs;
196 VALUE rb_default_rs;
197
198static VALUE argf;
199
200static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
201static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
202static VALUE sym_textmode, sym_binmode, sym_autoclose;
203static VALUE sym_SET, sym_CUR, sym_END;
204static VALUE sym_wait_readable, sym_wait_writable;
205#ifdef SEEK_DATA
206static VALUE sym_DATA;
207#endif
208#ifdef SEEK_HOLE
209static VALUE sym_HOLE;
210#endif
211
212static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
213
214 struct argf {
215 VALUE filename, current_file;
216 long last_lineno; /* $. */
217 long lineno;
218 VALUE argv;
219 VALUE inplace;
220 struct rb_io_encoding encs;
221 int8_t init_p, next_p, binmode;
222};
223
224static rb_atomic_t max_file_descriptor = NOFILE;
225void
226rb_update_max_fd(int fd)
227{
228 rb_atomic_t afd = (rb_atomic_t)fd;
229 rb_atomic_t max_fd = max_file_descriptor;
230 int err;
231
232 if (fd < 0 || afd <= max_fd)
233 return;
234
235#if defined(HAVE_FCNTL) && defined(F_GETFL)
236 err = fcntl(fd, F_GETFL) == -1;
237#else
238 {
239 struct stat buf;
240 err = fstat(fd, &buf) != 0;
241 }
242#endif
243 if (err && errno == EBADF) {
244 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
245 }
246
247 while (max_fd < afd) {
248 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
249 }
250}
251
252void
253rb_maygvl_fd_fix_cloexec(int fd)
254{
255 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
256#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
257 int flags, flags2, ret;
258 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
259 if (flags == -1) {
260 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
261 }
262 if (fd <= 2)
263 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
264 else
265 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
266 if (flags != flags2) {
267 ret = fcntl(fd, F_SETFD, flags2);
268 if (ret != 0) {
269 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
270 }
271 }
272#endif
273}
274
275void
276rb_fd_fix_cloexec(int fd)
277{
278 rb_maygvl_fd_fix_cloexec(fd);
279 rb_update_max_fd(fd);
280}
281
282/* this is only called once */
283static int
284rb_fix_detect_o_cloexec(int fd)
285{
286#if defined(O_CLOEXEC) && defined(F_GETFD)
287 int flags = fcntl(fd, F_GETFD);
288
289 if (flags == -1)
290 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
291
292 if (flags & FD_CLOEXEC)
293 return 1;
294#endif /* fall through if O_CLOEXEC does not work: */
295 rb_maygvl_fd_fix_cloexec(fd);
296 return 0;
297}
298
299static inline bool
300io_again_p(int e)
301{
302 return (e == EWOULDBLOCK) || (e == EAGAIN);
303}
304
305int
306rb_cloexec_open(const char *pathname, int flags, mode_t mode)
307{
308 int ret;
309 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
310
311 static const int retry_interval = 0;
312 static const int retry_max_count = 10000;
313
314 int retry_count = 0;
315
316#ifdef O_CLOEXEC
317 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
318 flags |= O_CLOEXEC;
319#elif defined O_NOINHERIT
320 flags |= O_NOINHERIT;
321#endif
322
323 while ((ret = open(pathname, flags, mode)) == -1) {
324 int e = errno;
325 if (!io_again_p(e)) break;
326 if (retry_count++ >= retry_max_count) break;
327
328 sleep(retry_interval);
329 }
330
331 if (ret < 0) return ret;
332 if (ret <= 2 || o_cloexec_state == 0) {
333 rb_maygvl_fd_fix_cloexec(ret);
334 }
335 else if (o_cloexec_state > 0) {
336 return ret;
337 }
338 else {
339 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
340 }
341 return ret;
342}
343
344int
345rb_cloexec_dup(int oldfd)
346{
347 /* Don't allocate standard file descriptors: 0, 1, 2 */
348 return rb_cloexec_fcntl_dupfd(oldfd, 3);
349}
350
351int
352rb_cloexec_dup2(int oldfd, int newfd)
353{
354 int ret;
355
356 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
357 * rb_cloexec_dup2 succeeds as dup2. */
358 if (oldfd == newfd) {
359 ret = newfd;
360 }
361 else {
362#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
363 static int try_dup3 = 1;
364 if (2 < newfd && try_dup3) {
365 ret = dup3(oldfd, newfd, O_CLOEXEC);
366 if (ret != -1)
367 return ret;
368 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
369 if (errno == ENOSYS) {
370 try_dup3 = 0;
371 ret = dup2(oldfd, newfd);
372 }
373 }
374 else {
375 ret = dup2(oldfd, newfd);
376 }
377#else
378 ret = dup2(oldfd, newfd);
379#endif
380 if (ret < 0) return ret;
381 }
382 rb_maygvl_fd_fix_cloexec(ret);
383 return ret;
384}
385
386static int
387rb_fd_set_nonblock(int fd)
388{
389#ifdef _WIN32
390 return rb_w32_set_nonblock(fd);
391#elif defined(F_GETFL)
392 int oflags = fcntl(fd, F_GETFL);
393
394 if (oflags == -1)
395 return -1;
396 if (oflags & O_NONBLOCK)
397 return 0;
398 oflags |= O_NONBLOCK;
399 return fcntl(fd, F_SETFL, oflags);
400#endif
401 return 0;
402}
403
404int
405rb_cloexec_pipe(int descriptors[2])
406{
407#ifdef HAVE_PIPE2
408 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
409#else
410 int result = pipe(descriptors);
411#endif
412
413 if (result < 0)
414 return result;
415
416#ifdef __CYGWIN__
417 if (result == 0 && descriptors[1] == -1) {
418 close(descriptors[0]);
419 descriptors[0] = -1;
420 errno = ENFILE;
421 return -1;
422 }
423#endif
424
425#ifndef HAVE_PIPE2
426 rb_maygvl_fd_fix_cloexec(descriptors[0]);
427 rb_maygvl_fd_fix_cloexec(descriptors[1]);
428
429#ifndef _WIN32
430 rb_fd_set_nonblock(descriptors[0]);
431 rb_fd_set_nonblock(descriptors[1]);
432#endif
433#endif
434
435 return result;
436}
437
438int
439rb_cloexec_fcntl_dupfd(int fd, int minfd)
440{
441 int ret;
442
443#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
444 static int try_dupfd_cloexec = 1;
445 if (try_dupfd_cloexec) {
446 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
447 if (ret != -1) {
448 if (ret <= 2)
449 rb_maygvl_fd_fix_cloexec(ret);
450 return ret;
451 }
452 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
453 if (errno == EINVAL) {
454 ret = fcntl(fd, F_DUPFD, minfd);
455 if (ret != -1) {
456 try_dupfd_cloexec = 0;
457 }
458 }
459 }
460 else {
461 ret = fcntl(fd, F_DUPFD, minfd);
462 }
463#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
464 ret = fcntl(fd, F_DUPFD, minfd);
465#else
466 ret = dup(fd);
467 if (ret >= 0 && ret < minfd) {
468 const int prev_fd = ret;
469 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
470 close(prev_fd);
471 }
472 return ret;
473#endif
474 if (ret < 0) return ret;
475 rb_maygvl_fd_fix_cloexec(ret);
476 return ret;
477}
478
479#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
480#define ARGF argf_of(argf)
481
482#define GetWriteIO(io) rb_io_get_write_io(io)
483
484#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
485#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
486#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
487#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
488
489#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
490#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
491#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
492
493#if defined(_WIN32)
494#define WAIT_FD_IN_WIN32(fptr) \
495 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
496#else
497#define WAIT_FD_IN_WIN32(fptr)
498#endif
499
500#define READ_CHECK(fptr) do {\
501 if (!READ_DATA_PENDING(fptr)) {\
502 WAIT_FD_IN_WIN32(fptr);\
503 rb_io_check_closed(fptr);\
504 }\
505} while(0)
506
507#ifndef S_ISSOCK
508# ifdef _S_ISSOCK
509# define S_ISSOCK(m) _S_ISSOCK(m)
510# else
511# ifdef _S_IFSOCK
512# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
513# else
514# ifdef S_IFSOCK
515# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
516# endif
517# endif
518# endif
519#endif
520
521static int io_fflush(rb_io_t *);
522static rb_io_t *flush_before_seek(rb_io_t *fptr);
523
524#define FMODE_SIGNAL_ON_EPIPE (1<<17)
525
526#define fptr_signal_on_epipe(fptr) \
527 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
528
529#define fptr_set_signal_on_epipe(fptr, flag) \
530 ((flag) ? \
531 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
532 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
533
534extern ID ruby_static_id_signo;
535
536NORETURN(static void raise_on_write(rb_io_t *fptr, int e, VALUE errinfo));
537static void
538raise_on_write(rb_io_t *fptr, int e, VALUE errinfo)
539{
540#if defined EPIPE
541 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
542 const VALUE sig =
543# if defined SIGPIPE
544 INT2FIX(SIGPIPE) - INT2FIX(0) +
545# endif
546 INT2FIX(0);
547 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
548 }
549#endif
550 rb_exc_raise(errinfo);
551}
552
553#define rb_sys_fail_on_write(fptr) \
554 do { \
555 int e = errno; \
556 raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
557 } while (0)
558
559#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
560#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
561#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
562# define RUBY_CRLF_ENVIRONMENT 1
563#else
564# define RUBY_CRLF_ENVIRONMENT 0
565#endif
566
567#if RUBY_CRLF_ENVIRONMENT
568/* Windows */
569# define DEFAULT_TEXTMODE FMODE_TEXTMODE
570# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
571/*
572 * CRLF newline is set as default newline decorator.
573 * If only CRLF newline conversion is needed, we use binary IO process
574 * with OS's text mode for IO performance improvement.
575 * If encoding conversion is needed or a user sets text mode, we use encoding
576 * conversion IO process and universal newline decorator by default.
577 */
578#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
579#define WRITECONV_MASK ( \
580 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
581 ECONV_STATEFUL_DECORATOR_MASK|\
582 0)
583#define NEED_WRITECONV(fptr) ( \
584 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
585 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
586 0)
587#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
588
589#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
590 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
591 if (((fptr)->mode & FMODE_READABLE) &&\
592 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
593 setmode((fptr)->fd, O_BINARY);\
594 }\
595 else {\
596 setmode((fptr)->fd, O_TEXT);\
597 }\
598 }\
599} while(0)
600
601#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
602 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
603 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
604 }\
605} while(0)
606
607/*
608 * IO unread with taking care of removed '\r' in text mode.
609 */
610static void
611io_unread(rb_io_t *fptr)
612{
613 rb_off_t r, pos;
614 ssize_t read_size;
615 long i;
616 long newlines = 0;
617 long extra_max;
618 char *p;
619 char *buf;
620
621 rb_io_check_closed(fptr);
622 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
623 return;
624 }
625
626 errno = 0;
627 if (!rb_w32_fd_is_text(fptr->fd)) {
628 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
629 if (r < 0 && errno) {
630 if (errno == ESPIPE)
631 fptr->mode |= FMODE_DUPLEX;
632 return;
633 }
634
635 fptr->rbuf.off = 0;
636 fptr->rbuf.len = 0;
637 return;
638 }
639
640 pos = lseek(fptr->fd, 0, SEEK_CUR);
641 if (pos < 0 && errno) {
642 if (errno == ESPIPE)
643 fptr->mode |= FMODE_DUPLEX;
644 return;
645 }
646
647 /* add extra offset for removed '\r' in rbuf */
648 extra_max = (long)(pos - fptr->rbuf.len);
649 p = fptr->rbuf.ptr + fptr->rbuf.off;
650
651 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
652 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
653 newlines++;
654 }
655
656 for (i = 0; i < fptr->rbuf.len; i++) {
657 if (*p == '\n') newlines++;
658 if (extra_max == newlines) break;
659 p++;
660 }
661
662 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
663 while (newlines >= 0) {
664 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
665 if (newlines == 0) break;
666 if (r < 0) {
667 newlines--;
668 continue;
669 }
670 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
671 if (read_size < 0) {
672 int e = errno;
673 free(buf);
674 rb_syserr_fail_path(e, fptr->pathv);
675 }
676 if (read_size == fptr->rbuf.len) {
677 lseek(fptr->fd, r, SEEK_SET);
678 break;
679 }
680 else {
681 newlines--;
682 }
683 }
684 free(buf);
685 fptr->rbuf.off = 0;
686 fptr->rbuf.len = 0;
687 return;
688}
689
690/*
691 * We use io_seek to back cursor position when changing mode from text to binary,
692 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
693 * conversion for working properly with mode change.
694 *
695 * Return previous translation mode.
696 */
697static inline int
698set_binary_mode_with_seek_cur(rb_io_t *fptr)
699{
700 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
701
702 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
703 return setmode(fptr->fd, O_BINARY);
704 }
705 flush_before_seek(fptr);
706 return setmode(fptr->fd, O_BINARY);
707}
708#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
709
710#else
711/* Unix */
712# define DEFAULT_TEXTMODE 0
713#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
714#define NEED_WRITECONV(fptr) ( \
715 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
716 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
717 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
718 0)
719#define SET_BINARY_MODE(fptr) (void)(fptr)
720#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
721#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
722#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
723#endif
724
725#if !defined HAVE_SHUTDOWN && !defined shutdown
726#define shutdown(a,b) 0
727#endif
728
729#if defined(_WIN32)
730#define is_socket(fd, path) rb_w32_is_socket(fd)
731#elif !defined(S_ISSOCK)
732#define is_socket(fd, path) 0
733#else
734static int
735is_socket(int fd, VALUE path)
736{
737 struct stat sbuf;
738 if (fstat(fd, &sbuf) < 0)
739 rb_sys_fail_path(path);
740 return S_ISSOCK(sbuf.st_mode);
741}
742#endif
743
744static const char closed_stream[] = "closed stream";
745
746static void
747io_fd_check_closed(int fd)
748{
749 if (fd < 0) {
750 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
751 rb_raise(rb_eIOError, closed_stream);
752 }
753}
754
755void
756rb_eof_error(void)
757{
758 rb_raise(rb_eEOFError, "end of file reached");
759}
760
761 VALUE
762rb_io_taint_check(VALUE io)
763{
764 rb_check_frozen(io);
765 return io;
766}
767
768void
769rb_io_check_initialized(rb_io_t *fptr)
770{
771 if (!fptr) {
772 rb_raise(rb_eIOError, "uninitialized stream");
773 }
774}
775
776void
777rb_io_check_closed(rb_io_t *fptr)
778{
779 rb_io_check_initialized(fptr);
780 io_fd_check_closed(fptr->fd);
781}
782
783static rb_io_t *
784rb_io_get_fptr(VALUE io)
785{
786 rb_io_t *fptr = RFILE(io)->fptr;
787 rb_io_check_initialized(fptr);
788 return fptr;
789}
790
791 VALUE
792rb_io_get_io(VALUE io)
793{
794 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
795}
796
797 VALUE
798rb_io_check_io(VALUE io)
799{
800 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
801}
802
803 VALUE
804rb_io_get_write_io(VALUE io)
805{
806 VALUE write_io;
807 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
808 if (write_io) {
809 return write_io;
810 }
811 return io;
812}
813
814 VALUE
815rb_io_set_write_io(VALUE io, VALUE w)
816{
817 VALUE write_io;
818 rb_io_t *fptr = rb_io_get_fptr(io);
819 if (!RTEST(w)) {
820 w = 0;
821 }
822 else {
823 GetWriteIO(w);
824 }
825 write_io = fptr->tied_io_for_writing;
826 fptr->tied_io_for_writing = w;
827 return write_io ? write_io : Qnil;
828}
829
830/*
831 * call-seq:
832 * timeout -> duration or nil
833 *
834 * Get the internal timeout duration or nil if it was not set.
835 *
836 */
837 VALUE
838rb_io_timeout(VALUE self)
839{
840 rb_io_t *fptr = rb_io_get_fptr(self);
841
842 return fptr->timeout;
843}
844
845/*
846 * call-seq:
847 * timeout = duration -> duration
848 * timeout = nil -> nil
849 *
850 * Sets the internal timeout to the specified duration or nil. The timeout
851 * applies to all blocking operations where possible.
852 *
853 * When the operation performs longer than the timeout set, IO::TimeoutError
854 * is raised.
855 *
856 * This affects the following methods (but is not limited to): #gets, #puts,
857 * #read, #write, #wait_readable and #wait_writable. This also affects
858 * blocking socket operations like Socket#accept and Socket#connect.
859 *
860 * Some operations like File#open and IO#close are not affected by the
861 * timeout. A timeout during a write operation may leave the IO in an
862 * inconsistent state, e.g. data was partially written. Generally speaking, a
863 * timeout is a last ditch effort to prevent an application from hanging on
864 * slow I/O operations, such as those that occur during a slowloris attack.
865 */
866 VALUE
867rb_io_set_timeout(VALUE self, VALUE timeout)
868{
869 // Validate it:
870 if (RTEST(timeout)) {
871 rb_time_interval(timeout);
872 }
873
874 rb_io_t *fptr = rb_io_get_fptr(self);
875
876 fptr->timeout = timeout;
877
878 return self;
879}
880
881/*
882 * call-seq:
883 * IO.try_convert(object) -> new_io or nil
884 *
885 * Attempts to convert +object+ into an \IO object via method +to_io+;
886 * returns the new \IO object if successful, or +nil+ otherwise:
887 *
888 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
889 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
890 * IO.try_convert('STDOUT') # => nil
891 *
892 */
893static VALUE
894rb_io_s_try_convert(VALUE dummy, VALUE io)
895{
896 return rb_io_check_io(io);
897}
898
899#if !RUBY_CRLF_ENVIRONMENT
900static void
901io_unread(rb_io_t *fptr)
902{
903 rb_off_t r;
904 rb_io_check_closed(fptr);
905 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
906 return;
907 /* xxx: target position may be negative if buffer is filled by ungetc */
908 errno = 0;
909 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
910 if (r < 0 && errno) {
911 if (errno == ESPIPE)
912 fptr->mode |= FMODE_DUPLEX;
913 return;
914 }
915 fptr->rbuf.off = 0;
916 fptr->rbuf.len = 0;
917 return;
918}
919#endif
920
921static rb_encoding *io_input_encoding(rb_io_t *fptr);
922
923static void
924io_ungetbyte(VALUE str, rb_io_t *fptr)
925{
926 long len = RSTRING_LEN(str);
927
928 if (fptr->rbuf.ptr == NULL) {
929 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
930 fptr->rbuf.off = 0;
931 fptr->rbuf.len = 0;
932#if SIZEOF_LONG > SIZEOF_INT
933 if (len > INT_MAX)
934 rb_raise(rb_eIOError, "ungetbyte failed");
935#endif
936 if (len > min_capa)
937 fptr->rbuf.capa = (int)len;
938 else
939 fptr->rbuf.capa = min_capa;
940 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
941 }
942 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
943 rb_raise(rb_eIOError, "ungetbyte failed");
944 }
945 if (fptr->rbuf.off < len) {
946 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
947 fptr->rbuf.ptr+fptr->rbuf.off,
948 char, fptr->rbuf.len);
949 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
950 }
951 fptr->rbuf.off-=(int)len;
952 fptr->rbuf.len+=(int)len;
953 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
954}
955
956static rb_io_t *
957flush_before_seek(rb_io_t *fptr)
958{
959 if (io_fflush(fptr) < 0)
960 rb_sys_fail_on_write(fptr);
961 io_unread(fptr);
962 errno = 0;
963 return fptr;
964}
965
966#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
967#define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
968
969#ifndef SEEK_CUR
970# define SEEK_SET 0
971# define SEEK_CUR 1
972# define SEEK_END 2
973#endif
974
975void
976rb_io_check_char_readable(rb_io_t *fptr)
977{
978 rb_io_check_closed(fptr);
979 if (!(fptr->mode & FMODE_READABLE)) {
980 rb_raise(rb_eIOError, "not opened for reading");
981 }
982 if (fptr->wbuf.len) {
983 if (io_fflush(fptr) < 0)
984 rb_sys_fail_on_write(fptr);
985 }
986 if (fptr->tied_io_for_writing) {
987 rb_io_t *wfptr;
988 GetOpenFile(fptr->tied_io_for_writing, wfptr);
989 if (io_fflush(wfptr) < 0)
990 rb_sys_fail_on_write(wfptr);
991 }
992}
993
994void
995rb_io_check_byte_readable(rb_io_t *fptr)
996{
997 rb_io_check_char_readable(fptr);
998 if (READ_CHAR_PENDING(fptr)) {
999 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1000 }
1001}
1002
1003void
1004rb_io_check_readable(rb_io_t *fptr)
1005{
1006 rb_io_check_byte_readable(fptr);
1007}
1008
1009static rb_encoding*
1010io_read_encoding(rb_io_t *fptr)
1011{
1012 if (fptr->encs.enc) {
1013 return fptr->encs.enc;
1014 }
1015 return rb_default_external_encoding();
1016}
1017
1018static rb_encoding*
1019io_input_encoding(rb_io_t *fptr)
1020{
1021 if (fptr->encs.enc2) {
1022 return fptr->encs.enc2;
1023 }
1024 return io_read_encoding(fptr);
1025}
1026
1027void
1028rb_io_check_writable(rb_io_t *fptr)
1029{
1030 rb_io_check_closed(fptr);
1031 if (!(fptr->mode & FMODE_WRITABLE)) {
1032 rb_raise(rb_eIOError, "not opened for writing");
1033 }
1034 if (fptr->rbuf.len) {
1035 io_unread(fptr);
1036 }
1037}
1038
1039int
1040rb_io_read_pending(rb_io_t *fptr)
1041{
1042 /* This function is used for bytes and chars. Confusing. */
1043 if (READ_CHAR_PENDING(fptr))
1044 return 1; /* should raise? */
1045 return READ_DATA_PENDING(fptr);
1046}
1047
1048void
1049rb_io_read_check(rb_io_t *fptr)
1050{
1051 if (!READ_DATA_PENDING(fptr)) {
1052 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1053 }
1054 return;
1055}
1056
1057int
1058rb_gc_for_fd(int err)
1059{
1060 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1061 rb_gc();
1062 return 1;
1063 }
1064 return 0;
1065}
1066
1067/* try `expr` upto twice while it returns false and `errno`
1068 * is to GC. Each `errno`s are available as `first_errno` and
1069 * `retried_errno` respectively */
1070#define TRY_WITH_GC(expr) \
1071 for (int first_errno, retried_errno = 0, retried = 0; \
1072 (!retried && \
1073 !(expr) && \
1074 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1075 (retried_errno = errno, 1)); \
1076 (void)retried_errno, retried = 1)
1077
1078static int
1079ruby_dup(int orig)
1080{
1081 int fd = -1;
1082
1083 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1084 rb_syserr_fail(first_errno, 0);
1085 }
1086 rb_update_max_fd(fd);
1087 return fd;
1088}
1089
1090static VALUE
1091io_alloc(VALUE klass)
1092{
1093 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1094
1095 io->fptr = 0;
1096
1097 return (VALUE)io;
1098}
1099
1100#ifndef S_ISREG
1101# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1102#endif
1103
1104 struct io_internal_read_struct {
1105 VALUE th;
1106 rb_io_t *fptr;
1107 int nonblock;
1108 int fd;
1109
1110 void *buf;
1111 size_t capa;
1112 struct timeval *timeout;
1113};
1114
1115 struct io_internal_write_struct {
1116 VALUE th;
1117 rb_io_t *fptr;
1118 int nonblock;
1119 int fd;
1120
1121 const void *buf;
1122 size_t capa;
1123 struct timeval *timeout;
1124};
1125
1126#ifdef HAVE_WRITEV
1127struct io_internal_writev_struct {
1128 VALUE th;
1129 rb_io_t *fptr;
1130 int nonblock;
1131 int fd;
1132
1133 int iovcnt;
1134 const struct iovec *iov;
1135 struct timeval *timeout;
1136};
1137#endif
1138
1139static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1140
1146static inline int
1147io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1148{
1149 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1150
1151 if (ready > 0) {
1152 return ready;
1153 }
1154 else if (ready == 0) {
1155 errno = ETIMEDOUT;
1156 return -1;
1157 }
1158
1159 errno = error;
1160 return -1;
1161}
1162
1163static VALUE
1164internal_read_func(void *ptr)
1165{
1166 struct io_internal_read_struct *iis = ptr;
1167 ssize_t result;
1168
1169 if (iis->timeout && !iis->nonblock) {
1170 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1171 return -1;
1172 }
1173 }
1174
1175 retry:
1176 result = read(iis->fd, iis->buf, iis->capa);
1177
1178 if (result < 0 && !iis->nonblock) {
1179 if (io_again_p(errno)) {
1180 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1181 return -1;
1182 }
1183 else {
1184 goto retry;
1185 }
1186 }
1187 }
1188
1189 return result;
1190}
1191
1192#if defined __APPLE__
1193# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1194#else
1195# define do_write_retry(code) result = code
1196#endif
1197
1198static VALUE
1199internal_write_func(void *ptr)
1200{
1201 struct io_internal_write_struct *iis = ptr;
1202 ssize_t result;
1203
1204 if (iis->timeout && !iis->nonblock) {
1205 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1206 return -1;
1207 }
1208 }
1209
1210 retry:
1211 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1212
1213 if (result < 0 && !iis->nonblock) {
1214 int e = errno;
1215 if (io_again_p(e)) {
1216 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1217 return -1;
1218 }
1219 else {
1220 goto retry;
1221 }
1222 }
1223 }
1224
1225 return result;
1226}
1227
1228#ifdef HAVE_WRITEV
1229static VALUE
1230internal_writev_func(void *ptr)
1231{
1232 struct io_internal_writev_struct *iis = ptr;
1233 ssize_t result;
1234
1235 if (iis->timeout && !iis->nonblock) {
1236 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1237 return -1;
1238 }
1239 }
1240
1241 retry:
1242 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1243
1244 if (result < 0 && !iis->nonblock) {
1245 if (io_again_p(errno)) {
1246 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1247 return -1;
1248 }
1249 else {
1250 goto retry;
1251 }
1252 }
1253 }
1254
1255 return result;
1256}
1257#endif
1258
1259static ssize_t
1260rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1261{
1262 VALUE scheduler = rb_fiber_scheduler_current();
1263 if (scheduler != Qnil) {
1264 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1265
1266 if (!UNDEF_P(result)) {
1267 return rb_fiber_scheduler_io_result_apply(result);
1268 }
1269 }
1270
1271 struct io_internal_read_struct iis = {
1272 .th = rb_thread_current(),
1273 .fptr = fptr,
1274 .nonblock = 0,
1275 .fd = fptr->fd,
1276
1277 .buf = buf,
1278 .capa = count,
1279 .timeout = NULL,
1280 };
1281
1282 struct timeval timeout_storage;
1283
1284 if (fptr->timeout != Qnil) {
1285 timeout_storage = rb_time_interval(fptr->timeout);
1286 iis.timeout = &timeout_storage;
1287 }
1288
1289 return (ssize_t)rb_thread_io_blocking_call(internal_read_func, &iis, fptr->fd, RB_WAITFD_IN);
1290}
1291
1292static ssize_t
1293rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1294{
1295 VALUE scheduler = rb_fiber_scheduler_current();
1296 if (scheduler != Qnil) {
1297 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1298
1299 if (!UNDEF_P(result)) {
1300 return rb_fiber_scheduler_io_result_apply(result);
1301 }
1302 }
1303
1304 struct io_internal_write_struct iis = {
1305 .th = rb_thread_current(),
1306 .fptr = fptr,
1307 .nonblock = 0,
1308 .fd = fptr->fd,
1309
1310 .buf = buf,
1311 .capa = count,
1312 .timeout = NULL
1313 };
1314
1315 struct timeval timeout_storage;
1316
1317 if (fptr->timeout != Qnil) {
1318 timeout_storage = rb_time_interval(fptr->timeout);
1319 iis.timeout = &timeout_storage;
1320 }
1321
1322 return (ssize_t)rb_thread_io_blocking_call(internal_write_func, &iis, fptr->fd, RB_WAITFD_OUT);
1323}
1324
1325#ifdef HAVE_WRITEV
1326static ssize_t
1327rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1328{
1329 if (!iovcnt) return 0;
1330
1331 VALUE scheduler = rb_fiber_scheduler_current();
1332 if (scheduler != Qnil) {
1333 // This path assumes at least one `iov`:
1334 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1335
1336 if (!UNDEF_P(result)) {
1337 return rb_fiber_scheduler_io_result_apply(result);
1338 }
1339 }
1340
1341 struct io_internal_writev_struct iis = {
1342 .th = rb_thread_current(),
1343 .fptr = fptr,
1344 .nonblock = 0,
1345 .fd = fptr->fd,
1346
1347 .iov = iov,
1348 .iovcnt = iovcnt,
1349 .timeout = NULL
1350 };
1351
1352 struct timeval timeout_storage;
1353
1354 if (fptr->timeout != Qnil) {
1355 timeout_storage = rb_time_interval(fptr->timeout);
1356 iis.timeout = &timeout_storage;
1357 }
1358
1359 return (ssize_t)rb_thread_io_blocking_call(internal_writev_func, &iis, fptr->fd, RB_WAITFD_OUT);
1360}
1361#endif
1362
1363static VALUE
1364io_flush_buffer_sync(void *arg)
1365{
1366 rb_io_t *fptr = arg;
1367 long l = fptr->wbuf.len;
1368 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1369
1370 if (fptr->wbuf.len <= r) {
1371 fptr->wbuf.off = 0;
1372 fptr->wbuf.len = 0;
1373 return 0;
1374 }
1375
1376 if (0 <= r) {
1377 fptr->wbuf.off += (int)r;
1378 fptr->wbuf.len -= (int)r;
1379 errno = EAGAIN;
1380 }
1381
1382 return (VALUE)-1;
1383}
1384
1385static VALUE
1386io_flush_buffer_async(VALUE arg)
1387{
1388 rb_io_t *fptr = (rb_io_t *)arg;
1389 return rb_thread_io_blocking_call(io_flush_buffer_sync, fptr, fptr->fd, RB_WAITFD_OUT);
1390}
1391
1392static inline int
1393io_flush_buffer(rb_io_t *fptr)
1394{
1395 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1396 return (int)io_flush_buffer_async((VALUE)fptr);
1397 }
1398 else {
1399 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1400 }
1401}
1402
1403static int
1404io_fflush(rb_io_t *fptr)
1405{
1406 rb_io_check_closed(fptr);
1407
1408 if (fptr->wbuf.len == 0)
1409 return 0;
1410
1411 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1412 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1413 return -1;
1414
1415 rb_io_check_closed(fptr);
1416 }
1417
1418 return 0;
1419}
1420
1421 VALUE
1422rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1423{
1424 VALUE scheduler = rb_fiber_scheduler_current();
1425
1426 if (scheduler != Qnil) {
1427 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1428 }
1429
1430 rb_io_t * fptr = NULL;
1431 RB_IO_POINTER(io, fptr);
1432
1433 struct timeval tv_storage;
1434 struct timeval *tv = NULL;
1435
1436 if (NIL_OR_UNDEF_P(timeout)) {
1437 timeout = fptr->timeout;
1438 }
1439
1440 if (timeout != Qnil) {
1441 tv_storage = rb_time_interval(timeout);
1442 tv = &tv_storage;
1443 }
1444
1445 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1446
1447 if (ready < 0) {
1448 rb_sys_fail(0);
1449 }
1450
1451 // Not sure if this is necessary:
1452 rb_io_check_closed(fptr);
1453
1454 if (ready) {
1455 return RB_INT2NUM(ready);
1456 }
1457 else {
1458 return Qfalse;
1459 }
1460}
1461
1462static VALUE
1463io_from_fd(int fd)
1464{
1465 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1466}
1467
1468static int
1469io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1470{
1471 VALUE scheduler = rb_fiber_scheduler_current();
1472
1473 if (scheduler != Qnil) {
1474 return RTEST(
1475 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1476 );
1477 }
1478
1479 return rb_thread_wait_for_single_fd(fd, events, timeout);
1480}
1481
1482int
1483rb_io_wait_readable(int f)
1484{
1485 io_fd_check_closed(f);
1486
1487 VALUE scheduler = rb_fiber_scheduler_current();
1488
1489 switch (errno) {
1490 case EINTR:
1491#if defined(ERESTART)
1492 case ERESTART:
1493#endif
1494 rb_thread_check_ints();
1495 return TRUE;
1496
1497 case EAGAIN:
1498#if EWOULDBLOCK != EAGAIN
1499 case EWOULDBLOCK:
1500#endif
1501 if (scheduler != Qnil) {
1502 return RTEST(
1503 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1504 );
1505 }
1506 else {
1507 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1508 }
1509 return TRUE;
1510
1511 default:
1512 return FALSE;
1513 }
1514}
1515
1516int
1517rb_io_wait_writable(int f)
1518{
1519 io_fd_check_closed(f);
1520
1521 VALUE scheduler = rb_fiber_scheduler_current();
1522
1523 switch (errno) {
1524 case EINTR:
1525#if defined(ERESTART)
1526 case ERESTART:
1527#endif
1528 /*
1529 * In old Linux, several special files under /proc and /sys don't handle
1530 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1531 * Otherwise, we face nasty hang up. Sigh.
1532 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1533 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1534 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1535 * Then rb_thread_check_ints() is enough.
1536 */
1537 rb_thread_check_ints();
1538 return TRUE;
1539
1540 case EAGAIN:
1541#if EWOULDBLOCK != EAGAIN
1542 case EWOULDBLOCK:
1543#endif
1544 if (scheduler != Qnil) {
1545 return RTEST(
1546 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1547 );
1548 }
1549 else {
1550 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1551 }
1552 return TRUE;
1553
1554 default:
1555 return FALSE;
1556 }
1557}
1558
1559int
1560rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1561{
1562 return io_wait_for_single_fd(fd, events, timeout);
1563}
1564
1565int
1566rb_thread_wait_fd(int fd)
1567{
1568 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1569}
1570
1571int
1572rb_thread_fd_writable(int fd)
1573{
1574 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1575}
1576
1577 VALUE
1578rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1579{
1580 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1581 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1582 // instead relies on `read(-1) -> -1` which causes this code path. We then
1583 // check here whether the IO was in fact closed. Probably it's better to
1584 // check that `fptr->fd != -1` before using it in syscall.
1585 rb_io_check_closed(RFILE(io)->fptr);
1586
1587 switch (error) {
1588 // In old Linux, several special files under /proc and /sys don't handle
1589 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1590 // Otherwise, we face nasty hang up. Sigh.
1591 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1592 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1593 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1594 // Then rb_thread_check_ints() is enough.
1595 case EINTR:
1596#if defined(ERESTART)
1597 case ERESTART:
1598#endif
1599 // We might have pending interrupts since the previous syscall was interrupted:
1600 rb_thread_check_ints();
1601
1602 // The operation was interrupted, so retry it immediately:
1603 return events;
1604
1605 case EAGAIN:
1606#if EWOULDBLOCK != EAGAIN
1607 case EWOULDBLOCK:
1608#endif
1609 // The operation would block, so wait for the specified events:
1610 return rb_io_wait(io, events, timeout);
1611
1612 default:
1613 // Non-specific error, no event is ready:
1614 return Qfalse;
1615 }
1616}
1617
1618int
1619rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
1620{
1621 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1622
1623 if (RTEST(result)) {
1624 return RB_NUM2INT(result);
1625 }
1626 else {
1627 return 0;
1628 }
1629}
1630
1631int
1632rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
1633{
1634 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1635
1636 if (RTEST(result)) {
1637 return RB_NUM2INT(result);
1638 }
1639 else {
1640 return 0;
1641 }
1642}
1643
1644static void
1645make_writeconv(rb_io_t *fptr)
1646{
1647 if (!fptr->writeconv_initialized) {
1648 const char *senc, *denc;
1649 rb_encoding *enc;
1650 int ecflags;
1651 VALUE ecopts;
1652
1653 fptr->writeconv_initialized = 1;
1654
1655 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1656 ecopts = fptr->encs.ecopts;
1657
1658 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1659 /* no encoding conversion */
1660 fptr->writeconv_pre_ecflags = 0;
1661 fptr->writeconv_pre_ecopts = Qnil;
1662 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1663 if (!fptr->writeconv)
1664 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1665 fptr->writeconv_asciicompat = Qnil;
1666 }
1667 else {
1668 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1669 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1670 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1671 /* single conversion */
1672 fptr->writeconv_pre_ecflags = ecflags;
1673 fptr->writeconv_pre_ecopts = ecopts;
1674 fptr->writeconv = NULL;
1675 fptr->writeconv_asciicompat = Qnil;
1676 }
1677 else {
1678 /* double conversion */
1679 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1680 fptr->writeconv_pre_ecopts = ecopts;
1681 if (senc) {
1682 denc = rb_enc_name(enc);
1683 fptr->writeconv_asciicompat = rb_str_new2(senc);
1684 }
1685 else {
1686 senc = denc = "";
1687 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1688 }
1689 ecflags = fptr->encs.ecflags & (ECONV_ERROR_HANDLER_MASK|ECONV_STATEFUL_DECORATOR_MASK);
1690 ecopts = fptr->encs.ecopts;
1691 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1692 if (!fptr->writeconv)
1693 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1694 }
1695 }
1696 }
1697}
1698
1699/* writing functions */
1700 struct binwrite_arg {
1701 rb_io_t *fptr;
1702 VALUE str;
1703 const char *ptr;
1704 long length;
1705};
1706
1707 struct write_arg {
1708 VALUE io;
1709 VALUE str;
1710 int nosync;
1711};
1712
1713#ifdef HAVE_WRITEV
1714static ssize_t
1715io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1716{
1717 if (fptr->wbuf.len) {
1718 struct iovec iov[2];
1719
1720 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1721 iov[0].iov_len = fptr->wbuf.len;
1722 iov[1].iov_base = (void*)ptr;
1723 iov[1].iov_len = length;
1724
1725 ssize_t result = rb_writev_internal(fptr, iov, 2);
1726
1727 if (result < 0)
1728 return result;
1729
1730 if (result >= fptr->wbuf.len) {
1731 // We wrote more than the internal buffer:
1732 result -= fptr->wbuf.len;
1733 fptr->wbuf.off = 0;
1734 fptr->wbuf.len = 0;
1735 }
1736 else {
1737 // We only wrote less data than the internal buffer:
1738 fptr->wbuf.off += (int)result;
1739 fptr->wbuf.len -= (int)result;
1740
1741 result = 0;
1742 }
1743
1744 return result;
1745 }
1746 else {
1747 return rb_io_write_memory(fptr, ptr, length);
1748 }
1749}
1750#else
1751static ssize_t
1752io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1753{
1754 long remaining = length;
1755
1756 if (fptr->wbuf.len) {
1757 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1758 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1759 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1760 fptr->wbuf.off = 0;
1761 }
1762
1763 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1764 fptr->wbuf.len += (int)length;
1765
1766 // We copied the entire incoming data to the internal buffer:
1767 remaining = 0;
1768 }
1769
1770 // Flush the internal buffer:
1771 if (io_fflush(fptr) < 0) {
1772 return -1;
1773 }
1774
1775 // If all the data was buffered, we are done:
1776 if (remaining == 0) {
1777 return length;
1778 }
1779 }
1780
1781 // Otherwise, we should write the data directly:
1782 return rb_io_write_memory(fptr, ptr, length);
1783}
1784#endif
1785
1786static VALUE
1787io_binwrite_string(VALUE arg)
1788{
1789 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1790
1791 const char *ptr = p->ptr;
1792 size_t remaining = p->length;
1793
1794 while (remaining) {
1795 // Write as much as possible:
1796 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1797
1798 if (result == 0) {
1799 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1800 // should try again immediately.
1801 }
1802 else if (result > 0) {
1803 if ((size_t)result == remaining) break;
1804 ptr += result;
1805 remaining -= result;
1806 }
1807 // Wait for it to become writable:
1808 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1809 rb_io_check_closed(p->fptr);
1810 }
1811 else {
1812 // The error was unrelated to waiting for it to become writable, so we fail:
1813 return -1;
1814 }
1815 }
1816
1817 return p->length;
1818}
1819
1820inline static void
1821io_allocate_write_buffer(rb_io_t *fptr, int sync)
1822{
1823 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1824 fptr->wbuf.off = 0;
1825 fptr->wbuf.len = 0;
1826 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1827 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1828 }
1829
1830 if (NIL_P(fptr->write_lock)) {
1831 fptr->write_lock = rb_mutex_new();
1832 rb_mutex_allow_trap(fptr->write_lock, 1);
1833 }
1834}
1835
1836static inline int
1837io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1838{
1839 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1840 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1841 return 1;
1842
1843 // If the amount of data we want to write exceeds the internal buffer:
1844 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1845 return 1;
1846
1847 // Otherwise, we can append to the internal buffer:
1848 return 0;
1849}
1850
1851static long
1852io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
1853{
1854 if (len <= 0) return len;
1855
1856 // Don't write anything if current thread has a pending interrupt:
1857 rb_thread_check_ints();
1858
1859 io_allocate_write_buffer(fptr, !nosync);
1860
1861 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1862 struct binwrite_arg arg;
1863
1864 arg.fptr = fptr;
1865 arg.str = str;
1866 arg.ptr = ptr;
1867 arg.length = len;
1868
1869 if (!NIL_P(fptr->write_lock)) {
1870 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1871 }
1872 else {
1873 return io_binwrite_string((VALUE)&arg);
1874 }
1875 }
1876 else {
1877 if (fptr->wbuf.off) {
1878 if (fptr->wbuf.len)
1879 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1880 fptr->wbuf.off = 0;
1881 }
1882
1883 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1884 fptr->wbuf.len += (int)len;
1885
1886 return len;
1887 }
1888}
1889
1890# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1891 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1892
1893#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1894 MODE_BTMODE(d, e, f) : \
1895 MODE_BTMODE(a, b, c))
1896
1897static VALUE
1898do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1899{
1900 if (NEED_WRITECONV(fptr)) {
1901 VALUE common_encoding = Qnil;
1902 SET_BINARY_MODE(fptr);
1903
1904 make_writeconv(fptr);
1905
1906 if (fptr->writeconv) {
1907#define fmode (fptr->mode)
1908 if (!NIL_P(fptr->writeconv_asciicompat))
1909 common_encoding = fptr->writeconv_asciicompat;
1910 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1911 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1912 rb_enc_name(rb_enc_get(str)));
1913 }
1914#undef fmode
1915 }
1916 else {
1917 if (fptr->encs.enc2)
1918 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1919 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1920 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1921 }
1922
1923 if (!NIL_P(common_encoding)) {
1924 str = rb_str_encode(str, common_encoding,
1925 fptr->writeconv_pre_ecflags, fptr->writeconv_pre_ecopts);
1926 *converted = 1;
1927 }
1928
1929 if (fptr->writeconv) {
1930 str = rb_econv_str_convert(fptr->writeconv, str, ECONV_PARTIAL_INPUT);
1931 *converted = 1;
1932 }
1933 }
1934#if RUBY_CRLF_ENVIRONMENT
1935#define fmode (fptr->mode)
1936 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1937 if ((fptr->mode & FMODE_READABLE) &&
1938 !(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
1939 setmode(fptr->fd, O_BINARY);
1940 }
1941 else {
1942 setmode(fptr->fd, O_TEXT);
1943 }
1944 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1945 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1946 rb_enc_name(rb_enc_get(str)));
1947 }
1948 }
1949#undef fmode
1950#endif
1951 return str;
1952}
1953
1954static long
1955io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1956{
1957 int converted = 0;
1958 VALUE tmp;
1959 long n, len;
1960 const char *ptr;
1961
1962#ifdef _WIN32
1963 if (fptr->mode & FMODE_TTY) {
1964 long len = rb_w32_write_console(str, fptr->fd);
1965 if (len > 0) return len;
1966 }
1967#endif
1968
1969 str = do_writeconv(str, fptr, &converted);
1970 if (converted)
1971 OBJ_FREEZE(str);
1972
1973 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
1974 RSTRING_GETMEM(tmp, ptr, len);
1975 n = io_binwrite(tmp, ptr, len, fptr, nosync);
1976 rb_str_tmp_frozen_release(str, tmp);
1977
1978 return n;
1979}
1980
1981ssize_t
1982rb_io_bufwrite(VALUE io, const void *buf, size_t size)
1983{
1984 rb_io_t *fptr;
1985
1986 GetOpenFile(io, fptr);
1987 rb_io_check_writable(fptr);
1988 return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
1989}
1990
1991static VALUE
1992io_write(VALUE io, VALUE str, int nosync)
1993{
1994 rb_io_t *fptr;
1995 long n;
1996 VALUE tmp;
1997
1998 io = GetWriteIO(io);
1999 str = rb_obj_as_string(str);
2000 tmp = rb_io_check_io(io);
2001
2002 if (NIL_P(tmp)) {
2003 /* port is not IO, call write method for it. */
2004 return rb_funcall(io, id_write, 1, str);
2005 }
2006
2007 io = tmp;
2008 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2009
2010 GetOpenFile(io, fptr);
2011 rb_io_check_writable(fptr);
2012
2013 n = io_fwrite(str, fptr, nosync);
2014 if (n < 0L) rb_sys_fail_on_write(fptr);
2015
2016 return LONG2FIX(n);
2017}
2018
2019#ifdef HAVE_WRITEV
2020struct binwritev_arg {
2021 rb_io_t *fptr;
2022 struct iovec *iov;
2023 int iovcnt;
2024 size_t total;
2025};
2026
2027static VALUE
2028io_binwritev_internal(VALUE arg)
2029{
2030 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2031
2032 size_t remaining = p->total;
2033 size_t offset = 0;
2034
2035 rb_io_t *fptr = p->fptr;
2036 struct iovec *iov = p->iov;
2037 int iovcnt = p->iovcnt;
2038
2039 while (remaining) {
2040 long result = rb_writev_internal(fptr, iov, iovcnt);
2041
2042 if (result >= 0) {
2043 offset += result;
2044 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2045 if (offset < (size_t)fptr->wbuf.len) {
2046 fptr->wbuf.off += result;
2047 fptr->wbuf.len -= result;
2048 }
2049 else {
2050 offset -= (size_t)fptr->wbuf.len;
2051 fptr->wbuf.off = 0;
2052 fptr->wbuf.len = 0;
2053 }
2054 }
2055
2056 if (offset == p->total) {
2057 return p->total;
2058 }
2059
2060 while (result >= (ssize_t)iov->iov_len) {
2061 /* iovcnt > 0 */
2062 result -= iov->iov_len;
2063 iov->iov_len = 0;
2064 iov++;
2065
2066 if (!--iovcnt) {
2067 // I don't believe this code path can ever occur.
2068 return offset;
2069 }
2070 }
2071
2072 iov->iov_base = (char *)iov->iov_base + result;
2073 iov->iov_len -= result;
2074 }
2075 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2076 rb_io_check_closed(fptr);
2077 }
2078 else {
2079 return -1;
2080 }
2081 }
2082
2083 return offset;
2084}
2085
2086static long
2087io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2088{
2089 // Don't write anything if current thread has a pending interrupt:
2090 rb_thread_check_ints();
2091
2092 if (iovcnt == 0) return 0;
2093
2094 size_t total = 0;
2095 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2096
2097 io_allocate_write_buffer(fptr, 1);
2098
2099 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2100 // The end of the buffered data:
2101 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2102
2103 if (offset + total <= (size_t)fptr->wbuf.capa) {
2104 for (int i = 1; i < iovcnt; i++) {
2105 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2106 offset += iov[i].iov_len;
2107 }
2108
2109 fptr->wbuf.len += total;
2110
2111 return total;
2112 }
2113 else {
2114 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2115 iov[0].iov_len = fptr->wbuf.len;
2116 }
2117 }
2118 else {
2119 // The first iov is reserved for the internal buffer, and it's empty.
2120 iov++;
2121
2122 if (!--iovcnt) {
2123 // If there are no other io vectors we are done.
2124 return 0;
2125 }
2126 }
2127
2128 struct binwritev_arg arg;
2129 arg.fptr = fptr;
2130 arg.iov = iov;
2131 arg.iovcnt = iovcnt;
2132 arg.total = total;
2133
2134 if (!NIL_P(fptr->write_lock)) {
2135 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2136 }
2137 else {
2138 return io_binwritev_internal((VALUE)&arg);
2139 }
2140}
2141
2142static long
2143io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2144{
2145 int i, converted, iovcnt = argc + 1;
2146 long n;
2147 VALUE v1, v2, str, tmp, *tmp_array;
2148 struct iovec *iov;
2149
2150 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2151 tmp_array = ALLOCV_N(VALUE, v2, argc);
2152
2153 for (i = 0; i < argc; i++) {
2154 str = rb_obj_as_string(argv[i]);
2155 converted = 0;
2156 str = do_writeconv(str, fptr, &converted);
2157
2158 if (converted)
2159 OBJ_FREEZE(str);
2160
2161 tmp = rb_str_tmp_frozen_acquire(str);
2162 tmp_array[i] = tmp;
2163
2164 /* iov[0] is reserved for buffer of fptr */
2165 iov[i+1].iov_base = RSTRING_PTR(tmp);
2166 iov[i+1].iov_len = RSTRING_LEN(tmp);
2167 }
2168
2169 n = io_binwritev(iov, iovcnt, fptr);
2170 if (v1) ALLOCV_END(v1);
2171
2172 for (i = 0; i < argc; i++) {
2173 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2174 }
2175
2176 if (v2) ALLOCV_END(v2);
2177
2178 return n;
2179}
2180
2181static int
2182iovcnt_ok(int iovcnt)
2183{
2184#ifdef IOV_MAX
2185 return iovcnt < IOV_MAX;
2186#else /* GNU/Hurd has writev, but no IOV_MAX */
2187 return 1;
2188#endif
2189}
2190#endif /* HAVE_WRITEV */
2191
2192static VALUE
2193io_writev(int argc, const VALUE *argv, VALUE io)
2194{
2195 rb_io_t *fptr;
2196 long n;
2197 VALUE tmp, total = INT2FIX(0);
2198 int i, cnt = 1;
2199
2200 io = GetWriteIO(io);
2201 tmp = rb_io_check_io(io);
2202
2203 if (NIL_P(tmp)) {
2204 /* port is not IO, call write method for it. */
2205 return rb_funcallv(io, id_write, argc, argv);
2206 }
2207
2208 io = tmp;
2209
2210 GetOpenFile(io, fptr);
2211 rb_io_check_writable(fptr);
2212
2213 for (i = 0; i < argc; i += cnt) {
2214#ifdef HAVE_WRITEV
2215 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2216 n = io_fwritev(cnt, &argv[i], fptr);
2217 }
2218 else
2219#endif
2220 {
2221 cnt = 1;
2222 /* sync at last item */
2223 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2224 }
2225
2226 if (n < 0L)
2227 rb_sys_fail_on_write(fptr);
2228
2229 total = rb_fix_plus(LONG2FIX(n), total);
2230 }
2231
2232 return total;
2233}
2234
2235/*
2236 * call-seq:
2237 * write(*objects) -> integer
2238 *
2239 * Writes each of the given +objects+ to +self+,
2240 * which must be opened for writing
2241 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2242 * returns the total number bytes written;
2243 * each of +objects+ that is not a string is converted via method +to_s+:
2244 *
2245 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2246 * $stdout.write('foo', :bar, 2, "\n") # => 8
2247 *
2248 * Output:
2249 *
2250 * Hello, World!
2251 * foobar2
2252 *
2253 * Related: IO#read.
2254 */
2255
2256static VALUE
2257io_write_m(int argc, VALUE *argv, VALUE io)
2258{
2259 if (argc != 1) {
2260 return io_writev(argc, argv, io);
2261 }
2262 else {
2263 VALUE str = argv[0];
2264 return io_write(io, str, 0);
2265 }
2266}
2267
2268 VALUE
2269rb_io_write(VALUE io, VALUE str)
2270{
2271 return rb_funcallv(io, id_write, 1, &str);
2272}
2273
2274static VALUE
2275rb_io_writev(VALUE io, int argc, const VALUE *argv)
2276{
2277 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2278 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2279 VALUE klass = CLASS_OF(io);
2280 char sep = FL_TEST(klass, FL_SINGLETON) ? (klass = io, '.') : '#';
2281 rb_category_warning(
2282 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2283 " which accepts just one argument",
2284 klass, sep
2285 );
2286 }
2287
2288 do rb_io_write(io, *argv++); while (--argc);
2289
2290 return Qnil;
2291 }
2292
2293 return rb_funcallv(io, id_write, argc, argv);
2294}
2295
2296/*
2297 * call-seq:
2298 * self << object -> self
2299 *
2300 * Writes the given +object+ to +self+,
2301 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2302 * returns +self+;
2303 * if +object+ is not a string, it is converted via method +to_s+:
2304 *
2305 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2306 * $stdout << 'foo' << :bar << 2 << "\n"
2307 *
2308 * Output:
2309 *
2310 * Hello, World!
2311 * foobar2
2312 *
2313 */
2314
2315
2316 VALUE
2317rb_io_addstr(VALUE io, VALUE str)
2318{
2319 rb_io_write(io, str);
2320 return io;
2321}
2322
2323#ifdef HAVE_FSYNC
2324static VALUE
2325nogvl_fsync(void *ptr)
2326{
2327 rb_io_t *fptr = ptr;
2328
2329#ifdef _WIN32
2330 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2331 return 0;
2332#endif
2333 return (VALUE)fsync(fptr->fd);
2334}
2335#endif
2336
2337 VALUE
2338rb_io_flush_raw(VALUE io, int sync)
2339{
2340 rb_io_t *fptr;
2341
2342 if (!RB_TYPE_P(io, T_FILE)) {
2343 return rb_funcall(io, id_flush, 0);
2344 }
2345
2346 io = GetWriteIO(io);
2347 GetOpenFile(io, fptr);
2348
2349 if (fptr->mode & FMODE_WRITABLE) {
2350 if (io_fflush(fptr) < 0)
2351 rb_sys_fail_on_write(fptr);
2352 }
2353 if (fptr->mode & FMODE_READABLE) {
2354 io_unread(fptr);
2355 }
2356
2357 return io;
2358}
2359
2360/*
2361 * call-seq:
2362 * flush -> self
2363 *
2364 * Flushes data buffered in +self+ to the operating system
2365 * (but does not necessarily flush data buffered in the operating system):
2366 *
2367 * $stdout.print 'no newline' # Not necessarily flushed.
2368 * $stdout.flush # Flushed.
2369 *
2370 */
2371
2372 VALUE
2373rb_io_flush(VALUE io)
2374{
2375 return rb_io_flush_raw(io, 1);
2376}
2377
2378/*
2379 * call-seq:
2380 * tell -> integer
2381 *
2382 * Returns the current position (in bytes) in +self+
2383 * (see {Position}[rdoc-ref:IO@Position]):
2384 *
2385 * f = File.open('t.txt')
2386 * f.tell # => 0
2387 * f.gets # => "First line\n"
2388 * f.tell # => 12
2389 * f.close
2390 *
2391 * Related: IO#pos=, IO#seek.
2392 */
2393
2394static VALUE
2395rb_io_tell(VALUE io)
2396{
2397 rb_io_t *fptr;
2398 rb_off_t pos;
2399
2400 GetOpenFile(io, fptr);
2401 pos = io_tell(fptr);
2402 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2403 pos -= fptr->rbuf.len;
2404 return OFFT2NUM(pos);
2405}
2406
2407static VALUE
2408rb_io_seek(VALUE io, VALUE offset, int whence)
2409{
2410 rb_io_t *fptr;
2411 rb_off_t pos;
2412
2413 pos = NUM2OFFT(offset);
2414 GetOpenFile(io, fptr);
2415 pos = io_seek(fptr, pos, whence);
2416 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2417
2418 return INT2FIX(0);
2419}
2420
2421static int
2422interpret_seek_whence(VALUE vwhence)
2423{
2424 if (vwhence == sym_SET)
2425 return SEEK_SET;
2426 if (vwhence == sym_CUR)
2427 return SEEK_CUR;
2428 if (vwhence == sym_END)
2429 return SEEK_END;
2430#ifdef SEEK_DATA
2431 if (vwhence == sym_DATA)
2432 return SEEK_DATA;
2433#endif
2434#ifdef SEEK_HOLE
2435 if (vwhence == sym_HOLE)
2436 return SEEK_HOLE;
2437#endif
2438 return NUM2INT(vwhence);
2439}
2440
2441/*
2442 * call-seq:
2443 * seek(offset, whence = IO::SEEK_SET) -> 0
2444 *
2445 * Seeks to the position given by integer +offset+
2446 * (see {Position}[rdoc-ref:IO@Position])
2447 * and constant +whence+, which is one of:
2448 *
2449 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2450 * Repositions the stream to its current position plus the given +offset+:
2451 *
2452 * f = File.open('t.txt')
2453 * f.tell # => 0
2454 * f.seek(20, :CUR) # => 0
2455 * f.tell # => 20
2456 * f.seek(-10, :CUR) # => 0
2457 * f.tell # => 10
2458 * f.close
2459 *
2460 * - +:END+ or <tt>IO::SEEK_END</tt>:
2461 * Repositions the stream to its end plus the given +offset+:
2462 *
2463 * f = File.open('t.txt')
2464 * f.tell # => 0
2465 * f.seek(0, :END) # => 0 # Repositions to stream end.
2466 * f.tell # => 52
2467 * f.seek(-20, :END) # => 0
2468 * f.tell # => 32
2469 * f.seek(-40, :END) # => 0
2470 * f.tell # => 12
2471 * f.close
2472 *
2473 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2474 * Repositions the stream to the given +offset+:
2475 *
2476 * f = File.open('t.txt')
2477 * f.tell # => 0
2478 * f.seek(20, :SET) # => 0
2479 * f.tell # => 20
2480 * f.seek(40, :SET) # => 0
2481 * f.tell # => 40
2482 * f.close
2483 *
2484 * Related: IO#pos=, IO#tell.
2485 *
2486 */
2487
2488static VALUE
2489rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2490{
2491 VALUE offset, ptrname;
2492 int whence = SEEK_SET;
2493
2494 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2495 whence = interpret_seek_whence(ptrname);
2496 }
2497
2498 return rb_io_seek(io, offset, whence);
2499}
2500
2501/*
2502 * call-seq:
2503 * pos = new_position -> new_position
2504 *
2505 * Seeks to the given +new_position+ (in bytes);
2506 * see {Position}[rdoc-ref:IO@Position]:
2507 *
2508 * f = File.open('t.txt')
2509 * f.tell # => 0
2510 * f.pos = 20 # => 20
2511 * f.tell # => 20
2512 * f.close
2513 *
2514 * Related: IO#seek, IO#tell.
2515 *
2516 */
2517
2518static VALUE
2519rb_io_set_pos(VALUE io, VALUE offset)
2520{
2521 rb_io_t *fptr;
2522 rb_off_t pos;
2523
2524 pos = NUM2OFFT(offset);
2525 GetOpenFile(io, fptr);
2526 pos = io_seek(fptr, pos, SEEK_SET);
2527 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2528
2529 return OFFT2NUM(pos);
2530}
2531
2532static void clear_readconv(rb_io_t *fptr);
2533
2534/*
2535 * call-seq:
2536 * rewind -> 0
2537 *
2538 * Repositions the stream to its beginning,
2539 * setting both the position and the line number to zero;
2540 * see {Position}[rdoc-ref:IO@Position]
2541 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2542 *
2543 * f = File.open('t.txt')
2544 * f.tell # => 0
2545 * f.lineno # => 0
2546 * f.gets # => "First line\n"
2547 * f.tell # => 12
2548 * f.lineno # => 1
2549 * f.rewind # => 0
2550 * f.tell # => 0
2551 * f.lineno # => 0
2552 * f.close
2553 *
2554 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2555 *
2556 */
2557
2558static VALUE
2559rb_io_rewind(VALUE io)
2560{
2561 rb_io_t *fptr;
2562
2563 GetOpenFile(io, fptr);
2564 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2565 if (io == ARGF.current_file) {
2566 ARGF.lineno -= fptr->lineno;
2567 }
2568 fptr->lineno = 0;
2569 if (fptr->readconv) {
2570 clear_readconv(fptr);
2571 }
2572
2573 return INT2FIX(0);
2574}
2575
2576static int
2577fptr_wait_readable(rb_io_t *fptr)
2578{
2579 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2580
2581 if (result)
2582 rb_io_check_closed(fptr);
2583
2584 return result;
2585}
2586
2587static int
2588io_fillbuf(rb_io_t *fptr)
2589{
2590 ssize_t r;
2591
2592 if (fptr->rbuf.ptr == NULL) {
2593 fptr->rbuf.off = 0;
2594 fptr->rbuf.len = 0;
2595 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2596 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2597#ifdef _WIN32
2598 fptr->rbuf.capa--;
2599#endif
2600 }
2601 if (fptr->rbuf.len == 0) {
2602 retry:
2603 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2604
2605 if (r < 0) {
2606 if (fptr_wait_readable(fptr))
2607 goto retry;
2608
2609 int e = errno;
2610 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2611 if (!NIL_P(fptr->pathv)) {
2612 rb_str_append(path, fptr->pathv);
2613 }
2614
2615 rb_syserr_fail_path(e, path);
2616 }
2617 if (r > 0) rb_io_check_closed(fptr);
2618 fptr->rbuf.off = 0;
2619 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2620 if (r == 0)
2621 return -1; /* EOF */
2622 }
2623 return 0;
2624}
2625
2626/*
2627 * call-seq:
2628 * eof -> true or false
2629 *
2630 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2631 * see {Position}[rdoc-ref:IO@Position]:
2632 *
2633 * f = File.open('t.txt')
2634 * f.eof # => false
2635 * f.seek(0, :END) # => 0
2636 * f.eof # => true
2637 * f.close
2638 *
2639 * Raises an exception unless the stream is opened for reading;
2640 * see {Mode}[rdoc-ref:File@Access+Modes].
2641 *
2642 * If +self+ is a stream such as pipe or socket, this method
2643 * blocks until the other end sends some data or closes it:
2644 *
2645 * r, w = IO.pipe
2646 * Thread.new { sleep 1; w.close }
2647 * r.eof? # => true # After 1-second wait.
2648 *
2649 * r, w = IO.pipe
2650 * Thread.new { sleep 1; w.puts "a" }
2651 * r.eof? # => false # After 1-second wait.
2652 *
2653 * r, w = IO.pipe
2654 * r.eof? # blocks forever
2655 *
2656 * Note that this method reads data to the input byte buffer. So
2657 * IO#sysread may not behave as you intend with IO#eof?, unless you
2658 * call IO#rewind first (which is not available for some streams).
2659 */
2660
2661 VALUE
2662rb_io_eof(VALUE io)
2663{
2664 rb_io_t *fptr;
2665
2666 GetOpenFile(io, fptr);
2667 rb_io_check_char_readable(fptr);
2668
2669 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2670 if (READ_DATA_PENDING(fptr)) return Qfalse;
2671 READ_CHECK(fptr);
2672#if RUBY_CRLF_ENVIRONMENT
2673 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2674 return RBOOL(eof(fptr->fd));;
2675 }
2676#endif
2677 return RBOOL(io_fillbuf(fptr) < 0);
2678}
2679
2680/*
2681 * call-seq:
2682 * sync -> true or false
2683 *
2684 * Returns the current sync mode of the stream.
2685 * When sync mode is true, all output is immediately flushed to the underlying
2686 * operating system and is not buffered by Ruby internally. See also #fsync.
2687 *
2688 * f = File.open('t.tmp', 'w')
2689 * f.sync # => false
2690 * f.sync = true
2691 * f.sync # => true
2692 * f.close
2693 *
2694 */
2695
2696static VALUE
2697rb_io_sync(VALUE io)
2698{
2699 rb_io_t *fptr;
2700
2701 io = GetWriteIO(io);
2702 GetOpenFile(io, fptr);
2703 return RBOOL(fptr->mode & FMODE_SYNC);
2704}
2705
2706#ifdef HAVE_FSYNC
2707
2708/*
2709 * call-seq:
2710 * sync = boolean -> boolean
2711 *
2712 * Sets the _sync_ _mode_ for the stream to the given value;
2713 * returns the given value.
2714 *
2715 * Values for the sync mode:
2716 *
2717 * - +true+: All output is immediately flushed to the
2718 * underlying operating system and is not buffered internally.
2719 * - +false+: Output may be buffered internally.
2720 *
2721 * Example;
2722 *
2723 * f = File.open('t.tmp', 'w')
2724 * f.sync # => false
2725 * f.sync = true
2726 * f.sync # => true
2727 * f.close
2728 *
2729 * Related: IO#fsync.
2730 *
2731 */
2732
2733static VALUE
2734rb_io_set_sync(VALUE io, VALUE sync)
2735{
2736 rb_io_t *fptr;
2737
2738 io = GetWriteIO(io);
2739 GetOpenFile(io, fptr);
2740 if (RTEST(sync)) {
2741 fptr->mode |= FMODE_SYNC;
2742 }
2743 else {
2744 fptr->mode &= ~FMODE_SYNC;
2745 }
2746 return sync;
2747}
2748
2749/*
2750 * call-seq:
2751 * fsync -> 0
2752 *
2753 * Immediately writes to disk all data buffered in the stream,
2754 * via the operating system's <tt>fsync(2)</tt>.
2755
2756 * Note this difference:
2757 *
2758 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2759 * but does not guarantee that the operating system actually writes the data to disk.
2760 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2761 * and that data is written to disk.
2762 *
2763 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2764 *
2765 */
2766
2767static VALUE
2768rb_io_fsync(VALUE io)
2769{
2770 rb_io_t *fptr;
2771
2772 io = GetWriteIO(io);
2773 GetOpenFile(io, fptr);
2774
2775 if (io_fflush(fptr) < 0)
2776 rb_sys_fail_on_write(fptr);
2777 if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
2778 rb_sys_fail_path(fptr->pathv);
2779 return INT2FIX(0);
2780}
2781#else
2782# define rb_io_fsync rb_f_notimplement
2783# define rb_io_sync rb_f_notimplement
2784static VALUE
2785rb_io_set_sync(VALUE io, VALUE sync)
2786{
2787 rb_notimplement();
2788 UNREACHABLE;
2789}
2790#endif
2791
2792#ifdef HAVE_FDATASYNC
2793static VALUE
2794nogvl_fdatasync(void *ptr)
2795{
2796 rb_io_t *fptr = ptr;
2797
2798#ifdef _WIN32
2799 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2800 return 0;
2801#endif
2802 return (VALUE)fdatasync(fptr->fd);
2803}
2804
2805/*
2806 * call-seq:
2807 * fdatasync -> 0
2808 *
2809 * Immediately writes to disk all data buffered in the stream,
2810 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2811 * otherwise via <tt>fsync(2)</tt>, if supported;
2812 * otherwise raises an exception.
2813 *
2814 */
2815
2816static VALUE
2817rb_io_fdatasync(VALUE io)
2818{
2819 rb_io_t *fptr;
2820
2821 io = GetWriteIO(io);
2822 GetOpenFile(io, fptr);
2823
2824 if (io_fflush(fptr) < 0)
2825 rb_sys_fail_on_write(fptr);
2826
2827 if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
2828 return INT2FIX(0);
2829
2830 /* fall back */
2831 return rb_io_fsync(io);
2832}
2833#else
2834#define rb_io_fdatasync rb_io_fsync
2835#endif
2836
2837/*
2838 * call-seq:
2839 * fileno -> integer
2840 *
2841 * Returns the integer file descriptor for the stream:
2842 *
2843 * $stdin.fileno # => 0
2844 * $stdout.fileno # => 1
2845 * $stderr.fileno # => 2
2846 * File.open('t.txt').fileno # => 10
2847 * f.close
2848 *
2849 */
2850
2851static VALUE
2852rb_io_fileno(VALUE io)
2853{
2854 rb_io_t *fptr = RFILE(io)->fptr;
2855 int fd;
2856
2857 rb_io_check_closed(fptr);
2858 fd = fptr->fd;
2859 return INT2FIX(fd);
2860}
2861
2862int
2863rb_io_descriptor(VALUE io)
2864{
2865 if (RB_TYPE_P(io, T_FILE)) {
2866 rb_io_t *fptr = RFILE(io)->fptr;
2867 rb_io_check_closed(fptr);
2868 return fptr->fd;
2869 }
2870 else {
2871 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2872 if (!UNDEF_P(fileno)) {
2873 return RB_NUM2INT(fileno);
2874 }
2875 }
2876
2877 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2878
2879 UNREACHABLE_RETURN(-1);
2880}
2881
2882int
2883rb_io_mode(VALUE io)
2884{
2885 rb_io_t *fptr;
2886 GetOpenFile(io, fptr);
2887 return fptr->mode;
2888}
2889
2890/*
2891 * call-seq:
2892 * pid -> integer or nil
2893 *
2894 * Returns the process ID of a child process associated with the stream,
2895 * which will have been set by IO#popen, or +nil+ if the stream was not
2896 * created by IO#popen:
2897 *
2898 * pipe = IO.popen("-")
2899 * if pipe
2900 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2901 * else
2902 * $stderr.puts "In child, pid is #{$$}"
2903 * end
2904 *
2905 * Output:
2906 *
2907 * In child, pid is 26209
2908 * In parent, child pid is 26209
2909 *
2910 */
2911
2912static VALUE
2913rb_io_pid(VALUE io)
2914{
2915 rb_io_t *fptr;
2916
2917 GetOpenFile(io, fptr);
2918 if (!fptr->pid)
2919 return Qnil;
2920 return PIDT2NUM(fptr->pid);
2921}
2922
2923/*
2924 * call-seq:
2925 * path -> string or nil
2926 *
2927 * Returns the path associated with the IO, or +nil+ if there is no path
2928 * associated with the IO. It is not guaranteed that the path exists on
2929 * the filesystem.
2930 *
2931 * $stdin.path # => "<STDIN>"
2932 *
2933 * File.open("testfile") {|f| f.path} # => "testfile"
2934 */
2935
2936 VALUE
2937rb_io_path(VALUE io)
2938{
2939 rb_io_t *fptr = RFILE(io)->fptr;
2940
2941 if (!fptr)
2942 return Qnil;
2943
2944 return rb_obj_dup(fptr->pathv);
2945}
2946
2947/*
2948 * call-seq:
2949 * inspect -> string
2950 *
2951 * Returns a string representation of +self+:
2952 *
2953 * f = File.open('t.txt')
2954 * f.inspect # => "#<File:t.txt>"
2955 * f.close
2956 *
2957 */
2958
2959static VALUE
2960rb_io_inspect(VALUE obj)
2961{
2962 rb_io_t *fptr;
2963 VALUE result;
2964 static const char closed[] = " (closed)";
2965
2966 fptr = RFILE(obj)->fptr;
2967 if (!fptr) return rb_any_to_s(obj);
2968 result = rb_str_new_cstr("#<");
2969 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2970 rb_str_cat2(result, ":");
2971 if (NIL_P(fptr->pathv)) {
2972 if (fptr->fd < 0) {
2973 rb_str_cat(result, closed+1, strlen(closed)-1);
2974 }
2975 else {
2976 rb_str_catf(result, "fd %d", fptr->fd);
2977 }
2978 }
2979 else {
2980 rb_str_append(result, fptr->pathv);
2981 if (fptr->fd < 0) {
2982 rb_str_cat(result, closed, strlen(closed));
2983 }
2984 }
2985 return rb_str_cat2(result, ">");
2986}
2987
2988/*
2989 * call-seq:
2990 * to_io -> self
2991 *
2992 * Returns +self+.
2993 *
2994 */
2995
2996static VALUE
2997rb_io_to_io(VALUE io)
2998{
2999 return io;
3000}
3001
3002/* reading functions */
3003static long
3004read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3005{
3006 int n;
3007
3008 n = READ_DATA_PENDING_COUNT(fptr);
3009 if (n <= 0) return 0;
3010 if (n > len) n = (int)len;
3011 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3012 fptr->rbuf.off += n;
3013 fptr->rbuf.len -= n;
3014 return n;
3015}
3016
3017static long
3018io_bufread(char *ptr, long len, rb_io_t *fptr)
3019{
3020 long offset = 0;
3021 long n = len;
3022 long c;
3023
3024 if (READ_DATA_PENDING(fptr) == 0) {
3025 while (n > 0) {
3026 again:
3027 rb_io_check_closed(fptr);
3028 c = rb_io_read_memory(fptr, ptr+offset, n);
3029 if (c == 0) break;
3030 if (c < 0) {
3031 if (fptr_wait_readable(fptr))
3032 goto again;
3033 return -1;
3034 }
3035 offset += c;
3036 if ((n -= c) <= 0) break;
3037 }
3038 return len - n;
3039 }
3040
3041 while (n > 0) {
3042 c = read_buffered_data(ptr+offset, n, fptr);
3043 if (c > 0) {
3044 offset += c;
3045 if ((n -= c) <= 0) break;
3046 }
3047 rb_io_check_closed(fptr);
3048 if (io_fillbuf(fptr) < 0) {
3049 break;
3050 }
3051 }
3052 return len - n;
3053}
3054
3055static int io_setstrbuf(VALUE *str, long len);
3056
3057 struct bufread_arg {
3058 char *str_ptr;
3059 long len;
3060 rb_io_t *fptr;
3061};
3062
3063static VALUE
3064bufread_call(VALUE arg)
3065{
3066 struct bufread_arg *p = (struct bufread_arg *)arg;
3067 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3068 return Qundef;
3069}
3070
3071static long
3072io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3073{
3074 long len;
3075 struct bufread_arg arg;
3076
3077 io_setstrbuf(&str, offset + size);
3078 arg.str_ptr = RSTRING_PTR(str) + offset;
3079 arg.len = size;
3080 arg.fptr = fptr;
3081 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3082 len = arg.len;
3083 if (len < 0) rb_sys_fail_path(fptr->pathv);
3084 return len;
3085}
3086
3087static long
3088remain_size(rb_io_t *fptr)
3089{
3090 struct stat st;
3091 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3092 rb_off_t pos;
3093
3094 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3095#if defined(__HAIKU__)
3096 && (st.st_dev > 3)
3097#endif
3098 )
3099 {
3100 if (io_fflush(fptr) < 0)
3101 rb_sys_fail_on_write(fptr);
3102 pos = lseek(fptr->fd, 0, SEEK_CUR);
3103 if (st.st_size >= pos && pos >= 0) {
3104 siz += st.st_size - pos;
3105 if (siz > LONG_MAX) {
3106 rb_raise(rb_eIOError, "file too big for single read");
3107 }
3108 }
3109 }
3110 else {
3111 siz += BUFSIZ;
3112 }
3113 return (long)siz;
3114}
3115
3116static VALUE
3117io_enc_str(VALUE str, rb_io_t *fptr)
3118{
3119 rb_enc_associate(str, io_read_encoding(fptr));
3120 return str;
3121}
3122
3123static rb_encoding *io_read_encoding(rb_io_t *fptr);
3124
3125static void
3126make_readconv(rb_io_t *fptr, int size)
3127{
3128 if (!fptr->readconv) {
3129 int ecflags;
3130 VALUE ecopts;
3131 const char *sname, *dname;
3132 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3133 ecopts = fptr->encs.ecopts;
3134 if (fptr->encs.enc2) {
3135 sname = rb_enc_name(fptr->encs.enc2);
3136 dname = rb_enc_name(io_read_encoding(fptr));
3137 }
3138 else {
3139 sname = dname = "";
3140 }
3141 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3142 if (!fptr->readconv)
3143 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3144 fptr->cbuf.off = 0;
3145 fptr->cbuf.len = 0;
3146 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3147 fptr->cbuf.capa = size;
3148 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3149 }
3150}
3151
3152#define MORE_CHAR_SUSPENDED Qtrue
3153#define MORE_CHAR_FINISHED Qnil
3154static VALUE
3155fill_cbuf(rb_io_t *fptr, int ec_flags)
3156{
3157 const unsigned char *ss, *sp, *se;
3158 unsigned char *ds, *dp, *de;
3159 rb_econv_result_t res;
3160 int putbackable;
3161 int cbuf_len0;
3162 VALUE exc;
3163
3164 ec_flags |= ECONV_PARTIAL_INPUT;
3165
3166 if (fptr->cbuf.len == fptr->cbuf.capa)
3167 return MORE_CHAR_SUSPENDED; /* cbuf full */
3168 if (fptr->cbuf.len == 0)
3169 fptr->cbuf.off = 0;
3170 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3171 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3172 fptr->cbuf.off = 0;
3173 }
3174
3175 cbuf_len0 = fptr->cbuf.len;
3176
3177 while (1) {
3178 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3179 se = sp + fptr->rbuf.len;
3180 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3181 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3182 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3183 fptr->rbuf.off += (int)(sp - ss);
3184 fptr->rbuf.len -= (int)(sp - ss);
3185 fptr->cbuf.len += (int)(dp - ds);
3186
3187 putbackable = rb_econv_putbackable(fptr->readconv);
3188 if (putbackable) {
3189 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3190 fptr->rbuf.off -= putbackable;
3191 fptr->rbuf.len += putbackable;
3192 }
3193
3194 exc = rb_econv_make_exception(fptr->readconv);
3195 if (!NIL_P(exc))
3196 return exc;
3197
3198 if (cbuf_len0 != fptr->cbuf.len)
3199 return MORE_CHAR_SUSPENDED;
3200
3201 if (res == econv_finished) {
3202 return MORE_CHAR_FINISHED;
3203 }
3204
3205 if (res == econv_source_buffer_empty) {
3206 if (fptr->rbuf.len == 0) {
3207 READ_CHECK(fptr);
3208 if (io_fillbuf(fptr) < 0) {
3209 if (!fptr->readconv) {
3210 return MORE_CHAR_FINISHED;
3211 }
3212 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3213 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3214 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3215 fptr->cbuf.len += (int)(dp - ds);
3216 rb_econv_check_error(fptr->readconv);
3217 break;
3218 }
3219 }
3220 }
3221 }
3222 if (cbuf_len0 != fptr->cbuf.len)
3223 return MORE_CHAR_SUSPENDED;
3224
3225 return MORE_CHAR_FINISHED;
3226}
3227
3228static VALUE
3229more_char(rb_io_t *fptr)
3230{
3231 VALUE v;
3232 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3233 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3234 rb_exc_raise(v);
3235 return v;
3236}
3237
3238static VALUE
3239io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3240{
3241 VALUE str = Qnil;
3242 if (strp) {
3243 str = *strp;
3244 if (NIL_P(str)) {
3245 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3246 }
3247 else {
3248 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3249 }
3250 rb_enc_associate(str, fptr->encs.enc);
3251 }
3252 fptr->cbuf.off += len;
3253 fptr->cbuf.len -= len;
3254 /* xxx: set coderange */
3255 if (fptr->cbuf.len == 0)
3256 fptr->cbuf.off = 0;
3257 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3258 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3259 fptr->cbuf.off = 0;
3260 }
3261 return str;
3262}
3263
3264static int
3265io_setstrbuf(VALUE *str, long len)
3266{
3267#ifdef _WIN32
3268 if (len > 0)
3269 len = (len + 1) & ~1L; /* round up for wide char */
3270#endif
3271 if (NIL_P(*str)) {
3272 *str = rb_str_new(0, len);
3273 return TRUE;
3274 }
3275 else {
3276 VALUE s = StringValue(*str);
3277 rb_str_modify(s);
3278
3279 long clen = RSTRING_LEN(s);
3280 if (clen >= len) {
3281 return FALSE;
3282 }
3283 len -= clen;
3284 }
3285 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3286 rb_str_modify_expand(*str, len);
3287 }
3288 return FALSE;
3289}
3290
3291#define MAX_REALLOC_GAP 4096
3292static void
3293io_shrink_read_string(VALUE str, long n)
3294{
3295 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3296 rb_str_resize(str, n);
3297 }
3298}
3299
3300static void
3301io_set_read_length(VALUE str, long n, int shrinkable)
3302{
3303 if (RSTRING_LEN(str) != n) {
3304 rb_str_modify(str);
3305 rb_str_set_len(str, n);
3306 if (shrinkable) io_shrink_read_string(str, n);
3307 }
3308}
3309
3310static VALUE
3311read_all(rb_io_t *fptr, long siz, VALUE str)
3312{
3313 long bytes;
3314 long n;
3315 long pos;
3316 rb_encoding *enc;
3317 int cr;
3318 int shrinkable;
3319
3320 if (NEED_READCONV(fptr)) {
3321 int first = !NIL_P(str);
3322 SET_BINARY_MODE(fptr);
3323 shrinkable = io_setstrbuf(&str,0);
3324 make_readconv(fptr, 0);
3325 while (1) {
3326 VALUE v;
3327 if (fptr->cbuf.len) {
3328 if (first) rb_str_set_len(str, first = 0);
3329 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3330 }
3331 v = fill_cbuf(fptr, 0);
3332 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3333 if (fptr->cbuf.len) {
3334 if (first) rb_str_set_len(str, first = 0);
3335 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3336 }
3337 rb_exc_raise(v);
3338 }
3339 if (v == MORE_CHAR_FINISHED) {
3340 clear_readconv(fptr);
3341 if (first) rb_str_set_len(str, first = 0);
3342 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3343 return io_enc_str(str, fptr);
3344 }
3345 }
3346 }
3347
3348 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3349 bytes = 0;
3350 pos = 0;
3351
3352 enc = io_read_encoding(fptr);
3353 cr = 0;
3354
3355 if (siz == 0) siz = BUFSIZ;
3356 shrinkable = io_setstrbuf(&str, siz);
3357 for (;;) {
3358 READ_CHECK(fptr);
3359 n = io_fread(str, bytes, siz - bytes, fptr);
3360 if (n == 0 && bytes == 0) {
3361 rb_str_set_len(str, 0);
3362 break;
3363 }
3364 bytes += n;
3365 rb_str_set_len(str, bytes);
3366 if (cr != ENC_CODERANGE_BROKEN)
3367 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3368 if (bytes < siz) break;
3369 siz += BUFSIZ;
3370
3371 size_t capa = rb_str_capacity(str);
3372 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3373 if (capa < BUFSIZ) {
3374 capa = BUFSIZ;
3375 }
3376 else if (capa > IO_MAX_BUFFER_GROWTH) {
3377 capa = IO_MAX_BUFFER_GROWTH;
3378 }
3379 rb_str_modify_expand(str, capa);
3380 }
3381 }
3382 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3383 str = io_enc_str(str, fptr);
3384 ENC_CODERANGE_SET(str, cr);
3385 return str;
3386}
3387
3388void
3389rb_io_set_nonblock(rb_io_t *fptr)
3390{
3391 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3392 rb_sys_fail_path(fptr->pathv);
3393 }
3394}
3395
3396static VALUE
3397io_read_memory_call(VALUE arg)
3398{
3399 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3400
3401 VALUE scheduler = rb_fiber_scheduler_current();
3402 if (scheduler != Qnil) {
3403 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3404
3405 if (!UNDEF_P(result)) {
3406 // This is actually returned as a pseudo-VALUE and later cast to a long:
3407 return (VALUE)rb_fiber_scheduler_io_result_apply(result);
3408 }
3409 }
3410
3411 if (iis->nonblock) {
3412 return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->fd, 0);
3413 }
3414 else {
3415 return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->fd, RB_WAITFD_IN);
3416 }
3417}
3418
3419static long
3420io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3421{
3422 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3423}
3424
3425#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3426
3427static VALUE
3428io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3429{
3430 rb_io_t *fptr;
3431 VALUE length, str;
3432 long n, len;
3433 struct io_internal_read_struct iis;
3434 int shrinkable;
3435
3436 rb_scan_args(argc, argv, "11", &length, &str);
3437
3438 if ((len = NUM2LONG(length)) < 0) {
3439 rb_raise(rb_eArgError, "negative length %ld given", len);
3440 }
3441
3442 shrinkable = io_setstrbuf(&str, len);
3443
3444 GetOpenFile(io, fptr);
3445 rb_io_check_byte_readable(fptr);
3446
3447 if (len == 0) {
3448 io_set_read_length(str, 0, shrinkable);
3449 return str;
3450 }
3451
3452 if (!nonblock)
3453 READ_CHECK(fptr);
3454 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3455 if (n <= 0) {
3456 again:
3457 if (nonblock) {
3458 rb_io_set_nonblock(fptr);
3459 }
3460 io_setstrbuf(&str, len);
3461 iis.th = rb_thread_current();
3462 iis.fptr = fptr;
3463 iis.nonblock = nonblock;
3464 iis.fd = fptr->fd;
3465 iis.buf = RSTRING_PTR(str);
3466 iis.capa = len;
3467 iis.timeout = NULL;
3468 n = io_read_memory_locktmp(str, &iis);
3469 if (n < 0) {
3470 int e = errno;
3471 if (!nonblock && fptr_wait_readable(fptr))
3472 goto again;
3473 if (nonblock && (io_again_p(e))) {
3474 if (no_exception)
3475 return sym_wait_readable;
3476 else
3477 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3478 e, "read would block");
3479 }
3480 rb_syserr_fail_path(e, fptr->pathv);
3481 }
3482 }
3483 io_set_read_length(str, n, shrinkable);
3484
3485 if (n == 0)
3486 return Qnil;
3487 else
3488 return str;
3489}
3490
3491/*
3492 * call-seq:
3493 * readpartial(maxlen) -> string
3494 * readpartial(maxlen, out_string) -> out_string
3495 *
3496 * Reads up to +maxlen+ bytes from the stream;
3497 * returns a string (either a new string or the given +out_string+).
3498 * Its encoding is:
3499 *
3500 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3501 * - ASCII-8BIT, otherwise.
3502 *
3503 * - Contains +maxlen+ bytes from the stream, if available.
3504 * - Otherwise contains all available bytes, if any available.
3505 * - Otherwise is an empty string.
3506 *
3507 * With the single non-negative integer argument +maxlen+ given,
3508 * returns a new string:
3509 *
3510 * f = File.new('t.txt')
3511 * f.readpartial(20) # => "First line\nSecond l"
3512 * f.readpartial(20) # => "ine\n\nFourth line\n"
3513 * f.readpartial(20) # => "Fifth line\n"
3514 * f.readpartial(20) # Raises EOFError.
3515 * f.close
3516 *
3517 * With both argument +maxlen+ and string argument +out_string+ given,
3518 * returns modified +out_string+:
3519 *
3520 * f = File.new('t.txt')
3521 * s = 'foo'
3522 * f.readpartial(20, s) # => "First line\nSecond l"
3523 * s = 'bar'
3524 * f.readpartial(0, s) # => ""
3525 * f.close
3526 *
3527 * This method is useful for a stream such as a pipe, a socket, or a tty.
3528 * It blocks only when no data is immediately available.
3529 * This means that it blocks only when _all_ of the following are true:
3530 *
3531 * - The byte buffer in the stream is empty.
3532 * - The content of the stream is empty.
3533 * - The stream is not at EOF.
3534 *
3535 * When blocked, the method waits for either more data or EOF on the stream:
3536 *
3537 * - If more data is read, the method returns the data.
3538 * - If EOF is reached, the method raises EOFError.
3539 *
3540 * When not blocked, the method responds immediately:
3541 *
3542 * - Returns data from the buffer if there is any.
3543 * - Otherwise returns data from the stream if there is any.
3544 * - Otherwise raises EOFError if the stream has reached EOF.
3545 *
3546 * Note that this method is similar to sysread. The differences are:
3547 *
3548 * - If the byte buffer is not empty, read from the byte buffer
3549 * instead of "sysread for buffered IO (IOError)".
3550 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3551 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3552 * readpartial retries the system call.
3553 *
3554 * The latter means that readpartial is non-blocking-flag insensitive.
3555 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3556 * if the fd is blocking mode.
3557 *
3558 * Examples:
3559 *
3560 * # # Returned Buffer Content Pipe Content
3561 * r, w = IO.pipe #
3562 * w << 'abc' # "" "abc".
3563 * r.readpartial(4096) # => "abc" "" ""
3564 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3565 *
3566 * # # Returned Buffer Content Pipe Content
3567 * r, w = IO.pipe #
3568 * w << 'abc' # "" "abc"
3569 * w.close # "" "abc" EOF
3570 * r.readpartial(4096) # => "abc" "" EOF
3571 * r.readpartial(4096) # raises EOFError
3572 *
3573 * # # Returned Buffer Content Pipe Content
3574 * r, w = IO.pipe #
3575 * w << "abc\ndef\n" # "" "abc\ndef\n"
3576 * r.gets # => "abc\n" "def\n" ""
3577 * w << "ghi\n" # "def\n" "ghi\n"
3578 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3579 * r.readpartial(4096) # => "ghi\n" "" ""
3580 *
3581 */
3582
3583static VALUE
3584io_readpartial(int argc, VALUE *argv, VALUE io)
3585{
3586 VALUE ret;
3587
3588 ret = io_getpartial(argc, argv, io, Qnil, 0);
3589 if (NIL_P(ret))
3590 rb_eof_error();
3591 return ret;
3592}
3593
3594static VALUE
3595io_nonblock_eof(int no_exception)
3596{
3597 if (!no_exception) {
3598 rb_eof_error();
3599 }
3600 return Qnil;
3601}
3602
3603/* :nodoc: */
3604static VALUE
3605io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3606{
3607 rb_io_t *fptr;
3608 long n, len;
3609 struct io_internal_read_struct iis;
3610 int shrinkable;
3611
3612 if ((len = NUM2LONG(length)) < 0) {
3613 rb_raise(rb_eArgError, "negative length %ld given", len);
3614 }
3615
3616 shrinkable = io_setstrbuf(&str, len);
3617 rb_bool_expected(ex, "exception", TRUE);
3618
3619 GetOpenFile(io, fptr);
3620 rb_io_check_byte_readable(fptr);
3621
3622 if (len == 0) {
3623 io_set_read_length(str, 0, shrinkable);
3624 return str;
3625 }
3626
3627 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3628 if (n <= 0) {
3629 rb_fd_set_nonblock(fptr->fd);
3630 shrinkable |= io_setstrbuf(&str, len);
3631 iis.fptr = fptr;
3632 iis.nonblock = 1;
3633 iis.fd = fptr->fd;
3634 iis.buf = RSTRING_PTR(str);
3635 iis.capa = len;
3636 iis.timeout = NULL;
3637 n = io_read_memory_locktmp(str, &iis);
3638 if (n < 0) {
3639 int e = errno;
3640 if (io_again_p(e)) {
3641 if (!ex) return sym_wait_readable;
3642 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3643 e, "read would block");
3644 }
3645 rb_syserr_fail_path(e, fptr->pathv);
3646 }
3647 }
3648 io_set_read_length(str, n, shrinkable);
3649
3650 if (n == 0) {
3651 if (!ex) return Qnil;
3652 rb_eof_error();
3653 }
3654
3655 return str;
3656}
3657
3658/* :nodoc: */
3659static VALUE
3660io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3661{
3662 rb_io_t *fptr;
3663 long n;
3664
3665 if (!RB_TYPE_P(str, T_STRING))
3666 str = rb_obj_as_string(str);
3667 rb_bool_expected(ex, "exception", TRUE);
3668
3669 io = GetWriteIO(io);
3670 GetOpenFile(io, fptr);
3671 rb_io_check_writable(fptr);
3672
3673 if (io_fflush(fptr) < 0)
3674 rb_sys_fail_on_write(fptr);
3675
3676 rb_fd_set_nonblock(fptr->fd);
3677 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3678 RB_GC_GUARD(str);
3679
3680 if (n < 0) {
3681 int e = errno;
3682 if (io_again_p(e)) {
3683 if (!ex) {
3684 return sym_wait_writable;
3685 }
3686 else {
3687 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3688 }
3689 }
3690 rb_syserr_fail_path(e, fptr->pathv);
3691 }
3692
3693 return LONG2FIX(n);
3694}
3695
3696/*
3697 * call-seq:
3698 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3699 *
3700 * Reads bytes from the stream; the stream must be opened for reading
3701 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3702 *
3703 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3704 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3705 *
3706 * Returns a string (either a new string or the given +out_string+)
3707 * containing the bytes read.
3708 * The encoding of the string depends on both +maxLen+ and +out_string+:
3709 *
3710 * - +maxlen+ is +nil+: uses internal encoding of +self+
3711 * (regardless of whether +out_string+ was given).
3712 * - +maxlen+ not +nil+:
3713 *
3714 * - +out_string+ given: encoding of +out_string+ not modified.
3715 * - +out_string+ not given: ASCII-8BIT is used.
3716 *
3717 * <b>Without Argument +out_string+</b>
3718 *
3719 * When argument +out_string+ is omitted,
3720 * the returned value is a new string:
3721 *
3722 * f = File.new('t.txt')
3723 * f.read
3724 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3725 * f.rewind
3726 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3727 * f.read(30) # => "rth line\r\nFifth line\r\n"
3728 * f.read(30) # => nil
3729 * f.close
3730 *
3731 * If +maxlen+ is zero, returns an empty string.
3732 *
3733 * <b> With Argument +out_string+</b>
3734 *
3735 * When argument +out_string+ is given,
3736 * the returned value is +out_string+, whose content is replaced:
3737 *
3738 * f = File.new('t.txt')
3739 * s = 'foo' # => "foo"
3740 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3741 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3742 * f.rewind
3743 * s = 'bar'
3744 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3745 * s # => "First line\r\nSecond line\r\n\r\nFou"
3746 * s = 'baz'
3747 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3748 * s # => "rth line\r\nFifth line\r\n"
3749 * s = 'bat'
3750 * f.read(30, s) # => nil
3751 * s # => ""
3752 * f.close
3753 *
3754 * Note that this method behaves like the fread() function in C.
3755 * This means it retries to invoke read(2) system calls to read data
3756 * with the specified maxlen (or until EOF).
3757 *
3758 * This behavior is preserved even if the stream is in non-blocking mode.
3759 * (This method is non-blocking-flag insensitive as other methods.)
3760 *
3761 * If you need the behavior like a single read(2) system call,
3762 * consider #readpartial, #read_nonblock, and #sysread.
3763 *
3764 * Related: IO#write.
3765 */
3766
3767static VALUE
3768io_read(int argc, VALUE *argv, VALUE io)
3769{
3770 rb_io_t *fptr;
3771 long n, len;
3772 VALUE length, str;
3773 int shrinkable;
3774#if RUBY_CRLF_ENVIRONMENT
3775 int previous_mode;
3776#endif
3777
3778 rb_scan_args(argc, argv, "02", &length, &str);
3779
3780 if (NIL_P(length)) {
3781 GetOpenFile(io, fptr);
3782 rb_io_check_char_readable(fptr);
3783 return read_all(fptr, remain_size(fptr), str);
3784 }
3785 len = NUM2LONG(length);
3786 if (len < 0) {
3787 rb_raise(rb_eArgError, "negative length %ld given", len);
3788 }
3789
3790 shrinkable = io_setstrbuf(&str,len);
3791
3792 GetOpenFile(io, fptr);
3793 rb_io_check_byte_readable(fptr);
3794 if (len == 0) {
3795 io_set_read_length(str, 0, shrinkable);
3796 return str;
3797 }
3798
3799 READ_CHECK(fptr);
3800#if RUBY_CRLF_ENVIRONMENT
3801 previous_mode = set_binary_mode_with_seek_cur(fptr);
3802#endif
3803 n = io_fread(str, 0, len, fptr);
3804 io_set_read_length(str, n, shrinkable);
3805#if RUBY_CRLF_ENVIRONMENT
3806 if (previous_mode == O_TEXT) {
3807 setmode(fptr->fd, O_TEXT);
3808 }
3809#endif
3810 if (n == 0) return Qnil;
3811
3812 return str;
3813}
3814
3815static void
3816rscheck(const char *rsptr, long rslen, VALUE rs)
3817{
3818 if (!rs) return;
3819 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3820 rb_raise(rb_eRuntimeError, "rs modified");
3821}
3822
3823static int
3824appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
3825{
3826 VALUE str = *strp;
3827 long limit = *lp;
3828
3829 if (NEED_READCONV(fptr)) {
3830 SET_BINARY_MODE(fptr);
3831 make_readconv(fptr, 0);
3832 do {
3833 const char *p, *e;
3834 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3835 if (searchlen) {
3836 p = READ_CHAR_PENDING_PTR(fptr);
3837 if (0 < limit && limit < searchlen)
3838 searchlen = (int)limit;
3839 e = memchr(p, delim, searchlen);
3840 if (e) {
3841 int len = (int)(e-p+1);
3842 if (NIL_P(str))
3843 *strp = str = rb_str_new(p, len);
3844 else
3845 rb_str_buf_cat(str, p, len);
3846 fptr->cbuf.off += len;
3847 fptr->cbuf.len -= len;
3848 limit -= len;
3849 *lp = limit;
3850 return delim;
3851 }
3852
3853 if (NIL_P(str))
3854 *strp = str = rb_str_new(p, searchlen);
3855 else
3856 rb_str_buf_cat(str, p, searchlen);
3857 fptr->cbuf.off += searchlen;
3858 fptr->cbuf.len -= searchlen;
3859 limit -= searchlen;
3860
3861 if (limit == 0) {
3862 *lp = limit;
3863 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3864 }
3865 }
3866 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3867 clear_readconv(fptr);
3868 *lp = limit;
3869 return EOF;
3870 }
3871
3872 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3873 do {
3874 long pending = READ_DATA_PENDING_COUNT(fptr);
3875 if (pending > 0) {
3876 const char *p = READ_DATA_PENDING_PTR(fptr);
3877 const char *e;
3878 long last;
3879
3880 if (limit > 0 && pending > limit) pending = limit;
3881 e = memchr(p, delim, pending);
3882 if (e) pending = e - p + 1;
3883 if (!NIL_P(str)) {
3884 last = RSTRING_LEN(str);
3885 rb_str_resize(str, last + pending);
3886 }
3887 else {
3888 last = 0;
3889 *strp = str = rb_str_buf_new(pending);
3890 rb_str_set_len(str, pending);
3891 }
3892 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3893 limit -= pending;
3894 *lp = limit;
3895 if (e) return delim;
3896 if (limit == 0)
3897 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3898 }
3899 READ_CHECK(fptr);
3900 } while (io_fillbuf(fptr) >= 0);
3901 *lp = limit;
3902 return EOF;
3903}
3904
3905static inline int
3906swallow(rb_io_t *fptr, int term)
3907{
3908 if (NEED_READCONV(fptr)) {
3909 rb_encoding *enc = io_read_encoding(fptr);
3910 int needconv = rb_enc_mbminlen(enc) != 1;
3911 SET_BINARY_MODE(fptr);
3912 make_readconv(fptr, 0);
3913 do {
3914 size_t cnt;
3915 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3916 const char *p = READ_CHAR_PENDING_PTR(fptr);
3917 int i;
3918 if (!needconv) {
3919 if (*p != term) return TRUE;
3920 i = (int)cnt;
3921 while (--i && *++p == term);
3922 }
3923 else {
3924 const char *e = p + cnt;
3925 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3926 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3927 i = (int)(e - p);
3928 }
3929 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3930 }
3931 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3932 return FALSE;
3933 }
3934
3935 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3936 do {
3937 size_t cnt;
3938 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3939 char buf[1024];
3940 const char *p = READ_DATA_PENDING_PTR(fptr);
3941 int i;
3942 if (cnt > sizeof buf) cnt = sizeof buf;
3943 if (*p != term) return TRUE;
3944 i = (int)cnt;
3945 while (--i && *++p == term);
3946 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
3947 rb_sys_fail_path(fptr->pathv);
3948 }
3949 READ_CHECK(fptr);
3950 } while (io_fillbuf(fptr) == 0);
3951 return FALSE;
3952}
3953
3954static VALUE
3955rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
3956{
3957 VALUE str = Qnil;
3958 int len = 0;
3959 long pos = 0;
3960 int cr = 0;
3961
3962 do {
3963 int pending = READ_DATA_PENDING_COUNT(fptr);
3964
3965 if (pending > 0) {
3966 const char *p = READ_DATA_PENDING_PTR(fptr);
3967 const char *e;
3968 int chomplen = 0;
3969
3970 e = memchr(p, '\n', pending);
3971 if (e) {
3972 pending = (int)(e - p + 1);
3973 if (chomp) {
3974 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
3975 }
3976 }
3977 if (NIL_P(str)) {
3978 str = rb_str_new(p, pending - chomplen);
3979 fptr->rbuf.off += pending;
3980 fptr->rbuf.len -= pending;
3981 }
3982 else {
3983 rb_str_resize(str, len + pending - chomplen);
3984 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
3985 fptr->rbuf.off += chomplen;
3986 fptr->rbuf.len -= chomplen;
3987 if (pending == 1 && chomplen == 1 && len > 0) {
3988 if (RSTRING_PTR(str)[len-1] == '\r') {
3989 rb_str_resize(str, --len);
3990 break;
3991 }
3992 }
3993 }
3994 len += pending - chomplen;
3995 if (cr != ENC_CODERANGE_BROKEN)
3996 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
3997 if (e) break;
3998 }
3999 READ_CHECK(fptr);
4000 } while (io_fillbuf(fptr) >= 0);
4001 if (NIL_P(str)) return Qnil;
4002
4003 str = io_enc_str(str, fptr);
4004 ENC_CODERANGE_SET(str, cr);
4005 fptr->lineno++;
4006
4007 return str;
4008}
4009
4010 struct getline_arg {
4011 VALUE io;
4012 VALUE rs;
4013 long limit;
4014 unsigned int chomp: 1;
4015};
4016
4017static void
4018extract_getline_opts(VALUE opts, struct getline_arg *args)
4019{
4020 int chomp = FALSE;
4021 if (!NIL_P(opts)) {
4022 static ID kwds[1];
4023 VALUE vchomp;
4024 if (!kwds[0]) {
4025 kwds[0] = rb_intern_const("chomp");
4026 }
4027 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4028 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4029 }
4030 args->chomp = chomp;
4031}
4032
4033static void
4034extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4035{
4036 VALUE rs = rb_rs, lim = Qnil;
4037
4038 if (argc == 1) {
4039 VALUE tmp = Qnil;
4040
4041 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4042 rs = tmp;
4043 }
4044 else {
4045 lim = argv[0];
4046 }
4047 }
4048 else if (2 <= argc) {
4049 rs = argv[0], lim = argv[1];
4050 if (!NIL_P(rs))
4051 StringValue(rs);
4052 }
4053 args->rs = rs;
4054 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4055}
4056
4057static void
4058check_getline_args(VALUE *rsp, long *limit, VALUE io)
4059{
4060 rb_io_t *fptr;
4061 VALUE rs = *rsp;
4062
4063 if (!NIL_P(rs)) {
4064 rb_encoding *enc_rs, *enc_io;
4065
4066 GetOpenFile(io, fptr);
4067 enc_rs = rb_enc_get(rs);
4068 enc_io = io_read_encoding(fptr);
4069 if (enc_io != enc_rs &&
4070 (!is_ascii_string(rs) ||
4071 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4072 if (rs == rb_default_rs) {
4073 rs = rb_enc_str_new(0, 0, enc_io);
4074 rb_str_buf_cat_ascii(rs, "\n");
4075 *rsp = rs;
4076 }
4077 else {
4078 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4079 rb_enc_name(enc_io),
4080 rb_enc_name(enc_rs));
4081 }
4082 }
4083 }
4084}
4085
4086static void
4087prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4088{
4089 VALUE opts;
4090 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4091 extract_getline_args(argc, argv, args);
4092 extract_getline_opts(opts, args);
4093 check_getline_args(&args->rs, &args->limit, io);
4094}
4095
4096static VALUE
4097rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4098{
4099 VALUE str = Qnil;
4100 int nolimit = 0;
4101 rb_encoding *enc;
4102
4103 rb_io_check_char_readable(fptr);
4104 if (NIL_P(rs) && limit < 0) {
4105 str = read_all(fptr, 0, Qnil);
4106 if (RSTRING_LEN(str) == 0) return Qnil;
4107 }
4108 else if (limit == 0) {
4109 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4110 }
4111 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4112 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4113 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4114 return rb_io_getline_fast(fptr, enc, chomp);
4115 }
4116 else {
4117 int c, newline = -1;
4118 const char *rsptr = 0;
4119 long rslen = 0;
4120 int rspara = 0;
4121 int extra_limit = 16;
4122 int chomp_cr = chomp;
4123
4124 SET_BINARY_MODE(fptr);
4125 enc = io_read_encoding(fptr);
4126
4127 if (!NIL_P(rs)) {
4128 rslen = RSTRING_LEN(rs);
4129 if (rslen == 0) {
4130 rsptr = "\n\n";
4131 rslen = 2;
4132 rspara = 1;
4133 swallow(fptr, '\n');
4134 rs = 0;
4135 if (!rb_enc_asciicompat(enc)) {
4136 rs = rb_usascii_str_new(rsptr, rslen);
4137 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
4138 OBJ_FREEZE(rs);
4139 rsptr = RSTRING_PTR(rs);
4140 rslen = RSTRING_LEN(rs);
4141 }
4142 }
4143 else {
4144 rsptr = RSTRING_PTR(rs);
4145 }
4146 newline = (unsigned char)rsptr[rslen - 1];
4147 chomp_cr = chomp && rslen == 1 && newline == '\n';
4148 }
4149
4150 /* MS - Optimization */
4151 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
4152 const char *s, *p, *pp, *e;
4153
4154 if (c == newline) {
4155 if (RSTRING_LEN(str) < rslen) continue;
4156 s = RSTRING_PTR(str);
4157 e = RSTRING_END(str);
4158 p = e - rslen;
4159 if (!at_char_boundary(s, p, e, enc)) continue;
4160 if (!rspara) rscheck(rsptr, rslen, rs);
4161 if (memcmp(p, rsptr, rslen) == 0) {
4162 if (chomp) {
4163 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4164 rb_str_set_len(str, p - s);
4165 }
4166 break;
4167 }
4168 }
4169 if (limit == 0) {
4170 s = RSTRING_PTR(str);
4171 p = RSTRING_END(str);
4172 pp = rb_enc_left_char_head(s, p-1, p, enc);
4173 if (extra_limit &&
4174 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4175 /* relax the limit while incomplete character.
4176 * extra_limit limits the relax length */
4177 limit = 1;
4178 extra_limit--;
4179 }
4180 else {
4181 nolimit = 1;
4182 break;
4183 }
4184 }
4185 }
4186
4187 if (rspara && c != EOF)
4188 swallow(fptr, '\n');
4189 if (!NIL_P(str))
4190 str = io_enc_str(str, fptr);
4191 }
4192
4193 if (!NIL_P(str) && !nolimit) {
4194 fptr->lineno++;
4195 }
4196
4197 return str;
4198}
4199
4200static VALUE
4201rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4202{
4203 rb_io_t *fptr;
4204 int old_lineno, new_lineno;
4205 VALUE str;
4206
4207 GetOpenFile(io, fptr);
4208 old_lineno = fptr->lineno;
4209 str = rb_io_getline_0(rs, limit, chomp, fptr);
4210 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4211 if (io == ARGF.current_file) {
4212 ARGF.lineno += new_lineno - old_lineno;
4213 ARGF.last_lineno = ARGF.lineno;
4214 }
4215 else {
4216 ARGF.last_lineno = new_lineno;
4217 }
4218 }
4219
4220 return str;
4221}
4222
4223static VALUE
4224rb_io_getline(int argc, VALUE *argv, VALUE io)
4225{
4226 struct getline_arg args;
4227
4228 prepare_getline_args(argc, argv, &args, io);
4229 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4230}
4231
4232 VALUE
4233rb_io_gets(VALUE io)
4234{
4235 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4236}
4237
4238 VALUE
4239rb_io_gets_internal(VALUE io)
4240{
4241 rb_io_t *fptr;
4242 GetOpenFile(io, fptr);
4243 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4244}
4245
4246/*
4247 * call-seq:
4248 * gets(sep = $/, chomp: false) -> string or nil
4249 * gets(limit, chomp: false) -> string or nil
4250 * gets(sep, limit, chomp: false) -> string or nil
4251 *
4252 * Reads and returns a line from the stream;
4253 * assigns the return value to <tt>$_</tt>.
4254 * See {Line IO}[rdoc-ref:IO@Line+IO].
4255 *
4256 * With no arguments given, returns the next line
4257 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4258 *
4259 * f = File.open('t.txt')
4260 * f.gets # => "First line\n"
4261 * $_ # => "First line\n"
4262 * f.gets # => "\n"
4263 * f.gets # => "Fourth line\n"
4264 * f.gets # => "Fifth line\n"
4265 * f.gets # => nil
4266 * f.close
4267 *
4268 * With only string argument +sep+ given,
4269 * returns the next line as determined by line separator +sep+,
4270 * or +nil+ if none;
4271 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4272 *
4273 * f = File.new('t.txt')
4274 * f.gets('l') # => "First l"
4275 * f.gets('li') # => "ine\nSecond li"
4276 * f.gets('lin') # => "ne\n\nFourth lin"
4277 * f.gets # => "e\n"
4278 * f.close
4279 *
4280 * The two special values for +sep+ are honored:
4281 *
4282 * f = File.new('t.txt')
4283 * # Get all.
4284 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4285 * f.rewind
4286 * # Get paragraph (up to two line separators).
4287 * f.gets('') # => "First line\nSecond line\n\n"
4288 * f.close
4289 *
4290 * With only integer argument +limit+ given,
4291 * limits the number of bytes in the line;
4292 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4293 *
4294 * # No more than one line.
4295 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4296 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4297 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4298 *
4299 * With arguments +sep+ and +limit+ given,
4300 * combines the two behaviors:
4301 *
4302 * - Returns the next line as determined by line separator +sep+,
4303 * or +nil+ if none.
4304 * - But returns no more bytes than are allowed by the limit.
4305 *
4306 * Optional keyword argument +chomp+ specifies whether line separators
4307 * are to be omitted:
4308 *
4309 * f = File.open('t.txt')
4310 * # Chomp the lines.
4311 * f.gets(chomp: true) # => "First line"
4312 * f.gets(chomp: true) # => "Second line"
4313 * f.gets(chomp: true) # => ""
4314 * f.gets(chomp: true) # => "Fourth line"
4315 * f.gets(chomp: true) # => "Fifth line"
4316 * f.gets(chomp: true) # => nil
4317 * f.close
4318 *
4319 */
4320
4321static VALUE
4322rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4323{
4324 VALUE str;
4325
4326 str = rb_io_getline(argc, argv, io);
4327 rb_lastline_set(str);
4328
4329 return str;
4330}
4331
4332/*
4333 * call-seq:
4334 * lineno -> integer
4335 *
4336 * Returns the current line number for the stream;
4337 * see {Line Number}[rdoc-ref:IO@Line+Number].
4338 *
4339 */
4340
4341static VALUE
4342rb_io_lineno(VALUE io)
4343{
4344 rb_io_t *fptr;
4345
4346 GetOpenFile(io, fptr);
4347 rb_io_check_char_readable(fptr);
4348 return INT2NUM(fptr->lineno);
4349}
4350
4351/*
4352 * call-seq:
4353 * lineno = integer -> integer
4354 *
4355 * Sets and returns the line number for the stream;
4356 * see {Line Number}[rdoc-ref:IO@Line+Number].
4357 *
4358 */
4359
4360static VALUE
4361rb_io_set_lineno(VALUE io, VALUE lineno)
4362{
4363 rb_io_t *fptr;
4364
4365 GetOpenFile(io, fptr);
4366 rb_io_check_char_readable(fptr);
4367 fptr->lineno = NUM2INT(lineno);
4368 return lineno;
4369}
4370
4371/* :nodoc: */
4372static VALUE
4373io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4374{
4375 if (NIL_P(lim)) {
4376 // If sep is specified, but it's not a string and not nil, then assume
4377 // it's the limit (it should be an integer)
4378 if (!NIL_P(sep) && NIL_P(rb_check_string_type(sep))) {
4379 // If the user has specified a non-nil / non-string value
4380 // for the separator, we assume it's the limit and set the
4381 // separator to default: rb_rs.
4382 lim = sep;
4383 sep = rb_rs;
4384 }
4385 }
4386
4387 if (!NIL_P(sep)) {
4388 StringValue(sep);
4389 }
4390
4391 VALUE line = rb_io_getline_1(sep, NIL_P(lim) ? -1L : NUM2LONG(lim), RTEST(chomp), io);
4392 rb_lastline_set_up(line, 1);
4393
4394 if (NIL_P(line)) {
4395 rb_eof_error();
4396 }
4397 return line;
4398}
4399
4400static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4401
4402/*
4403 * call-seq:
4404 * readlines(sep = $/, chomp: false) -> array
4405 * readlines(limit, chomp: false) -> array
4406 * readlines(sep, limit, chomp: false) -> array
4407 *
4408 * Reads and returns all remaining line from the stream;
4409 * does not modify <tt>$_</tt>.
4410 * See {Line IO}[rdoc-ref:IO@Line+IO].
4411 *
4412 * With no arguments given, returns lines
4413 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4414 *
4415 * f = File.new('t.txt')
4416 * f.readlines
4417 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4418 * f.readlines # => []
4419 * f.close
4420 *
4421 * With only string argument +sep+ given,
4422 * returns lines as determined by line separator +sep+,
4423 * or +nil+ if none;
4424 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4425 *
4426 * f = File.new('t.txt')
4427 * f.readlines('li')
4428 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4429 * f.close
4430 *
4431 * The two special values for +sep+ are honored:
4432 *
4433 * f = File.new('t.txt')
4434 * # Get all into one string.
4435 * f.readlines(nil)
4436 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4437 * # Get paragraphs (up to two line separators).
4438 * f.rewind
4439 * f.readlines('')
4440 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4441 * f.close
4442 *
4443 * With only integer argument +limit+ given,
4444 * limits the number of bytes in each line;
4445 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4446 *
4447 * f = File.new('t.txt')
4448 * f.readlines(8)
4449 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4450 * f.close
4451 *
4452 * With arguments +sep+ and +limit+ given,
4453 * combines the two behaviors:
4454 *
4455 * - Returns lines as determined by line separator +sep+.
4456 * - But returns no more bytes in a line than are allowed by the limit.
4457 *
4458 * Optional keyword argument +chomp+ specifies whether line separators
4459 * are to be omitted:
4460 *
4461 * f = File.new('t.txt')
4462 * f.readlines(chomp: true)
4463 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4464 * f.close
4465 *
4466 */
4467
4468static VALUE
4469rb_io_readlines(int argc, VALUE *argv, VALUE io)
4470{
4471 struct getline_arg args;
4472
4473 prepare_getline_args(argc, argv, &args, io);
4474 return io_readlines(&args, io);
4475}
4476
4477static VALUE
4478io_readlines(const struct getline_arg *arg, VALUE io)
4479{
4480 VALUE line, ary;
4481
4482 if (arg->limit == 0)
4483 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4484 ary = rb_ary_new();
4485 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4486 rb_ary_push(ary, line);
4487 }
4488 return ary;
4489}
4490
4491/*
4492 * call-seq:
4493 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4494 * each_line(limit, chomp: false) {|line| ... } -> self
4495 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4496 * each_line -> enumerator
4497 *
4498 * Calls the block with each remaining line read from the stream;
4499 * returns +self+.
4500 * Does nothing if already at end-of-stream;
4501 * See {Line IO}[rdoc-ref:IO@Line+IO].
4502 *
4503 * With no arguments given, reads lines
4504 * as determined by line separator <tt>$/</tt>:
4505 *
4506 * f = File.new('t.txt')
4507 * f.each_line {|line| p line }
4508 * f.each_line {|line| fail 'Cannot happen' }
4509 * f.close
4510 *
4511 * Output:
4512 *
4513 * "First line\n"
4514 * "Second line\n"
4515 * "\n"
4516 * "Fourth line\n"
4517 * "Fifth line\n"
4518 *
4519 * With only string argument +sep+ given,
4520 * reads lines as determined by line separator +sep+;
4521 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4522 *
4523 * f = File.new('t.txt')
4524 * f.each_line('li') {|line| p line }
4525 * f.close
4526 *
4527 * Output:
4528 *
4529 * "First li"
4530 * "ne\nSecond li"
4531 * "ne\n\nFourth li"
4532 * "ne\nFifth li"
4533 * "ne\n"
4534 *
4535 * The two special values for +sep+ are honored:
4536 *
4537 * f = File.new('t.txt')
4538 * # Get all into one string.
4539 * f.each_line(nil) {|line| p line }
4540 * f.close
4541 *
4542 * Output:
4543 *
4544 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4545 *
4546 * f.rewind
4547 * # Get paragraphs (up to two line separators).
4548 * f.each_line('') {|line| p line }
4549 *
4550 * Output:
4551 *
4552 * "First line\nSecond line\n\n"
4553 * "Fourth line\nFifth line\n"
4554 *
4555 * With only integer argument +limit+ given,
4556 * limits the number of bytes in each line;
4557 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4558 *
4559 * f = File.new('t.txt')
4560 * f.each_line(8) {|line| p line }
4561 * f.close
4562 *
4563 * Output:
4564 *
4565 * "First li"
4566 * "ne\n"
4567 * "Second l"
4568 * "ine\n"
4569 * "\n"
4570 * "Fourth l"
4571 * "ine\n"
4572 * "Fifth li"
4573 * "ne\n"
4574 *
4575 * With arguments +sep+ and +limit+ given,
4576 * combines the two behaviors:
4577 *
4578 * - Calls with the next line as determined by line separator +sep+.
4579 * - But returns no more bytes than are allowed by the limit.
4580 *
4581 * Optional keyword argument +chomp+ specifies whether line separators
4582 * are to be omitted:
4583 *
4584 * f = File.new('t.txt')
4585 * f.each_line(chomp: true) {|line| p line }
4586 * f.close
4587 *
4588 * Output:
4589 *
4590 * "First line"
4591 * "Second line"
4592 * ""
4593 * "Fourth line"
4594 * "Fifth line"
4595 *
4596 * Returns an Enumerator if no block is given.
4597 */
4598
4599static VALUE
4600rb_io_each_line(int argc, VALUE *argv, VALUE io)
4601{
4602 VALUE str;
4603 struct getline_arg args;
4604
4605 RETURN_ENUMERATOR(io, argc, argv);
4606 prepare_getline_args(argc, argv, &args, io);
4607 if (args.limit == 0)
4608 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4609 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4610 rb_yield(str);
4611 }
4612 return io;
4613}
4614
4615/*
4616 * call-seq:
4617 * each_byte {|byte| ... } -> self
4618 * each_byte -> enumerator
4619 *
4620 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4621 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4622 *
4623 * f = File.new('t.rus')
4624 * a = []
4625 * f.each_byte {|b| a << b }
4626 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4627 * f.close
4628 *
4629 * Returns an Enumerator if no block is given.
4630 *
4631 * Related: IO#each_char, IO#each_codepoint.
4632 *
4633 */
4634
4635static VALUE
4636rb_io_each_byte(VALUE io)
4637{
4638 rb_io_t *fptr;
4639
4640 RETURN_ENUMERATOR(io, 0, 0);
4641 GetOpenFile(io, fptr);
4642
4643 do {
4644 while (fptr->rbuf.len > 0) {
4645 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4646 fptr->rbuf.len--;
4647 rb_yield(INT2FIX(*p & 0xff));
4648 rb_io_check_byte_readable(fptr);
4649 errno = 0;
4650 }
4651 READ_CHECK(fptr);
4652 } while (io_fillbuf(fptr) >= 0);
4653 return io;
4654}
4655
4656static VALUE
4657io_getc(rb_io_t *fptr, rb_encoding *enc)
4658{
4659 int r, n, cr = 0;
4660 VALUE str;
4661
4662 if (NEED_READCONV(fptr)) {
4663 rb_encoding *read_enc = io_read_encoding(fptr);
4664
4665 str = Qnil;
4666 SET_BINARY_MODE(fptr);
4667 make_readconv(fptr, 0);
4668
4669 while (1) {
4670 if (fptr->cbuf.len) {
4671 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4672 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4673 read_enc);
4674 if (!MBCLEN_NEEDMORE_P(r))
4675 break;
4676 if (fptr->cbuf.len == fptr->cbuf.capa) {
4677 rb_raise(rb_eIOError, "too long character");
4678 }
4679 }
4680
4681 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4682 if (fptr->cbuf.len == 0) {
4683 clear_readconv(fptr);
4684 return Qnil;
4685 }
4686 /* return an unit of an incomplete character just before EOF */
4687 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4688 fptr->cbuf.off += 1;
4689 fptr->cbuf.len -= 1;
4690 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4691 ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
4692 return str;
4693 }
4694 }
4695 if (MBCLEN_INVALID_P(r)) {
4696 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4697 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4698 read_enc);
4699 io_shift_cbuf(fptr, r, &str);
4700 cr = ENC_CODERANGE_BROKEN;
4701 }
4702 else {
4703 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4704 cr = ENC_CODERANGE_VALID;
4705 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4706 ISASCII(RSTRING_PTR(str)[0])) {
4707 cr = ENC_CODERANGE_7BIT;
4708 }
4709 }
4710 str = io_enc_str(str, fptr);
4711 ENC_CODERANGE_SET(str, cr);
4712 return str;
4713 }
4714
4715 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4716 if (io_fillbuf(fptr) < 0) {
4717 return Qnil;
4718 }
4719 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4720 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4721 fptr->rbuf.off += 1;
4722 fptr->rbuf.len -= 1;
4723 cr = ENC_CODERANGE_7BIT;
4724 }
4725 else {
4726 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4727 if (MBCLEN_CHARFOUND_P(r) &&
4728 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4729 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4730 fptr->rbuf.off += n;
4731 fptr->rbuf.len -= n;
4732 cr = ENC_CODERANGE_VALID;
4733 }
4734 else if (MBCLEN_NEEDMORE_P(r)) {
4735 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4736 fptr->rbuf.len = 0;
4737 getc_needmore:
4738 if (io_fillbuf(fptr) != -1) {
4739 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4740 fptr->rbuf.off++;
4741 fptr->rbuf.len--;
4742 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4743 if (MBCLEN_NEEDMORE_P(r)) {
4744 goto getc_needmore;
4745 }
4746 else if (MBCLEN_CHARFOUND_P(r)) {
4747 cr = ENC_CODERANGE_VALID;
4748 }
4749 }
4750 }
4751 else {
4752 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4753 fptr->rbuf.off++;
4754 fptr->rbuf.len--;
4755 }
4756 }
4757 if (!cr) cr = ENC_CODERANGE_BROKEN;
4758 str = io_enc_str(str, fptr);
4759 ENC_CODERANGE_SET(str, cr);
4760 return str;
4761}
4762
4763/*
4764 * call-seq:
4765 * each_char {|c| ... } -> self
4766 * each_char -> enumerator
4767 *
4768 * Calls the given block with each character in the stream; returns +self+.
4769 * See {Character IO}[rdoc-ref:IO@Character+IO].
4770 *
4771 * f = File.new('t.rus')
4772 * a = []
4773 * f.each_char {|c| a << c.ord }
4774 * a # => [1090, 1077, 1089, 1090]
4775 * f.close
4776 *
4777 * Returns an Enumerator if no block is given.
4778 *
4779 * Related: IO#each_byte, IO#each_codepoint.
4780 *
4781 */
4782
4783static VALUE
4784rb_io_each_char(VALUE io)
4785{
4786 rb_io_t *fptr;
4787 rb_encoding *enc;
4788 VALUE c;
4789
4790 RETURN_ENUMERATOR(io, 0, 0);
4791 GetOpenFile(io, fptr);
4792 rb_io_check_char_readable(fptr);
4793
4794 enc = io_input_encoding(fptr);
4795 READ_CHECK(fptr);
4796 while (!NIL_P(c = io_getc(fptr, enc))) {
4797 rb_yield(c);
4798 }
4799 return io;
4800}
4801
4802/*
4803 * call-seq:
4804 * each_codepoint {|c| ... } -> self
4805 * each_codepoint -> enumerator
4806 *
4807 * Calls the given block with each codepoint in the stream; returns +self+:
4808 *
4809 * f = File.new('t.rus')
4810 * a = []
4811 * f.each_codepoint {|c| a << c }
4812 * a # => [1090, 1077, 1089, 1090]
4813 * f.close
4814 *
4815 * Returns an Enumerator if no block is given.
4816 *
4817 * Related: IO#each_byte, IO#each_char.
4818 *
4819 */
4820
4821static VALUE
4822rb_io_each_codepoint(VALUE io)
4823{
4824 rb_io_t *fptr;
4825 rb_encoding *enc;
4826 unsigned int c;
4827 int r, n;
4828
4829 RETURN_ENUMERATOR(io, 0, 0);
4830 GetOpenFile(io, fptr);
4831 rb_io_check_char_readable(fptr);
4832
4833 READ_CHECK(fptr);
4834 if (NEED_READCONV(fptr)) {
4835 SET_BINARY_MODE(fptr);
4836 r = 1; /* no invalid char yet */
4837 for (;;) {
4838 make_readconv(fptr, 0);
4839 for (;;) {
4840 if (fptr->cbuf.len) {
4841 if (fptr->encs.enc)
4842 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4843 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4844 fptr->encs.enc);
4845 else
4846 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4847 if (!MBCLEN_NEEDMORE_P(r))
4848 break;
4849 if (fptr->cbuf.len == fptr->cbuf.capa) {
4850 rb_raise(rb_eIOError, "too long character");
4851 }
4852 }
4853 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4854 clear_readconv(fptr);
4855 if (!MBCLEN_CHARFOUND_P(r)) {
4856 enc = fptr->encs.enc;
4857 goto invalid;
4858 }
4859 return io;
4860 }
4861 }
4862 if (MBCLEN_INVALID_P(r)) {
4863 enc = fptr->encs.enc;
4864 goto invalid;
4865 }
4866 n = MBCLEN_CHARFOUND_LEN(r);
4867 if (fptr->encs.enc) {
4868 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4869 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4870 fptr->encs.enc);
4871 }
4872 else {
4873 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4874 }
4875 fptr->cbuf.off += n;
4876 fptr->cbuf.len -= n;
4877 rb_yield(UINT2NUM(c));
4878 rb_io_check_byte_readable(fptr);
4879 }
4880 }
4881 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4882 enc = io_input_encoding(fptr);
4883 while (io_fillbuf(fptr) >= 0) {
4884 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4885 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4886 if (MBCLEN_CHARFOUND_P(r) &&
4887 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4888 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4889 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4890 fptr->rbuf.off += n;
4891 fptr->rbuf.len -= n;
4892 rb_yield(UINT2NUM(c));
4893 }
4894 else if (MBCLEN_INVALID_P(r)) {
4895 goto invalid;
4896 }
4897 else if (MBCLEN_NEEDMORE_P(r)) {
4898 char cbuf[8], *p = cbuf;
4899 int more = MBCLEN_NEEDMORE_LEN(r);
4900 if (more > numberof(cbuf)) goto invalid;
4901 more += n = fptr->rbuf.len;
4902 if (more > numberof(cbuf)) goto invalid;
4903 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4904 (p += n, (more -= n) > 0)) {
4905 if (io_fillbuf(fptr) < 0) goto invalid;
4906 if ((n = fptr->rbuf.len) > more) n = more;
4907 }
4908 r = rb_enc_precise_mbclen(cbuf, p, enc);
4909 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4910 c = rb_enc_codepoint(cbuf, p, enc);
4911 rb_yield(UINT2NUM(c));
4912 }
4913 else {
4914 continue;
4915 }
4916 rb_io_check_byte_readable(fptr);
4917 }
4918 return io;
4919
4920 invalid:
4921 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4922 UNREACHABLE_RETURN(Qundef);
4923}
4924
4925/*
4926 * call-seq:
4927 * getc -> character or nil
4928 *
4929 * Reads and returns the next 1-character string from the stream;
4930 * returns +nil+ if already at end-of-stream.
4931 * See {Character IO}[rdoc-ref:IO@Character+IO].
4932 *
4933 * f = File.open('t.txt')
4934 * f.getc # => "F"
4935 * f.close
4936 * f = File.open('t.rus')
4937 * f.getc.ord # => 1090
4938 * f.close
4939 *
4940 * Related: IO#readchar (may raise EOFError).
4941 *
4942 */
4943
4944static VALUE
4945rb_io_getc(VALUE io)
4946{
4947 rb_io_t *fptr;
4948 rb_encoding *enc;
4949
4950 GetOpenFile(io, fptr);
4951 rb_io_check_char_readable(fptr);
4952
4953 enc = io_input_encoding(fptr);
4954 READ_CHECK(fptr);
4955 return io_getc(fptr, enc);
4956}
4957
4958/*
4959 * call-seq:
4960 * readchar -> string
4961 *
4962 * Reads and returns the next 1-character string from the stream;
4963 * raises EOFError if already at end-of-stream.
4964 * See {Character IO}[rdoc-ref:IO@Character+IO].
4965 *
4966 * f = File.open('t.txt')
4967 * f.readchar # => "F"
4968 * f.close
4969 * f = File.open('t.rus')
4970 * f.readchar.ord # => 1090
4971 * f.close
4972 *
4973 * Related: IO#getc (will not raise EOFError).
4974 *
4975 */
4976
4977static VALUE
4978rb_io_readchar(VALUE io)
4979{
4980 VALUE c = rb_io_getc(io);
4981
4982 if (NIL_P(c)) {
4983 rb_eof_error();
4984 }
4985 return c;
4986}
4987
4988/*
4989 * call-seq:
4990 * getbyte -> integer or nil
4991 *
4992 * Reads and returns the next byte (in range 0..255) from the stream;
4993 * returns +nil+ if already at end-of-stream.
4994 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4995 *
4996 * f = File.open('t.txt')
4997 * f.getbyte # => 70
4998 * f.close
4999 * f = File.open('t.rus')
5000 * f.getbyte # => 209
5001 * f.close
5002 *
5003 * Related: IO#readbyte (may raise EOFError).
5004 */
5005
5006 VALUE
5007rb_io_getbyte(VALUE io)
5008{
5009 rb_io_t *fptr;
5010 int c;
5011
5012 GetOpenFile(io, fptr);
5013 rb_io_check_byte_readable(fptr);
5014 READ_CHECK(fptr);
5015 VALUE r_stdout = rb_ractor_stdout();
5016 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5017 rb_io_t *ofp;
5018 GetOpenFile(r_stdout, ofp);
5019 if (ofp->mode & FMODE_TTY) {
5020 rb_io_flush(r_stdout);
5021 }
5022 }
5023 if (io_fillbuf(fptr) < 0) {
5024 return Qnil;
5025 }
5026 fptr->rbuf.off++;
5027 fptr->rbuf.len--;
5028 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5029 return INT2FIX(c & 0xff);
5030}
5031
5032/*
5033 * call-seq:
5034 * readbyte -> integer
5035 *
5036 * Reads and returns the next byte (in range 0..255) from the stream;
5037 * raises EOFError if already at end-of-stream.
5038 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5039 *
5040 * f = File.open('t.txt')
5041 * f.readbyte # => 70
5042 * f.close
5043 * f = File.open('t.rus')
5044 * f.readbyte # => 209
5045 * f.close
5046 *
5047 * Related: IO#getbyte (will not raise EOFError).
5048 *
5049 */
5050
5051static VALUE
5052rb_io_readbyte(VALUE io)
5053{
5054 VALUE c = rb_io_getbyte(io);
5055
5056 if (NIL_P(c)) {
5057 rb_eof_error();
5058 }
5059 return c;
5060}
5061
5062/*
5063 * call-seq:
5064 * ungetbyte(integer) -> nil
5065 * ungetbyte(string) -> nil
5066 *
5067 * Pushes back ("unshifts") the given data onto the stream's buffer,
5068 * placing the data so that it is next to be read; returns +nil+.
5069 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5070 *
5071 * Note that:
5072 *
5073 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5074 * - Calling #rewind on the stream discards the pushed-back data.
5075 *
5076 * When argument +integer+ is given, uses only its low-order byte:
5077 *
5078 * File.write('t.tmp', '012')
5079 * f = File.open('t.tmp')
5080 * f.ungetbyte(0x41) # => nil
5081 * f.read # => "A012"
5082 * f.rewind
5083 * f.ungetbyte(0x4243) # => nil
5084 * f.read # => "C012"
5085 * f.close
5086 *
5087 * When argument +string+ is given, uses all bytes:
5088 *
5089 * File.write('t.tmp', '012')
5090 * f = File.open('t.tmp')
5091 * f.ungetbyte('A') # => nil
5092 * f.read # => "A012"
5093 * f.rewind
5094 * f.ungetbyte('BCDE') # => nil
5095 * f.read # => "BCDE012"
5096 * f.close
5097 *
5098 */
5099
5100 VALUE
5101rb_io_ungetbyte(VALUE io, VALUE b)
5102{
5103 rb_io_t *fptr;
5104
5105 GetOpenFile(io, fptr);
5106 rb_io_check_byte_readable(fptr);
5107 switch (TYPE(b)) {
5108 case T_NIL:
5109 return Qnil;
5110 case T_FIXNUM:
5111 case T_BIGNUM: ;
5112 VALUE v = rb_int_modulo(b, INT2FIX(256));
5113 unsigned char c = NUM2INT(v) & 0xFF;
5114 b = rb_str_new((const char *)&c, 1);
5115 break;
5116 default:
5117 SafeStringValue(b);
5118 }
5119 io_ungetbyte(b, fptr);
5120 return Qnil;
5121}
5122
5123/*
5124 * call-seq:
5125 * ungetc(integer) -> nil
5126 * ungetc(string) -> nil
5127 *
5128 * Pushes back ("unshifts") the given data onto the stream's buffer,
5129 * placing the data so that it is next to be read; returns +nil+.
5130 * See {Character IO}[rdoc-ref:IO@Character+IO].
5131 *
5132 * Note that:
5133 *
5134 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5135 * - Calling #rewind on the stream discards the pushed-back data.
5136 *
5137 * When argument +integer+ is given, interprets the integer as a character:
5138 *
5139 * File.write('t.tmp', '012')
5140 * f = File.open('t.tmp')
5141 * f.ungetc(0x41) # => nil
5142 * f.read # => "A012"
5143 * f.rewind
5144 * f.ungetc(0x0442) # => nil
5145 * f.getc.ord # => 1090
5146 * f.close
5147 *
5148 * When argument +string+ is given, uses all characters:
5149 *
5150 * File.write('t.tmp', '012')
5151 * f = File.open('t.tmp')
5152 * f.ungetc('A') # => nil
5153 * f.read # => "A012"
5154 * f.rewind
5155 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5156 * f.getc.ord # => 1090
5157 * f.getc.ord # => 1077
5158 * f.getc.ord # => 1089
5159 * f.getc.ord # => 1090
5160 * f.close
5161 *
5162 */
5163
5164 VALUE
5165rb_io_ungetc(VALUE io, VALUE c)
5166{
5167 rb_io_t *fptr;
5168 long len;
5169
5170 GetOpenFile(io, fptr);
5171 rb_io_check_char_readable(fptr);
5172 if (FIXNUM_P(c)) {
5173 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5174 }
5175 else if (RB_BIGNUM_TYPE_P(c)) {
5176 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5177 }
5178 else {
5179 SafeStringValue(c);
5180 }
5181 if (NEED_READCONV(fptr)) {
5182 SET_BINARY_MODE(fptr);
5183 len = RSTRING_LEN(c);
5184#if SIZEOF_LONG > SIZEOF_INT
5185 if (len > INT_MAX)
5186 rb_raise(rb_eIOError, "ungetc failed");
5187#endif
5188 make_readconv(fptr, (int)len);
5189 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5190 rb_raise(rb_eIOError, "ungetc failed");
5191 if (fptr->cbuf.off < len) {
5192 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5193 fptr->cbuf.ptr+fptr->cbuf.off,
5194 char, fptr->cbuf.len);
5195 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5196 }
5197 fptr->cbuf.off -= (int)len;
5198 fptr->cbuf.len += (int)len;
5199 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5200 }
5201 else {
5202 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5203 io_ungetbyte(c, fptr);
5204 }
5205 return Qnil;
5206}
5207
5208/*
5209 * call-seq:
5210 * isatty -> true or false
5211 *
5212 * Returns +true+ if the stream is associated with a terminal device (tty),
5213 * +false+ otherwise:
5214 *
5215 * f = File.new('t.txt').isatty #=> false
5216 * f.close
5217 * f = File.new('/dev/tty').isatty #=> true
5218 * f.close
5219 *
5220 */
5221
5222static VALUE
5223rb_io_isatty(VALUE io)
5224{
5225 rb_io_t *fptr;
5226
5227 GetOpenFile(io, fptr);
5228 return RBOOL(isatty(fptr->fd) != 0);
5229}
5230
5231#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5232/*
5233 * call-seq:
5234 * close_on_exec? -> true or false
5235 *
5236 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5237 *
5238 * f = File.open('t.txt')
5239 * f.close_on_exec? # => true
5240 * f.close_on_exec = false
5241 * f.close_on_exec? # => false
5242 * f.close
5243 *
5244 */
5245
5246static VALUE
5247rb_io_close_on_exec_p(VALUE io)
5248{
5249 rb_io_t *fptr;
5250 VALUE write_io;
5251 int fd, ret;
5252
5253 write_io = GetWriteIO(io);
5254 if (io != write_io) {
5255 GetOpenFile(write_io, fptr);
5256 if (fptr && 0 <= (fd = fptr->fd)) {
5257 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5258 if (!(ret & FD_CLOEXEC)) return Qfalse;
5259 }
5260 }
5261
5262 GetOpenFile(io, fptr);
5263 if (fptr && 0 <= (fd = fptr->fd)) {
5264 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5265 if (!(ret & FD_CLOEXEC)) return Qfalse;
5266 }
5267 return Qtrue;
5268}
5269#else
5270#define rb_io_close_on_exec_p rb_f_notimplement
5271#endif
5272
5273#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5274/*
5275 * call-seq:
5276 * self.close_on_exec = bool -> true or false
5277 *
5278 * Sets a close-on-exec flag.
5279 *
5280 * f = File.open(File::NULL)
5281 * f.close_on_exec = true
5282 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5283 * f.closed? #=> false
5284 *
5285 * Ruby sets close-on-exec flags of all file descriptors by default
5286 * since Ruby 2.0.0.
5287 * So you don't need to set by yourself.
5288 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5289 * if another thread use fork() and exec() (via system() method for example).
5290 * If you really needs file descriptor inheritance to child process,
5291 * use spawn()'s argument such as fd=>fd.
5292 */
5293
5294static VALUE
5295rb_io_set_close_on_exec(VALUE io, VALUE arg)
5296{
5297 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5298 rb_io_t *fptr;
5299 VALUE write_io;
5300 int fd, ret;
5301
5302 write_io = GetWriteIO(io);
5303 if (io != write_io) {
5304 GetOpenFile(write_io, fptr);
5305 if (fptr && 0 <= (fd = fptr->fd)) {
5306 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5307 if ((ret & FD_CLOEXEC) != flag) {
5308 ret = (ret & ~FD_CLOEXEC) | flag;
5309 ret = fcntl(fd, F_SETFD, ret);
5310 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5311 }
5312 }
5313
5314 }
5315
5316 GetOpenFile(io, fptr);
5317 if (fptr && 0 <= (fd = fptr->fd)) {
5318 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5319 if ((ret & FD_CLOEXEC) != flag) {
5320 ret = (ret & ~FD_CLOEXEC) | flag;
5321 ret = fcntl(fd, F_SETFD, ret);
5322 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5323 }
5324 }
5325 return Qnil;
5326}
5327#else
5328#define rb_io_set_close_on_exec rb_f_notimplement
5329#endif
5330
5331#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5332#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5333
5334static VALUE
5335finish_writeconv(rb_io_t *fptr, int noalloc)
5336{
5337 unsigned char *ds, *dp, *de;
5338 rb_econv_result_t res;
5339
5340 if (!fptr->wbuf.ptr) {
5341 unsigned char buf[1024];
5342
5343 res = econv_destination_buffer_full;
5344 while (res == econv_destination_buffer_full) {
5345 ds = dp = buf;
5346 de = buf + sizeof(buf);
5347 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5348 while (dp-ds) {
5349 size_t remaining = dp-ds;
5350 long result = rb_io_write_memory(fptr, ds, remaining);
5351
5352 if (result > 0) {
5353 ds += result;
5354 if ((size_t)result == remaining) break;
5355 }
5356 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5357 if (fptr->fd < 0)
5358 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5359 }
5360 else {
5361 return noalloc ? Qtrue : INT2NUM(errno);
5362 }
5363 }
5364 if (res == econv_invalid_byte_sequence ||
5365 res == econv_incomplete_input ||
5366 res == econv_undefined_conversion) {
5367 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5368 }
5369 }
5370
5371 return Qnil;
5372 }
5373
5374 res = econv_destination_buffer_full;
5375 while (res == econv_destination_buffer_full) {
5376 if (fptr->wbuf.len == fptr->wbuf.capa) {
5377 if (io_fflush(fptr) < 0) {
5378 return noalloc ? Qtrue : INT2NUM(errno);
5379 }
5380 }
5381
5382 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5383 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5384 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5385 fptr->wbuf.len += (int)(dp - ds);
5386 if (res == econv_invalid_byte_sequence ||
5387 res == econv_incomplete_input ||
5388 res == econv_undefined_conversion) {
5389 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5390 }
5391 }
5392 return Qnil;
5393}
5394
5395 struct finish_writeconv_arg {
5396 rb_io_t *fptr;
5397 int noalloc;
5398};
5399
5400static VALUE
5401finish_writeconv_sync(VALUE arg)
5402{
5403 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5404 return finish_writeconv(p->fptr, p->noalloc);
5405}
5406
5407static void*
5408nogvl_close(void *ptr)
5409{
5410 int *fd = ptr;
5411
5412 return (void*)(intptr_t)close(*fd);
5413}
5414
5415static int
5416maygvl_close(int fd, int keepgvl)
5417{
5418 if (keepgvl)
5419 return close(fd);
5420
5421 /*
5422 * close() may block for certain file types (NFS, SO_LINGER sockets,
5423 * inotify), so let other threads run.
5424 */
5425 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
5426}
5427
5428static void*
5429nogvl_fclose(void *ptr)
5430{
5431 FILE *file = ptr;
5432
5433 return (void*)(intptr_t)fclose(file);
5434}
5435
5436static int
5437maygvl_fclose(FILE *file, int keepgvl)
5438{
5439 if (keepgvl)
5440 return fclose(file);
5441
5442 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
5443}
5444
5445static void free_io_buffer(rb_io_buffer_t *buf);
5446static void clear_codeconv(rb_io_t *fptr);
5447
5448static void
5449fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5450 struct rb_io_close_wait_list *busy)
5451{
5452 VALUE error = Qnil;
5453 int fd = fptr->fd;
5454 FILE *stdio_file = fptr->stdio_file;
5455 int mode = fptr->mode;
5456
5457 if (fptr->writeconv) {
5458 if (!NIL_P(fptr->write_lock) && !noraise) {
5459 struct finish_writeconv_arg arg;
5460 arg.fptr = fptr;
5461 arg.noalloc = noraise;
5462 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5463 }
5464 else {
5465 error = finish_writeconv(fptr, noraise);
5466 }
5467 }
5468 if (fptr->wbuf.len) {
5469 if (noraise) {
5470 io_flush_buffer_sync(fptr);
5471 }
5472 else {
5473 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5474 error = INT2NUM(errno);
5475 }
5476 }
5477 }
5478
5479 int done = 0;
5480
5481 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5482 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5483 done = 1;
5484 }
5485
5486 fptr->fd = -1;
5487 fptr->stdio_file = 0;
5488 fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
5489
5490 // Ensure waiting_fd users do not hit EBADF.
5491 if (busy) {
5492 // Wait for them to exit before we call close().
5493 rb_notify_fd_close_wait(busy);
5494 }
5495
5496 // Disable for now.
5497 // if (!done && fd >= 0) {
5498 // VALUE scheduler = rb_fiber_scheduler_current();
5499 // if (scheduler != Qnil) {
5500 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5501 // if (!UNDEF_P(result)) done = 1;
5502 // }
5503 // }
5504
5505 if (!done && stdio_file) {
5506 // stdio_file is deallocated anyway even if fclose failed.
5507 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5508 if (!noraise) {
5509 error = INT2NUM(errno);
5510 }
5511 }
5512
5513 done = 1;
5514 }
5515
5516 if (!done && fd >= 0) {
5517 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5518 // We assumes it is closed.
5519
5520 keepgvl |= !(mode & FMODE_WRITABLE);
5521 keepgvl |= noraise;
5522 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5523 if (!noraise) {
5524 error = INT2NUM(errno);
5525 }
5526 }
5527
5528 done = 1;
5529 }
5530
5531 if (!NIL_P(error) && !noraise) {
5532 if (RB_INTEGER_TYPE_P(error))
5533 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5534 else
5535 rb_exc_raise(error);
5536 }
5537}
5538
5539static void
5540fptr_finalize(rb_io_t *fptr, int noraise)
5541{
5542 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5543 free_io_buffer(&fptr->rbuf);
5544 free_io_buffer(&fptr->wbuf);
5545 clear_codeconv(fptr);
5546}
5547
5548static void
5549rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5550{
5551 if (fptr->finalize) {
5552 (*fptr->finalize)(fptr, noraise);
5553 }
5554 else {
5555 fptr_finalize(fptr, noraise);
5556 }
5557}
5558
5559static void
5560free_io_buffer(rb_io_buffer_t *buf)
5561{
5562 if (buf->ptr) {
5563 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5564 buf->ptr = NULL;
5565 }
5566}
5567
5568static void
5569clear_readconv(rb_io_t *fptr)
5570{
5571 if (fptr->readconv) {
5572 rb_econv_close(fptr->readconv);
5573 fptr->readconv = NULL;
5574 }
5575 free_io_buffer(&fptr->cbuf);
5576}
5577
5578static void
5579clear_writeconv(rb_io_t *fptr)
5580{
5581 if (fptr->writeconv) {
5582 rb_econv_close(fptr->writeconv);
5583 fptr->writeconv = NULL;
5584 }
5585 fptr->writeconv_initialized = 0;
5586}
5587
5588static void
5589clear_codeconv(rb_io_t *fptr)
5590{
5591 clear_readconv(fptr);
5592 clear_writeconv(fptr);
5593}
5594
5595static void
5596rb_io_fptr_cleanup_all(rb_io_t *fptr)
5597{
5598 fptr->pathv = Qnil;
5599 if (0 <= fptr->fd)
5600 rb_io_fptr_cleanup(fptr, TRUE);
5601 fptr->write_lock = Qnil;
5602 free_io_buffer(&fptr->rbuf);
5603 free_io_buffer(&fptr->wbuf);
5604 clear_codeconv(fptr);
5605}
5606
5607void
5608rb_io_fptr_finalize_internal(void *ptr)
5609{
5610 if (!ptr) return;
5611 rb_io_fptr_cleanup_all(ptr);
5612 free(ptr);
5613}
5614
5615#undef rb_io_fptr_finalize
5616int
5617rb_io_fptr_finalize(rb_io_t *fptr)
5618{
5619 if (!fptr) {
5620 return 0;
5621 }
5622 else {
5623 rb_io_fptr_finalize_internal(fptr);
5624 return 1;
5625 }
5626}
5627#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5628
5629RUBY_FUNC_EXPORTED size_t
5630rb_io_memsize(const rb_io_t *fptr)
5631{
5632 size_t size = sizeof(rb_io_t);
5633 size += fptr->rbuf.capa;
5634 size += fptr->wbuf.capa;
5635 size += fptr->cbuf.capa;
5636 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5637 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5638 return size;
5639}
5640
5641#ifdef _WIN32
5642/* keep GVL while closing to prevent crash on Windows */
5643# define KEEPGVL TRUE
5644#else
5645# define KEEPGVL FALSE
5646#endif
5647
5648static rb_io_t *
5649io_close_fptr(VALUE io)
5650{
5651 rb_io_t *fptr;
5652 VALUE write_io;
5653 rb_io_t *write_fptr;
5654 struct rb_io_close_wait_list busy;
5655
5656 write_io = GetWriteIO(io);
5657 if (io != write_io) {
5658 write_fptr = RFILE(write_io)->fptr;
5659 if (write_fptr && 0 <= write_fptr->fd) {
5660 rb_io_fptr_cleanup(write_fptr, TRUE);
5661 }
5662 }
5663
5664 fptr = RFILE(io)->fptr;
5665 if (!fptr) return 0;
5666 if (fptr->fd < 0) return 0;
5667
5668 if (rb_notify_fd_close(fptr->fd, &busy)) {
5669 /* calls close(fptr->fd): */
5670 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5671 }
5672 rb_io_fptr_cleanup(fptr, FALSE);
5673 return fptr;
5674}
5675
5676static void
5677fptr_waitpid(rb_io_t *fptr, int nohang)
5678{
5679 int status;
5680 if (fptr->pid) {
5681 rb_last_status_clear();
5682 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5683 fptr->pid = 0;
5684 }
5685}
5686
5687 VALUE
5688rb_io_close(VALUE io)
5689{
5690 rb_io_t *fptr = io_close_fptr(io);
5691 if (fptr) fptr_waitpid(fptr, 0);
5692 return Qnil;
5693}
5694
5695/*
5696 * call-seq:
5697 * close -> nil
5698 *
5699 * Closes the stream for both reading and writing
5700 * if open for either or both; returns +nil+.
5701 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5702 *
5703 * If the stream is open for writing, flushes any buffered writes
5704 * to the operating system before closing.
5705 *
5706 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5707 * (child exit status).
5708 *
5709 * Example:
5710 *
5711 * IO.popen('ruby', 'r+') do |pipe|
5712 * puts pipe.closed?
5713 * pipe.close
5714 * puts $?
5715 * puts pipe.closed?
5716 * end
5717 *
5718 * Output:
5719 *
5720 * false
5721 * pid 13760 exit 0
5722 * true
5723 *
5724 * Related: IO#close_read, IO#close_write, IO#closed?.
5725 */
5726
5727static VALUE
5728rb_io_close_m(VALUE io)
5729{
5730 rb_io_t *fptr = rb_io_get_fptr(io);
5731 if (fptr->fd < 0) {
5732 return Qnil;
5733 }
5734 rb_io_close(io);
5735 return Qnil;
5736}
5737
5738static VALUE
5739io_call_close(VALUE io)
5740{
5741 rb_check_funcall(io, rb_intern("close"), 0, 0);
5742 return io;
5743}
5744
5745static VALUE
5746ignore_closed_stream(VALUE io, VALUE exc)
5747{
5748 enum {mesg_len = sizeof(closed_stream)-1};
5749 VALUE mesg = rb_attr_get(exc, idMesg);
5750 if (!RB_TYPE_P(mesg, T_STRING) ||
5751 RSTRING_LEN(mesg) != mesg_len ||
5752 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5753 rb_exc_raise(exc);
5754 }
5755 return io;
5756}
5757
5758static VALUE
5759io_close(VALUE io)
5760{
5761 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5762 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5763 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5764 rb_eIOError, (VALUE)0);
5765 return io;
5766}
5767
5768/*
5769 * call-seq:
5770 * closed? -> true or false
5771 *
5772 * Returns +true+ if the stream is closed for both reading and writing,
5773 * +false+ otherwise.
5774 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5775 *
5776 * IO.popen('ruby', 'r+') do |pipe|
5777 * puts pipe.closed?
5778 * pipe.close_read
5779 * puts pipe.closed?
5780 * pipe.close_write
5781 * puts pipe.closed?
5782 * end
5783 *
5784 * Output:
5785 *
5786 * false
5787 * false
5788 * true
5789 *
5790 * Related: IO#close_read, IO#close_write, IO#close.
5791 */
5792 VALUE
5793rb_io_closed_p(VALUE io)
5794{
5795 rb_io_t *fptr;
5796 VALUE write_io;
5797 rb_io_t *write_fptr;
5798
5799 write_io = GetWriteIO(io);
5800 if (io != write_io) {
5801 write_fptr = RFILE(write_io)->fptr;
5802 if (write_fptr && 0 <= write_fptr->fd) {
5803 return Qfalse;
5804 }
5805 }
5806
5807 fptr = rb_io_get_fptr(io);
5808 return RBOOL(0 > fptr->fd);
5809}
5810
5811/*
5812 * call-seq:
5813 * close_read -> nil
5814 *
5815 * Closes the stream for reading if open for reading;
5816 * returns +nil+.
5817 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5818 *
5819 * If the stream was opened by IO.popen and is also closed for writing,
5820 * sets global variable <tt>$?</tt> (child exit status).
5821 *
5822 * Example:
5823 *
5824 * IO.popen('ruby', 'r+') do |pipe|
5825 * puts pipe.closed?
5826 * pipe.close_write
5827 * puts pipe.closed?
5828 * pipe.close_read
5829 * puts $?
5830 * puts pipe.closed?
5831 * end
5832 *
5833 * Output:
5834 *
5835 * false
5836 * false
5837 * pid 14748 exit 0
5838 * true
5839 *
5840 * Related: IO#close, IO#close_write, IO#closed?.
5841 */
5842
5843static VALUE
5844rb_io_close_read(VALUE io)
5845{
5846 rb_io_t *fptr;
5847 VALUE write_io;
5848
5849 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5850 if (fptr->fd < 0) return Qnil;
5851 if (is_socket(fptr->fd, fptr->pathv)) {
5852#ifndef SHUT_RD
5853# define SHUT_RD 0
5854#endif
5855 if (shutdown(fptr->fd, SHUT_RD) < 0)
5856 rb_sys_fail_path(fptr->pathv);
5857 fptr->mode &= ~FMODE_READABLE;
5858 if (!(fptr->mode & FMODE_WRITABLE))
5859 return rb_io_close(io);
5860 return Qnil;
5861 }
5862
5863 write_io = GetWriteIO(io);
5864 if (io != write_io) {
5865 rb_io_t *wfptr;
5866 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5867 wfptr->pid = fptr->pid;
5868 fptr->pid = 0;
5869 RFILE(io)->fptr = wfptr;
5870 /* bind to write_io temporarily to get rid of memory/fd leak */
5871 fptr->tied_io_for_writing = 0;
5872 RFILE(write_io)->fptr = fptr;
5873 rb_io_fptr_cleanup(fptr, FALSE);
5874 /* should not finalize fptr because another thread may be reading it */
5875 return Qnil;
5876 }
5877
5878 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5879 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5880 }
5881 return rb_io_close(io);
5882}
5883
5884/*
5885 * call-seq:
5886 * close_write -> nil
5887 *
5888 * Closes the stream for writing if open for writing;
5889 * returns +nil+.
5890 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5891 *
5892 * Flushes any buffered writes to the operating system before closing.
5893 *
5894 * If the stream was opened by IO.popen and is also closed for reading,
5895 * sets global variable <tt>$?</tt> (child exit status).
5896 *
5897 * IO.popen('ruby', 'r+') do |pipe|
5898 * puts pipe.closed?
5899 * pipe.close_read
5900 * puts pipe.closed?
5901 * pipe.close_write
5902 * puts $?
5903 * puts pipe.closed?
5904 * end
5905 *
5906 * Output:
5907 *
5908 * false
5909 * false
5910 * pid 15044 exit 0
5911 * true
5912 *
5913 * Related: IO#close, IO#close_read, IO#closed?.
5914 */
5915
5916static VALUE
5917rb_io_close_write(VALUE io)
5918{
5919 rb_io_t *fptr;
5920 VALUE write_io;
5921
5922 write_io = GetWriteIO(io);
5923 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5924 if (fptr->fd < 0) return Qnil;
5925 if (is_socket(fptr->fd, fptr->pathv)) {
5926#ifndef SHUT_WR
5927# define SHUT_WR 1
5928#endif
5929 if (shutdown(fptr->fd, SHUT_WR) < 0)
5930 rb_sys_fail_path(fptr->pathv);
5931 fptr->mode &= ~FMODE_WRITABLE;
5932 if (!(fptr->mode & FMODE_READABLE))
5933 return rb_io_close(write_io);
5934 return Qnil;
5935 }
5936
5937 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
5938 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
5939 }
5940
5941 if (io != write_io) {
5942 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5943 fptr->tied_io_for_writing = 0;
5944 }
5945 rb_io_close(write_io);
5946 return Qnil;
5947}
5948
5949/*
5950 * call-seq:
5951 * sysseek(offset, whence = IO::SEEK_SET) -> integer
5952 *
5953 * Behaves like IO#seek, except that it:
5954 *
5955 * - Uses low-level system functions.
5956 * - Returns the new position.
5957 *
5958 */
5959
5960static VALUE
5961rb_io_sysseek(int argc, VALUE *argv, VALUE io)
5962{
5963 VALUE offset, ptrname;
5964 int whence = SEEK_SET;
5965 rb_io_t *fptr;
5966 rb_off_t pos;
5967
5968 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
5969 whence = interpret_seek_whence(ptrname);
5970 }
5971 pos = NUM2OFFT(offset);
5972 GetOpenFile(io, fptr);
5973 if ((fptr->mode & FMODE_READABLE) &&
5974 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5975 rb_raise(rb_eIOError, "sysseek for buffered IO");
5976 }
5977 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
5978 rb_warn("sysseek for buffered IO");
5979 }
5980 errno = 0;
5981 pos = lseek(fptr->fd, pos, whence);
5982 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
5983
5984 return OFFT2NUM(pos);
5985}
5986
5987/*
5988 * call-seq:
5989 * syswrite(object) -> integer
5990 *
5991 * Writes the given +object+ to self, which must be opened for writing (see Modes);
5992 * returns the number bytes written.
5993 * If +object+ is not a string is converted via method to_s:
5994 *
5995 * f = File.new('t.tmp', 'w')
5996 * f.syswrite('foo') # => 3
5997 * f.syswrite(30) # => 2
5998 * f.syswrite(:foo) # => 3
5999 * f.close
6000 *
6001 * This methods should not be used with other stream-writer methods.
6002 *
6003 */
6004
6005static VALUE
6006rb_io_syswrite(VALUE io, VALUE str)
6007{
6008 VALUE tmp;
6009 rb_io_t *fptr;
6010 long n, len;
6011 const char *ptr;
6012
6013 if (!RB_TYPE_P(str, T_STRING))
6014 str = rb_obj_as_string(str);
6015
6016 io = GetWriteIO(io);
6017 GetOpenFile(io, fptr);
6018 rb_io_check_writable(fptr);
6019
6020 if (fptr->wbuf.len) {
6021 rb_warn("syswrite for buffered IO");
6022 }
6023
6024 tmp = rb_str_tmp_frozen_acquire(str);
6025 RSTRING_GETMEM(tmp, ptr, len);
6026 n = rb_io_write_memory(fptr, ptr, len);
6027 if (n < 0) rb_sys_fail_path(fptr->pathv);
6028 rb_str_tmp_frozen_release(str, tmp);
6029
6030 return LONG2FIX(n);
6031}
6032
6033/*
6034 * call-seq:
6035 * sysread(maxlen) -> string
6036 * sysread(maxlen, out_string) -> string
6037 *
6038 * Behaves like IO#readpartial, except that it uses low-level system functions.
6039 *
6040 * This method should not be used with other stream-reader methods.
6041 *
6042 */
6043
6044static VALUE
6045rb_io_sysread(int argc, VALUE *argv, VALUE io)
6046{
6047 VALUE len, str;
6048 rb_io_t *fptr;
6049 long n, ilen;
6050 struct io_internal_read_struct iis;
6051 int shrinkable;
6052
6053 rb_scan_args(argc, argv, "11", &len, &str);
6054 ilen = NUM2LONG(len);
6055
6056 shrinkable = io_setstrbuf(&str, ilen);
6057 if (ilen == 0) return str;
6058
6059 GetOpenFile(io, fptr);
6060 rb_io_check_byte_readable(fptr);
6061
6062 if (READ_DATA_BUFFERED(fptr)) {
6063 rb_raise(rb_eIOError, "sysread for buffered IO");
6064 }
6065
6066 rb_io_check_closed(fptr);
6067
6068 io_setstrbuf(&str, ilen);
6069 iis.th = rb_thread_current();
6070 iis.fptr = fptr;
6071 iis.nonblock = 0;
6072 iis.fd = fptr->fd;
6073 iis.buf = RSTRING_PTR(str);
6074 iis.capa = ilen;
6075 iis.timeout = NULL;
6076 n = io_read_memory_locktmp(str, &iis);
6077
6078 if (n < 0) {
6079 rb_sys_fail_path(fptr->pathv);
6080 }
6081
6082 io_set_read_length(str, n, shrinkable);
6083
6084 if (n == 0 && ilen > 0) {
6085 rb_eof_error();
6086 }
6087
6088 return str;
6089}
6090
6091 struct prdwr_internal_arg {
6092 VALUE io;
6093 int fd;
6094 void *buf;
6095 size_t count;
6096 rb_off_t offset;
6097};
6098
6099static VALUE
6100internal_pread_func(void *_arg)
6101{
6102 struct prdwr_internal_arg *arg = _arg;
6103
6104 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6105}
6106
6107static VALUE
6108pread_internal_call(VALUE _arg)
6109{
6110 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6111
6112 VALUE scheduler = rb_fiber_scheduler_current();
6113 if (scheduler != Qnil) {
6114 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io, arg->offset, arg->buf, arg->count, 0);
6115
6116 if (!UNDEF_P(result)) {
6117 return rb_fiber_scheduler_io_result_apply(result);
6118 }
6119 }
6120
6121 return rb_thread_io_blocking_call(internal_pread_func, arg, arg->fd, RB_WAITFD_IN);
6122}
6123
6124/*
6125 * call-seq:
6126 * pread(maxlen, offset) -> string
6127 * pread(maxlen, offset, out_string) -> string
6128 *
6129 * Behaves like IO#readpartial, except that it:
6130 *
6131 * - Reads at the given +offset+ (in bytes).
6132 * - Disregards, and does not modify, the stream's position
6133 * (see {Position}[rdoc-ref:IO@Position]).
6134 * - Bypasses any user space buffering in the stream.
6135 *
6136 * Because this method does not disturb the stream's state
6137 * (its position, in particular), +pread+ allows multiple threads and processes
6138 * to use the same \IO object for reading at various offsets.
6139 *
6140 * f = File.open('t.txt')
6141 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6142 * f.pos # => 52
6143 * # Read 12 bytes at offset 0.
6144 * f.pread(12, 0) # => "First line\n"
6145 * # Read 9 bytes at offset 8.
6146 * f.pread(9, 8) # => "ne\nSecon"
6147 * f.close
6148 *
6149 * Not available on some platforms.
6150 *
6151 */
6152static VALUE
6153rb_io_pread(int argc, VALUE *argv, VALUE io)
6154{
6155 VALUE len, offset, str;
6156 rb_io_t *fptr;
6157 ssize_t n;
6158 struct prdwr_internal_arg arg = {.io = io};
6159 int shrinkable;
6160
6161 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6162 arg.count = NUM2SIZET(len);
6163 arg.offset = NUM2OFFT(offset);
6164
6165 shrinkable = io_setstrbuf(&str, (long)arg.count);
6166 if (arg.count == 0) return str;
6167 arg.buf = RSTRING_PTR(str);
6168
6169 GetOpenFile(io, fptr);
6170 rb_io_check_byte_readable(fptr);
6171
6172 arg.fd = fptr->fd;
6173 rb_io_check_closed(fptr);
6174
6175 rb_str_locktmp(str);
6176 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6177
6178 if (n < 0) {
6179 rb_sys_fail_path(fptr->pathv);
6180 }
6181 io_set_read_length(str, n, shrinkable);
6182 if (n == 0 && arg.count > 0) {
6183 rb_eof_error();
6184 }
6185
6186 return str;
6187}
6188
6189static VALUE
6190internal_pwrite_func(void *_arg)
6191{
6192 struct prdwr_internal_arg *arg = _arg;
6193
6194 VALUE scheduler = rb_fiber_scheduler_current();
6195 if (scheduler != Qnil) {
6196 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io, arg->offset, arg->buf, arg->count, 0);
6197
6198 if (!UNDEF_P(result)) {
6199 return rb_fiber_scheduler_io_result_apply(result);
6200 }
6201 }
6202
6203
6204 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6205}
6206
6207/*
6208 * call-seq:
6209 * pwrite(object, offset) -> integer
6210 *
6211 * Behaves like IO#write, except that it:
6212 *
6213 * - Writes at the given +offset+ (in bytes).
6214 * - Disregards, and does not modify, the stream's position
6215 * (see {Position}[rdoc-ref:IO@Position]).
6216 * - Bypasses any user space buffering in the stream.
6217 *
6218 * Because this method does not disturb the stream's state
6219 * (its position, in particular), +pwrite+ allows multiple threads and processes
6220 * to use the same \IO object for writing at various offsets.
6221 *
6222 * f = File.open('t.tmp', 'w+')
6223 * # Write 6 bytes at offset 3.
6224 * f.pwrite('ABCDEF', 3) # => 6
6225 * f.rewind
6226 * f.read # => "\u0000\u0000\u0000ABCDEF"
6227 * f.close
6228 *
6229 * Not available on some platforms.
6230 *
6231 */
6232static VALUE
6233rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6234{
6235 rb_io_t *fptr;
6236 ssize_t n;
6237 struct prdwr_internal_arg arg = {.io = io};
6238 VALUE tmp;
6239
6240 if (!RB_TYPE_P(str, T_STRING))
6241 str = rb_obj_as_string(str);
6242
6243 arg.offset = NUM2OFFT(offset);
6244
6245 io = GetWriteIO(io);
6246 GetOpenFile(io, fptr);
6247 rb_io_check_writable(fptr);
6248 arg.fd = fptr->fd;
6249
6250 tmp = rb_str_tmp_frozen_acquire(str);
6251 arg.buf = RSTRING_PTR(tmp);
6252 arg.count = (size_t)RSTRING_LEN(tmp);
6253
6254 n = (ssize_t)rb_thread_io_blocking_call(internal_pwrite_func, &arg, fptr->fd, RB_WAITFD_OUT);
6255 if (n < 0) rb_sys_fail_path(fptr->pathv);
6256 rb_str_tmp_frozen_release(str, tmp);
6257
6258 return SSIZET2NUM(n);
6259}
6260
6261 VALUE
6262rb_io_binmode(VALUE io)
6263{
6264 rb_io_t *fptr;
6265
6266 GetOpenFile(io, fptr);
6267 if (fptr->readconv)
6268 rb_econv_binmode(fptr->readconv);
6269 if (fptr->writeconv)
6270 rb_econv_binmode(fptr->writeconv);
6271 fptr->mode |= FMODE_BINMODE;
6272 fptr->mode &= ~FMODE_TEXTMODE;
6273 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6274#ifdef O_BINARY
6275 if (!fptr->readconv) {
6276 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6277 }
6278 else {
6279 setmode(fptr->fd, O_BINARY);
6280 }
6281#endif
6282 return io;
6283}
6284
6285static void
6286io_ascii8bit_binmode(rb_io_t *fptr)
6287{
6288 if (fptr->readconv) {
6289 rb_econv_close(fptr->readconv);
6290 fptr->readconv = NULL;
6291 }
6292 if (fptr->writeconv) {
6293 rb_econv_close(fptr->writeconv);
6294 fptr->writeconv = NULL;
6295 }
6296 fptr->mode |= FMODE_BINMODE;
6297 fptr->mode &= ~FMODE_TEXTMODE;
6298 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6299
6300 fptr->encs.enc = rb_ascii8bit_encoding();
6301 fptr->encs.enc2 = NULL;
6302 fptr->encs.ecflags = 0;
6303 fptr->encs.ecopts = Qnil;
6304 clear_codeconv(fptr);
6305}
6306
6307 VALUE
6308rb_io_ascii8bit_binmode(VALUE io)
6309{
6310 rb_io_t *fptr;
6311
6312 GetOpenFile(io, fptr);
6313 io_ascii8bit_binmode(fptr);
6314
6315 return io;
6316}
6317
6318/*
6319 * call-seq:
6320 * binmode -> self
6321 *
6322 * Sets the stream's data mode as binary
6323 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6324 *
6325 * A stream's data mode may not be changed from binary to text.
6326 *
6327 */
6328
6329static VALUE
6330rb_io_binmode_m(VALUE io)
6331{
6332 VALUE write_io;
6333
6334 rb_io_ascii8bit_binmode(io);
6335
6336 write_io = GetWriteIO(io);
6337 if (write_io != io)
6338 rb_io_ascii8bit_binmode(write_io);
6339 return io;
6340}
6341
6342/*
6343 * call-seq:
6344 * binmode? -> true or false
6345 *
6346 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6347 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6348 *
6349 */
6350static VALUE
6351rb_io_binmode_p(VALUE io)
6352{
6353 rb_io_t *fptr;
6354 GetOpenFile(io, fptr);
6355 return RBOOL(fptr->mode & FMODE_BINMODE);
6356}
6357
6358static const char*
6359rb_io_fmode_modestr(int fmode)
6360{
6361 if (fmode & FMODE_APPEND) {
6362 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6363 return MODE_BTMODE("a+", "ab+", "at+");
6364 }
6365 return MODE_BTMODE("a", "ab", "at");
6366 }
6367 switch (fmode & FMODE_READWRITE) {
6368 default:
6369 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6370 case FMODE_READABLE:
6371 return MODE_BTMODE("r", "rb", "rt");
6372 case FMODE_WRITABLE:
6373 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6374 case FMODE_READWRITE:
6375 if (fmode & FMODE_CREATE) {
6376 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6377 }
6378 return MODE_BTMODE("r+", "rb+", "rt+");
6379 }
6380}
6381
6382static const char bom_prefix[] = "bom|";
6383static const char utf_prefix[] = "utf-";
6384enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6385enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6386
6387static int
6388io_encname_bom_p(const char *name, long len)
6389{
6390 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6391}
6392
6393int
6394rb_io_modestr_fmode(const char *modestr)
6395{
6396 int fmode = 0;
6397 const char *m = modestr, *p = NULL;
6398
6399 switch (*m++) {
6400 case 'r':
6401 fmode |= FMODE_READABLE;
6402 break;
6403 case 'w':
6404 fmode |= FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE;
6405 break;
6406 case 'a':
6407 fmode |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
6408 break;
6409 default:
6410 goto error;
6411 }
6412
6413 while (*m) {
6414 switch (*m++) {
6415 case 'b':
6416 fmode |= FMODE_BINMODE;
6417 break;
6418 case 't':
6419 fmode |= FMODE_TEXTMODE;
6420 break;
6421 case '+':
6422 fmode |= FMODE_READWRITE;
6423 break;
6424 case 'x':
6425 if (modestr[0] != 'w')
6426 goto error;
6427 fmode |= FMODE_EXCL;
6428 break;
6429 default:
6430 goto error;
6431 case ':':
6432 p = strchr(m, ':');
6433 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6434 fmode |= FMODE_SETENC_BY_BOM;
6435 goto finished;
6436 }
6437 }
6438
6439 finished:
6440 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6441 goto error;
6442
6443 return fmode;
6444
6445 error:
6446 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6447 UNREACHABLE_RETURN(Qundef);
6448}
6449
6450int
6451rb_io_oflags_fmode(int oflags)
6452{
6453 int fmode = 0;
6454
6455 switch (oflags & O_ACCMODE) {
6456 case O_RDONLY:
6457 fmode = FMODE_READABLE;
6458 break;
6459 case O_WRONLY:
6460 fmode = FMODE_WRITABLE;
6461 break;
6462 case O_RDWR:
6463 fmode = FMODE_READWRITE;
6464 break;
6465 }
6466
6467 if (oflags & O_APPEND) {
6468 fmode |= FMODE_APPEND;
6469 }
6470 if (oflags & O_TRUNC) {
6471 fmode |= FMODE_TRUNC;
6472 }
6473 if (oflags & O_CREAT) {
6474 fmode |= FMODE_CREATE;
6475 }
6476 if (oflags & O_EXCL) {
6477 fmode |= FMODE_EXCL;
6478 }
6479#ifdef O_BINARY
6480 if (oflags & O_BINARY) {
6481 fmode |= FMODE_BINMODE;
6482 }
6483#endif
6484
6485 return fmode;
6486}
6487
6488static int
6489rb_io_fmode_oflags(int fmode)
6490{
6491 int oflags = 0;
6492
6493 switch (fmode & FMODE_READWRITE) {
6494 case FMODE_READABLE:
6495 oflags |= O_RDONLY;
6496 break;
6497 case FMODE_WRITABLE:
6498 oflags |= O_WRONLY;
6499 break;
6500 case FMODE_READWRITE:
6501 oflags |= O_RDWR;
6502 break;
6503 }
6504
6505 if (fmode & FMODE_APPEND) {
6506 oflags |= O_APPEND;
6507 }
6508 if (fmode & FMODE_TRUNC) {
6509 oflags |= O_TRUNC;
6510 }
6511 if (fmode & FMODE_CREATE) {
6512 oflags |= O_CREAT;
6513 }
6514 if (fmode & FMODE_EXCL) {
6515 oflags |= O_EXCL;
6516 }
6517#ifdef O_BINARY
6518 if (fmode & FMODE_BINMODE) {
6519 oflags |= O_BINARY;
6520 }
6521#endif
6522
6523 return oflags;
6524}
6525
6526int
6527rb_io_modestr_oflags(const char *modestr)
6528{
6529 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6530}
6531
6532static const char*
6533rb_io_oflags_modestr(int oflags)
6534{
6535#ifdef O_BINARY
6536# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6537#else
6538# define MODE_BINARY(a,b) (a)
6539#endif
6540 int accmode;
6541 if (oflags & O_EXCL) {
6542 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6543 }
6544 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6545 if (oflags & O_APPEND) {
6546 if (accmode == O_WRONLY) {
6547 return MODE_BINARY("a", "ab");
6548 }
6549 if (accmode == O_RDWR) {
6550 return MODE_BINARY("a+", "ab+");
6551 }
6552 }
6553 switch (accmode) {
6554 default:
6555 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6556 case O_RDONLY:
6557 return MODE_BINARY("r", "rb");
6558 case O_WRONLY:
6559 return MODE_BINARY("w", "wb");
6560 case O_RDWR:
6561 if (oflags & O_TRUNC) {
6562 return MODE_BINARY("w+", "wb+");
6563 }
6564 return MODE_BINARY("r+", "rb+");
6565 }
6566}
6567
6568/*
6569 * Convert external/internal encodings to enc/enc2
6570 * NULL => use default encoding
6571 * Qnil => no encoding specified (internal only)
6572 */
6573static void
6574rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6575{
6576 int default_ext = 0;
6577
6578 if (ext == NULL) {
6579 ext = rb_default_external_encoding();
6580 default_ext = 1;
6581 }
6582 if (rb_is_ascii8bit_enc(ext)) {
6583 /* If external is ASCII-8BIT, no transcoding */
6584 intern = NULL;
6585 }
6586 else if (intern == NULL) {
6587 intern = rb_default_internal_encoding();
6588 }
6589 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6590 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6591 /* No internal encoding => use external + no transcoding */
6592 *enc = (default_ext && intern != ext) ? NULL : ext;
6593 *enc2 = NULL;
6594 }
6595 else {
6596 *enc = intern;
6597 *enc2 = ext;
6598 }
6599}
6600
6601static void
6602unsupported_encoding(const char *name, rb_encoding *enc)
6603{
6604 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6605}
6606
6607static void
6608parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6609 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6610{
6611 const char *p;
6612 char encname[ENCODING_MAXNAMELEN+1];
6613 int idx, idx2;
6614 int fmode = fmode_p ? *fmode_p : 0;
6615 rb_encoding *ext_enc, *int_enc;
6616 long len;
6617
6618 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6619
6620 p = strrchr(estr, ':');
6621 len = p ? (p++ - estr) : (long)strlen(estr);
6622 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6623 estr += bom_prefix_len;
6624 len -= bom_prefix_len;
6625 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6626 fmode |= FMODE_SETENC_BY_BOM;
6627 }
6628 else {
6629 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6630 fmode &= ~FMODE_SETENC_BY_BOM;
6631 }
6632 }
6633 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6634 idx = -1;
6635 }
6636 else {
6637 if (p) {
6638 memcpy(encname, estr, len);
6639 encname[len] = '\0';
6640 estr = encname;
6641 }
6642 idx = rb_enc_find_index(estr);
6643 }
6644 if (fmode_p) *fmode_p = fmode;
6645
6646 if (idx >= 0)
6647 ext_enc = rb_enc_from_index(idx);
6648 else {
6649 if (idx != -2)
6650 unsupported_encoding(estr, estr_enc);
6651 ext_enc = NULL;
6652 }
6653
6654 int_enc = NULL;
6655 if (p) {
6656 if (*p == '-' && *(p+1) == '\0') {
6657 /* Special case - "-" => no transcoding */
6658 int_enc = (rb_encoding *)Qnil;
6659 }
6660 else {
6661 idx2 = rb_enc_find_index(p);
6662 if (idx2 < 0)
6663 unsupported_encoding(p, estr_enc);
6664 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6665 int_enc = (rb_encoding *)Qnil;
6666 }
6667 else
6668 int_enc = rb_enc_from_index(idx2);
6669 }
6670 }
6671
6672 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6673}
6674
6675int
6676rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6677{
6678 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6679 int extracted = 0;
6680 rb_encoding *extencoding = NULL;
6681 rb_encoding *intencoding = NULL;
6682
6683 if (!NIL_P(opt)) {
6684 VALUE v;
6685 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6686 if (v != Qnil) encoding = v;
6687 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6688 if (v != Qnil) extenc = v;
6689 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6690 if (!UNDEF_P(v)) intenc = v;
6691 }
6692 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6693 if (!NIL_P(ruby_verbose)) {
6694 int idx = rb_to_encoding_index(encoding);
6695 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6696 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6697 encoding, UNDEF_P(extenc) ? "internal" : "external");
6698 }
6699 encoding = Qnil;
6700 }
6701 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6702 extencoding = rb_to_encoding(extenc);
6703 }
6704 if (!UNDEF_P(intenc)) {
6705 if (NIL_P(intenc)) {
6706 /* internal_encoding: nil => no transcoding */
6707 intencoding = (rb_encoding *)Qnil;
6708 }
6709 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6710 char *p = StringValueCStr(tmp);
6711
6712 if (*p == '-' && *(p+1) == '\0') {
6713 /* Special case - "-" => no transcoding */
6714 intencoding = (rb_encoding *)Qnil;
6715 }
6716 else {
6717 intencoding = rb_to_encoding(intenc);
6718 }
6719 }
6720 else {
6721 intencoding = rb_to_encoding(intenc);
6722 }
6723 if (extencoding == intencoding) {
6724 intencoding = (rb_encoding *)Qnil;
6725 }
6726 }
6727 if (!NIL_P(encoding)) {
6728 extracted = 1;
6729 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6730 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6731 enc_p, enc2_p, fmode_p);
6732 }
6733 else {
6734 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6735 }
6736 }
6737 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6738 extracted = 1;
6739 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6740 }
6741 return extracted;
6742}
6743
6744static void
6745validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6746{
6747 int fmode = *fmode_p;
6748
6749 if ((fmode & FMODE_READABLE) &&
6750 !enc2 &&
6751 !(fmode & FMODE_BINMODE) &&
6752 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6753 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6754
6755 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6756 rb_raise(rb_eArgError, "newline decorator with binary mode");
6757 }
6758 if (!(fmode & FMODE_BINMODE) &&
6759 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6760 fmode |= FMODE_TEXTMODE;
6761 *fmode_p = fmode;
6762 }
6763#if !DEFAULT_TEXTMODE
6764 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6765 fmode &= ~FMODE_TEXTMODE;
6766 *fmode_p = fmode;
6767 }
6768#endif
6769}
6770
6771static void
6772extract_binmode(VALUE opthash, int *fmode)
6773{
6774 if (!NIL_P(opthash)) {
6775 VALUE v;
6776 v = rb_hash_aref(opthash, sym_textmode);
6777 if (!NIL_P(v)) {
6778 if (*fmode & FMODE_TEXTMODE)
6779 rb_raise(rb_eArgError, "textmode specified twice");
6780 if (*fmode & FMODE_BINMODE)
6781 rb_raise(rb_eArgError, "both textmode and binmode specified");
6782 if (RTEST(v))
6783 *fmode |= FMODE_TEXTMODE;
6784 }
6785 v = rb_hash_aref(opthash, sym_binmode);
6786 if (!NIL_P(v)) {
6787 if (*fmode & FMODE_BINMODE)
6788 rb_raise(rb_eArgError, "binmode specified twice");
6789 if (*fmode & FMODE_TEXTMODE)
6790 rb_raise(rb_eArgError, "both textmode and binmode specified");
6791 if (RTEST(v))
6792 *fmode |= FMODE_BINMODE;
6793 }
6794
6795 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6796 rb_raise(rb_eArgError, "both textmode and binmode specified");
6797 }
6798}
6799
6800void
6801rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6802 int *oflags_p, int *fmode_p, struct rb_io_encoding *convconfig_p)
6803{
6804 VALUE vmode;
6805 int oflags, fmode;
6806 rb_encoding *enc, *enc2;
6807 int ecflags;
6808 VALUE ecopts;
6809 int has_enc = 0, has_vmode = 0;
6810 VALUE intmode;
6811
6812 vmode = *vmode_p;
6813
6814 /* Set to defaults */
6815 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6816
6817 vmode_handle:
6818 if (NIL_P(vmode)) {
6819 fmode = FMODE_READABLE;
6820 oflags = O_RDONLY;
6821 }
6822 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6823 vmode = intmode;
6824 oflags = NUM2INT(intmode);
6825 fmode = rb_io_oflags_fmode(oflags);
6826 }
6827 else {
6828 const char *p;
6829
6830 SafeStringValue(vmode);
6831 p = StringValueCStr(vmode);
6832 fmode = rb_io_modestr_fmode(p);
6833 oflags = rb_io_fmode_oflags(fmode);
6834 p = strchr(p, ':');
6835 if (p) {
6836 has_enc = 1;
6837 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6838 }
6839 else {
6840 rb_encoding *e;
6841
6842 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6843 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6844 }
6845 }
6846
6847 if (NIL_P(opthash)) {
6848 ecflags = (fmode & FMODE_READABLE) ?
6849 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6850 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6851#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6852 ecflags |= (fmode & FMODE_WRITABLE) ?
6853 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6854 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6855#endif
6856 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6857 ecopts = Qnil;
6858 if (fmode & FMODE_BINMODE) {
6859#ifdef O_BINARY
6860 oflags |= O_BINARY;
6861#endif
6862 if (!has_enc)
6863 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6864 }
6865#if DEFAULT_TEXTMODE
6866 else if (NIL_P(vmode)) {
6867 fmode |= DEFAULT_TEXTMODE;
6868 }
6869#endif
6870 }
6871 else {
6872 VALUE v;
6873 if (!has_vmode) {
6874 v = rb_hash_aref(opthash, sym_mode);
6875 if (!NIL_P(v)) {
6876 if (!NIL_P(vmode)) {
6877 rb_raise(rb_eArgError, "mode specified twice");
6878 }
6879 has_vmode = 1;
6880 vmode = v;
6881 goto vmode_handle;
6882 }
6883 }
6884 v = rb_hash_aref(opthash, sym_flags);
6885 if (!NIL_P(v)) {
6886 v = rb_to_int(v);
6887 oflags |= NUM2INT(v);
6888 vmode = INT2NUM(oflags);
6889 fmode = rb_io_oflags_fmode(oflags);
6890 }
6891 extract_binmode(opthash, &fmode);
6892 if (fmode & FMODE_BINMODE) {
6893#ifdef O_BINARY
6894 oflags |= O_BINARY;
6895#endif
6896 if (!has_enc)
6897 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6898 }
6899#if DEFAULT_TEXTMODE
6900 else if (NIL_P(vmode)) {
6901 fmode |= DEFAULT_TEXTMODE;
6902 }
6903#endif
6904 v = rb_hash_aref(opthash, sym_perm);
6905 if (!NIL_P(v)) {
6906 if (vperm_p) {
6907 if (!NIL_P(*vperm_p)) {
6908 rb_raise(rb_eArgError, "perm specified twice");
6909 }
6910 *vperm_p = v;
6911 }
6912 else {
6913 /* perm no use, just ignore */
6914 }
6915 }
6916 ecflags = (fmode & FMODE_READABLE) ?
6917 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6918 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6919#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6920 ecflags |= (fmode & FMODE_WRITABLE) ?
6921 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6922 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6923#endif
6924
6925 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6926 if (has_enc) {
6927 rb_raise(rb_eArgError, "encoding specified twice");
6928 }
6929 }
6930 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6931 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
6932 }
6933
6934 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6935
6936 *vmode_p = vmode;
6937
6938 *oflags_p = oflags;
6939 *fmode_p = fmode;
6940 convconfig_p->enc = enc;
6941 convconfig_p->enc2 = enc2;
6942 convconfig_p->ecflags = ecflags;
6943 convconfig_p->ecopts = ecopts;
6944}
6945
6946 struct sysopen_struct {
6947 VALUE fname;
6948 int oflags;
6949 mode_t perm;
6950};
6951
6952static void *
6953sysopen_func(void *ptr)
6954{
6955 const struct sysopen_struct *data = ptr;
6956 const char *fname = RSTRING_PTR(data->fname);
6957 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
6958}
6959
6960static inline int
6961rb_sysopen_internal(struct sysopen_struct *data)
6962{
6963 int fd;
6964 fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
6965 if (0 <= fd)
6966 rb_update_max_fd(fd);
6967 return fd;
6968}
6969
6970static int
6971rb_sysopen(VALUE fname, int oflags, mode_t perm)
6972{
6973 int fd = -1;
6974 struct sysopen_struct data;
6975
6976 data.fname = rb_str_encode_ospath(fname);
6977 StringValueCStr(data.fname);
6978 data.oflags = oflags;
6979 data.perm = perm;
6980
6981 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
6982 rb_syserr_fail_path(first_errno, fname);
6983 }
6984 return fd;
6985}
6986
6987static inline FILE *
6988fdopen_internal(int fd, const char *modestr)
6989{
6990 FILE *file;
6991
6992#if defined(__sun)
6993 errno = 0;
6994#endif
6995 file = fdopen(fd, modestr);
6996 if (!file) {
6997#ifdef _WIN32
6998 if (errno == 0) errno = EINVAL;
6999#elif defined(__sun)
7000 if (errno == 0) errno = EMFILE;
7001#endif
7002 }
7003 return file;
7004}
7005
7006 FILE *
7007rb_fdopen(int fd, const char *modestr)
7008{
7009 FILE *file = 0;
7010
7011 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7012 rb_syserr_fail(first_errno, 0);
7013 }
7014
7015 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7016#ifdef USE_SETVBUF
7017 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7018 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7019#endif
7020 return file;
7021}
7022
7023static int
7024io_check_tty(rb_io_t *fptr)
7025{
7026 int t = isatty(fptr->fd);
7027 if (t)
7028 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7029 return t;
7030}
7031
7032static VALUE rb_io_internal_encoding(VALUE);
7033static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7034
7035static int
7036io_strip_bom(VALUE io)
7037{
7038 VALUE b1, b2, b3, b4;
7039 rb_io_t *fptr;
7040
7041 GetOpenFile(io, fptr);
7042 if (!(fptr->mode & FMODE_READABLE)) return 0;
7043 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7044 switch (b1) {
7045 case INT2FIX(0xEF):
7046 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7047 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7048 if (b3 == INT2FIX(0xBF)) {
7049 return rb_utf8_encindex();
7050 }
7051 rb_io_ungetbyte(io, b3);
7052 }
7053 rb_io_ungetbyte(io, b2);
7054 break;
7055
7056 case INT2FIX(0xFE):
7057 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7058 if (b2 == INT2FIX(0xFF)) {
7059 return ENCINDEX_UTF_16BE;
7060 }
7061 rb_io_ungetbyte(io, b2);
7062 break;
7063
7064 case INT2FIX(0xFF):
7065 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7066 if (b2 == INT2FIX(0xFE)) {
7067 b3 = rb_io_getbyte(io);
7068 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7069 if (b4 == INT2FIX(0)) {
7070 return ENCINDEX_UTF_32LE;
7071 }
7072 rb_io_ungetbyte(io, b4);
7073 }
7074 rb_io_ungetbyte(io, b3);
7075 return ENCINDEX_UTF_16LE;
7076 }
7077 rb_io_ungetbyte(io, b2);
7078 break;
7079
7080 case INT2FIX(0):
7081 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7082 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7083 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7084 if (b4 == INT2FIX(0xFF)) {
7085 return ENCINDEX_UTF_32BE;
7086 }
7087 rb_io_ungetbyte(io, b4);
7088 }
7089 rb_io_ungetbyte(io, b3);
7090 }
7091 rb_io_ungetbyte(io, b2);
7092 break;
7093 }
7094 rb_io_ungetbyte(io, b1);
7095 return 0;
7096}
7097
7098static rb_encoding *
7099io_set_encoding_by_bom(VALUE io)
7100{
7101 int idx = io_strip_bom(io);
7102 rb_io_t *fptr;
7103 rb_encoding *extenc = NULL;
7104
7105 GetOpenFile(io, fptr);
7106 if (idx) {
7107 extenc = rb_enc_from_index(idx);
7108 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7109 rb_io_internal_encoding(io), Qnil);
7110 }
7111 else {
7112 fptr->encs.enc2 = NULL;
7113 }
7114 return extenc;
7115}
7116
7117static VALUE
7118rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7119 const struct rb_io_encoding *convconfig, mode_t perm)
7120{
7121 VALUE pathv;
7122 rb_io_t *fptr;
7123 struct rb_io_encoding cc;
7124 if (!convconfig) {
7125 /* Set to default encodings */
7126 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7127 cc.ecflags = 0;
7128 cc.ecopts = Qnil;
7129 convconfig = &cc;
7130 }
7131 validate_enc_binmode(&fmode, convconfig->ecflags,
7132 convconfig->enc, convconfig->enc2);
7133
7134 MakeOpenFile(io, fptr);
7135 fptr->mode = fmode;
7136 fptr->encs = *convconfig;
7137 pathv = rb_str_new_frozen(filename);
7138#ifdef O_TMPFILE
7139 if (!(oflags & O_TMPFILE)) {
7140 fptr->pathv = pathv;
7141 }
7142#else
7143 fptr->pathv = pathv;
7144#endif
7145 fptr->fd = rb_sysopen(pathv, oflags, perm);
7146 io_check_tty(fptr);
7147 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7148
7149 return io;
7150}
7151
7152static VALUE
7153rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7154{
7155 int fmode = rb_io_modestr_fmode(modestr);
7156 const char *p = strchr(modestr, ':');
7157 struct rb_io_encoding convconfig;
7158
7159 if (p) {
7160 parse_mode_enc(p+1, rb_usascii_encoding(),
7161 &convconfig.enc, &convconfig.enc2, &fmode);
7162 convconfig.ecflags = 0;
7163 convconfig.ecopts = Qnil;
7164 }
7165 else {
7166 rb_encoding *e;
7167 /* Set to default encodings */
7168
7169 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7170 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7171 convconfig.ecflags = 0;
7172 convconfig.ecopts = Qnil;
7173 }
7174
7175 return rb_file_open_generic(io, filename,
7176 rb_io_fmode_oflags(fmode),
7177 fmode,
7178 &convconfig,
7179 0666);
7180}
7181
7182 VALUE
7183rb_file_open_str(VALUE fname, const char *modestr)
7184{
7185 FilePathValue(fname);
7186 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7187}
7188
7189 VALUE
7190rb_file_open(const char *fname, const char *modestr)
7191{
7192 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7193}
7194
7195#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7196 static struct pipe_list {
7197 rb_io_t *fptr;
7198 struct pipe_list *next;
7199} *pipe_list;
7200
7201static void
7202pipe_add_fptr(rb_io_t *fptr)
7203{
7204 struct pipe_list *list;
7205
7206 list = ALLOC(struct pipe_list);
7207 list->fptr = fptr;
7208 list->next = pipe_list;
7209 pipe_list = list;
7210}
7211
7212static void
7213pipe_del_fptr(rb_io_t *fptr)
7214{
7215 struct pipe_list **prev = &pipe_list;
7216 struct pipe_list *tmp;
7217
7218 while ((tmp = *prev) != 0) {
7219 if (tmp->fptr == fptr) {
7220 *prev = tmp->next;
7221 free(tmp);
7222 return;
7223 }
7224 prev = &tmp->next;
7225 }
7226}
7227
7228#if defined (_WIN32) || defined(__CYGWIN__)
7229static void
7230pipe_atexit(void)
7231{
7232 struct pipe_list *list = pipe_list;
7233 struct pipe_list *tmp;
7234
7235 while (list) {
7236 tmp = list->next;
7237 rb_io_fptr_finalize(list->fptr);
7238 list = tmp;
7239 }
7240}
7241#endif
7242
7243static void
7244pipe_finalize(rb_io_t *fptr, int noraise)
7245{
7246#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7247 int status = 0;
7248 if (fptr->stdio_file) {
7249 status = pclose(fptr->stdio_file);
7250 }
7251 fptr->fd = -1;
7252 fptr->stdio_file = 0;
7253 rb_last_status_set(status, fptr->pid);
7254#else
7255 fptr_finalize(fptr, noraise);
7256#endif
7257 pipe_del_fptr(fptr);
7258}
7259#endif
7260
7261static void
7262fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7263{
7264#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7265 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7266
7267 if (old_finalize == orig->finalize) return;
7268#endif
7269
7270 fptr->finalize = orig->finalize;
7271
7272#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7273 if (old_finalize != pipe_finalize) {
7274 struct pipe_list *list;
7275 for (list = pipe_list; list; list = list->next) {
7276 if (list->fptr == fptr) break;
7277 }
7278 if (!list) pipe_add_fptr(fptr);
7279 }
7280 else {
7281 pipe_del_fptr(fptr);
7282 }
7283#endif
7284}
7285
7286void
7287rb_io_synchronized(rb_io_t *fptr)
7288{
7289 rb_io_check_initialized(fptr);
7290 fptr->mode |= FMODE_SYNC;
7291}
7292
7293void
7294rb_io_unbuffered(rb_io_t *fptr)
7295{
7296 rb_io_synchronized(fptr);
7297}
7298
7299int
7300rb_pipe(int *pipes)
7301{
7302 int ret;
7303 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7304 if (ret == 0) {
7305 rb_update_max_fd(pipes[0]);
7306 rb_update_max_fd(pipes[1]);
7307 }
7308 return ret;
7309}
7310
7311#ifdef _WIN32
7312#define HAVE_SPAWNV 1
7313#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7314#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7315#endif
7316
7317#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7318struct popen_arg {
7319 VALUE execarg_obj;
7320 struct rb_execarg *eargp;
7321 int modef;
7322 int pair[2];
7323 int write_pair[2];
7324};
7325#endif
7326
7327#ifdef HAVE_WORKING_FORK
7328# ifndef __EMSCRIPTEN__
7329static void
7330popen_redirect(struct popen_arg *p)
7331{
7332 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7333 close(p->write_pair[1]);
7334 if (p->write_pair[0] != 0) {
7335 dup2(p->write_pair[0], 0);
7336 close(p->write_pair[0]);
7337 }
7338 close(p->pair[0]);
7339 if (p->pair[1] != 1) {
7340 dup2(p->pair[1], 1);
7341 close(p->pair[1]);
7342 }
7343 }
7344 else if (p->modef & FMODE_READABLE) {
7345 close(p->pair[0]);
7346 if (p->pair[1] != 1) {
7347 dup2(p->pair[1], 1);
7348 close(p->pair[1]);
7349 }
7350 }
7351 else {
7352 close(p->pair[1]);
7353 if (p->pair[0] != 0) {
7354 dup2(p->pair[0], 0);
7355 close(p->pair[0]);
7356 }
7357 }
7358}
7359# endif
7360
7361#if defined(__linux__)
7362/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7363 * Since /proc may not be available, linux_get_maxfd is just a hint.
7364 * This function, linux_get_maxfd, must be async-signal-safe.
7365 * I.e. opendir() is not usable.
7366 *
7367 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7368 * However they are easy to re-implement in async-signal-safe manner.
7369 * (Also note that there is missing/memcmp.c.)
7370 */
7371static int
7372linux_get_maxfd(void)
7373{
7374 int fd;
7375 char buf[4096], *p, *np, *e;
7376 ssize_t ss;
7377 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7378 if (fd < 0) return fd;
7379 ss = read(fd, buf, sizeof(buf));
7380 if (ss < 0) goto err;
7381 p = buf;
7382 e = buf + ss;
7383 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7384 (np = memchr(p, '\n', e-p)) != NULL) {
7385 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7386 int fdsize;
7387 p += sizeof("FDSize:")-1;
7388 *np = '\0';
7389 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7390 close(fd);
7391 return fdsize;
7392 }
7393 p = np+1;
7394 }
7395 /* fall through */
7396
7397 err:
7398 close(fd);
7399 return (int)ss;
7400}
7401#endif
7402
7403/* This function should be async-signal-safe. */
7404void
7405 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7406{
7407#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7408 int fd, ret;
7409 int max = (int)max_file_descriptor;
7410# ifdef F_MAXFD
7411 /* F_MAXFD is available since NetBSD 2.0. */
7412 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7413 if (ret != -1)
7414 maxhint = max = ret;
7415# elif defined(__linux__)
7416 ret = linux_get_maxfd();
7417 if (maxhint < ret)
7418 maxhint = ret;
7419 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7420# endif
7421 if (max < maxhint)
7422 max = maxhint;
7423 for (fd = lowfd; fd <= max; fd++) {
7424 if (!NIL_P(noclose_fds) &&
7425 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7426 continue;
7427 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7428 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7429 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7430 }
7431# define CONTIGUOUS_CLOSED_FDS 20
7432 if (ret != -1) {
7433 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7434 max = fd + CONTIGUOUS_CLOSED_FDS;
7435 }
7436 }
7437#endif
7438}
7439
7440# ifndef __EMSCRIPTEN__
7441static int
7442popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7443{
7444 struct popen_arg *p = (struct popen_arg*)pp;
7445
7446 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7447}
7448# endif
7449#endif
7450
7451#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7452static VALUE
7453rb_execarg_fixup_v(VALUE execarg_obj)
7454{
7455 rb_execarg_parent_start(execarg_obj);
7456 return Qnil;
7457}
7458#else
7459char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7460#endif
7461
7462#ifndef __EMSCRIPTEN__
7463static VALUE
7464pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7465 const struct rb_io_encoding *convconfig)
7466{
7467 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7468 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7469 rb_pid_t pid = 0;
7470 rb_io_t *fptr;
7471 VALUE port;
7472 rb_io_t *write_fptr;
7473 VALUE write_port;
7474#if defined(HAVE_WORKING_FORK)
7475 int status;
7476 char errmsg[80] = { '\0' };
7477#endif
7478#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7479 int state;
7480 struct popen_arg arg;
7481#endif
7482 int e = 0;
7483#if defined(HAVE_SPAWNV)
7484# if defined(HAVE_SPAWNVE)
7485# define DO_SPAWN(cmd, args, envp) ((args) ? \
7486 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7487 spawne(P_NOWAIT, (cmd), (envp)))
7488# else
7489# define DO_SPAWN(cmd, args, envp) ((args) ? \
7490 spawnv(P_NOWAIT, (cmd), (args)) : \
7491 spawn(P_NOWAIT, (cmd)))
7492# endif
7493# if !defined(HAVE_WORKING_FORK)
7494 char **args = NULL;
7495# if defined(HAVE_SPAWNVE)
7496 char **envp = NULL;
7497# endif
7498# endif
7499#endif
7500#if !defined(HAVE_WORKING_FORK)
7501 struct rb_execarg sarg, *sargp = &sarg;
7502#endif
7503 FILE *fp = 0;
7504 int fd = -1;
7505 int write_fd = -1;
7506#if !defined(HAVE_WORKING_FORK)
7507 const char *cmd = 0;
7508
7509 if (prog)
7510 cmd = StringValueCStr(prog);
7511#endif
7512
7513#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7514 arg.execarg_obj = execarg_obj;
7515 arg.eargp = eargp;
7516 arg.modef = fmode;
7517 arg.pair[0] = arg.pair[1] = -1;
7518 arg.write_pair[0] = arg.write_pair[1] = -1;
7519# if !defined(HAVE_WORKING_FORK)
7520 if (eargp && !eargp->use_shell) {
7521 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7522 }
7523# endif
7524 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7525 case FMODE_READABLE|FMODE_WRITABLE:
7526 if (rb_pipe(arg.write_pair) < 0)
7527 rb_sys_fail_str(prog);
7528 if (rb_pipe(arg.pair) < 0) {
7529 e = errno;
7530 close(arg.write_pair[0]);
7531 close(arg.write_pair[1]);
7532 rb_syserr_fail_str(e, prog);
7533 }
7534 if (eargp) {
7535 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7536 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7537 }
7538 break;
7539 case FMODE_READABLE:
7540 if (rb_pipe(arg.pair) < 0)
7541 rb_sys_fail_str(prog);
7542 if (eargp)
7543 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7544 break;
7545 case FMODE_WRITABLE:
7546 if (rb_pipe(arg.pair) < 0)
7547 rb_sys_fail_str(prog);
7548 if (eargp)
7549 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7550 break;
7551 default:
7552 rb_sys_fail_str(prog);
7553 }
7554 if (!NIL_P(execarg_obj)) {
7555 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7556 if (state) {
7557 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7558 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7559 if (0 <= arg.pair[0]) close(arg.pair[0]);
7560 if (0 <= arg.pair[1]) close(arg.pair[1]);
7561 rb_execarg_parent_end(execarg_obj);
7562 rb_jump_tag(state);
7563 }
7564
7565# if defined(HAVE_WORKING_FORK)
7566 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7567# else
7568 rb_execarg_run_options(eargp, sargp, NULL, 0);
7569# if defined(HAVE_SPAWNVE)
7570 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7571# endif
7572 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7573 /* exec failed */
7574 switch (e = errno) {
7575 case EAGAIN:
7576# if EWOULDBLOCK != EAGAIN
7577 case EWOULDBLOCK:
7578# endif
7579 rb_thread_sleep(1);
7580 continue;
7581 }
7582 break;
7583 }
7584 if (eargp)
7585 rb_execarg_run_options(sargp, NULL, NULL, 0);
7586# endif
7587 rb_execarg_parent_end(execarg_obj);
7588 }
7589 else {
7590# if defined(HAVE_WORKING_FORK)
7591 pid = rb_call_proc__fork();
7592 if (pid == 0) { /* child */
7593 popen_redirect(&arg);
7594 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7595 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7596 return Qnil;
7597 }
7598# else
7599 rb_notimplement();
7600# endif
7601 }
7602
7603 /* parent */
7604 if (pid < 0) {
7605# if defined(HAVE_WORKING_FORK)
7606 e = errno;
7607# endif
7608 close(arg.pair[0]);
7609 close(arg.pair[1]);
7610 if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) {
7611 close(arg.write_pair[0]);
7612 close(arg.write_pair[1]);
7613 }
7614# if defined(HAVE_WORKING_FORK)
7615 if (errmsg[0])
7616 rb_syserr_fail(e, errmsg);
7617# endif
7618 rb_syserr_fail_str(e, prog);
7619 }
7620 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7621 close(arg.pair[1]);
7622 fd = arg.pair[0];
7623 close(arg.write_pair[0]);
7624 write_fd = arg.write_pair[1];
7625 }
7626 else if (fmode & FMODE_READABLE) {
7627 close(arg.pair[1]);
7628 fd = arg.pair[0];
7629 }
7630 else {
7631 close(arg.pair[0]);
7632 fd = arg.pair[1];
7633 }
7634#else
7635 cmd = rb_execarg_commandline(eargp, &prog);
7636 if (!NIL_P(execarg_obj)) {
7637 rb_execarg_parent_start(execarg_obj);
7638 rb_execarg_run_options(eargp, sargp, NULL, 0);
7639 }
7640 fp = popen(cmd, modestr);
7641 e = errno;
7642 if (eargp) {
7643 rb_execarg_parent_end(execarg_obj);
7644 rb_execarg_run_options(sargp, NULL, NULL, 0);
7645 }
7646 if (!fp) rb_syserr_fail_path(e, prog);
7647 fd = fileno(fp);
7648#endif
7649
7650 port = io_alloc(rb_cIO);
7651 MakeOpenFile(port, fptr);
7652 fptr->fd = fd;
7653 fptr->stdio_file = fp;
7654 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7655 if (convconfig) {
7656 fptr->encs = *convconfig;
7657#if RUBY_CRLF_ENVIRONMENT
7658 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
7659 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7660 }
7661#endif
7662 }
7663 else {
7664 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7665 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7666 }
7667#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7668 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7669 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7670 }
7671#endif
7672 }
7673 fptr->pid = pid;
7674
7675 if (0 <= write_fd) {
7676 write_port = io_alloc(rb_cIO);
7677 MakeOpenFile(write_port, write_fptr);
7678 write_fptr->fd = write_fd;
7679 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7680 fptr->mode &= ~FMODE_WRITABLE;
7681 fptr->tied_io_for_writing = write_port;
7682 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7683 }
7684
7685#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7686 fptr->finalize = pipe_finalize;
7687 pipe_add_fptr(fptr);
7688#endif
7689 return port;
7690}
7691#else
7692static VALUE
7693pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7694 const struct rb_io_encoding *convconfig)
7695{
7696 rb_raise(rb_eNotImpError, "popen() is not available");
7697}
7698#endif
7699
7700static int
7701is_popen_fork(VALUE prog)
7702{
7703 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7704#if !defined(HAVE_WORKING_FORK)
7705 rb_raise(rb_eNotImpError,
7706 "fork() function is unimplemented on this machine");
7707#else
7708 return TRUE;
7709#endif
7710 }
7711 return FALSE;
7712}
7713
7714static VALUE
7715pipe_open_s(VALUE prog, const char *modestr, int fmode,
7716 const struct rb_io_encoding *convconfig)
7717{
7718 int argc = 1;
7719 VALUE *argv = &prog;
7720 VALUE execarg_obj = Qnil;
7721
7722 if (!is_popen_fork(prog))
7723 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7724 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7725}
7726
7727static VALUE
7728pipe_close(VALUE io)
7729{
7730 rb_io_t *fptr = io_close_fptr(io);
7731 if (fptr) {
7732 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7733 }
7734 return Qnil;
7735}
7736
7737static VALUE popen_finish(VALUE port, VALUE klass);
7738
7739/*
7740 * call-seq:
7741 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7742 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7743 *
7744 * Executes the given command +cmd+ as a subprocess
7745 * whose $stdin and $stdout are connected to a new stream +io+.
7746 *
7747 * This method has potential security vulnerabilities if called with untrusted input;
7748 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7749 *
7750 * If no block is given, returns the new stream,
7751 * which depending on given +mode+ may be open for reading, writing, or both.
7752 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7753 *
7754 * If a block is given, the stream is passed to the block
7755 * (again, open for reading, writing, or both);
7756 * when the block exits, the stream is closed,
7757 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7758 *
7759 * Optional argument +mode+ may be any valid \IO mode.
7760 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7761 *
7762 * Required argument +cmd+ determines which of the following occurs:
7763 *
7764 * - The process forks.
7765 * - A specified program runs in a shell.
7766 * - A specified program runs with specified arguments.
7767 * - A specified program runs with specified arguments and a specified +argv0+.
7768 *
7769 * Each of these is detailed below.
7770 *
7771 * The optional hash argument +env+ specifies name/value pairs that are to be added
7772 * to the environment variables for the subprocess:
7773 *
7774 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7775 * pipe.puts 'puts ENV["FOO"]'
7776 * pipe.close_write
7777 * pipe.gets
7778 * end => "bar\n"
7779 *
7780 * Optional keyword arguments +opts+ specify:
7781 *
7782 * - {Open options}[rdoc-ref:IO@Open+Options].
7783 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7784 * - Options for Kernel#spawn.
7785 *
7786 * <b>Forked \Process</b>
7787 *
7788 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7789 * IO.popen('-') do |pipe|
7790 * if pipe
7791 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7792 * else
7793 * $stderr.puts "In child, pid is #{$$}\n"
7794 * end
7795 * end
7796 *
7797 * Output:
7798 *
7799 * In parent, child pid is 26253
7800 * In child, pid is 26253
7801 *
7802 * Note that this is not supported on all platforms.
7803 *
7804 * <b>Shell Subprocess</b>
7805 *
7806 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7807 * the program named +cmd+ is run as a shell command:
7808 *
7809 * IO.popen('uname') do |pipe|
7810 * pipe.readlines
7811 * end
7812 *
7813 * Output:
7814 *
7815 * ["Linux\n"]
7816 *
7817 * Another example:
7818 *
7819 * IO.popen('/bin/sh', 'r+') do |pipe|
7820 * pipe.puts('ls')
7821 * pipe.close_write
7822 * $stderr.puts pipe.readlines.size
7823 * end
7824 *
7825 * Output:
7826 *
7827 * 213
7828 *
7829 * <b>Program Subprocess</b>
7830 *
7831 * When argument +cmd+ is an array of strings,
7832 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7833 *
7834 * IO.popen(['du', '..', '.']) do |pipe|
7835 * $stderr.puts pipe.readlines.size
7836 * end
7837 *
7838 * Output:
7839 *
7840 * 1111
7841 *
7842 * <b>Program Subprocess with <tt>argv0</tt></b>
7843 *
7844 * When argument +cmd+ is an array whose first element is a 2-element string array
7845 * and whose remaining elements (if any) are strings:
7846 *
7847 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7848 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7849 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7850 *
7851 * Example (sets <tt>$0</tt> to 'foo'):
7852 *
7853 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7854 *
7855 * <b>Some Special Examples</b>
7856 *
7857 * # Set IO encoding.
7858 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7859 * euc_jp_string = nkf_io.read
7860 * }
7861 *
7862 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7863 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7864 * ls_result_with_error = io.read
7865 * end
7866 *
7867 * # Use mixture of spawn options and IO options.
7868 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7869 * ls_result_with_error = io.read
7870 * end
7871 *
7872 * f = IO.popen("uname")
7873 * p f.readlines
7874 * f.close
7875 * puts "Parent is #{Process.pid}"
7876 * IO.popen("date") {|f| puts f.gets }
7877 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7878 * p $?
7879 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7880 * f.puts "bar"; f.close_write; puts f.gets
7881 * }
7882 *
7883 * Output (from last section):
7884 *
7885 * ["Linux\n"]
7886 * Parent is 21346
7887 * Thu Jan 15 22:41:19 JST 2009
7888 * 21346 is here, f is #<IO:fd 3>
7889 * 21352 is here, f is nil
7890 * #<Process::Status: pid 21352 exit 0>
7891 * <foo>bar;zot;
7892 *
7893 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7894 *
7895 */
7896
7897static VALUE
7898rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7899{
7900 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7901
7902 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7903 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7904 switch (argc) {
7905 case 2:
7906 pmode = argv[1];
7907 case 1:
7908 pname = argv[0];
7909 break;
7910 default:
7911 {
7912 int ex = !NIL_P(opt);
7913 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7914 }
7915 }
7916 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7917}
7918
7919 VALUE
7920rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7921{
7922 const char *modestr;
7923 VALUE tmp, execarg_obj = Qnil;
7924 int oflags, fmode;
7925 struct rb_io_encoding convconfig;
7926
7927 tmp = rb_check_array_type(pname);
7928 if (!NIL_P(tmp)) {
7929 long len = RARRAY_LEN(tmp);
7930#if SIZEOF_LONG > SIZEOF_INT
7931 if (len > INT_MAX) {
7932 rb_raise(rb_eArgError, "too many arguments");
7933 }
7934#endif
7935 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7936 RB_GC_GUARD(tmp);
7937 }
7938 else {
7939 SafeStringValue(pname);
7940 execarg_obj = Qnil;
7941 if (!is_popen_fork(pname))
7942 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7943 }
7944 if (!NIL_P(execarg_obj)) {
7945 if (!NIL_P(opt))
7946 opt = rb_execarg_extract_options(execarg_obj, opt);
7947 if (!NIL_P(env))
7948 rb_execarg_setenv(execarg_obj, env);
7949 }
7950 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
7951 modestr = rb_io_oflags_modestr(oflags);
7952
7953 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7954}
7955
7956static VALUE
7957popen_finish(VALUE port, VALUE klass)
7958{
7959 if (NIL_P(port)) {
7960 /* child */
7961 if (rb_block_given_p()) {
7962 rb_yield(Qnil);
7963 rb_io_flush(rb_ractor_stdout());
7964 rb_io_flush(rb_ractor_stderr());
7965 _exit(0);
7966 }
7967 return Qnil;
7968 }
7969 RBASIC_SET_CLASS(port, klass);
7970 if (rb_block_given_p()) {
7971 return rb_ensure(rb_yield, port, pipe_close, port);
7972 }
7973 return port;
7974}
7975
7976#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
7977struct popen_writer_arg {
7978 char *const *argv;
7979 struct popen_arg popen;
7980};
7981
7982static int
7983exec_popen_writer(void *arg, char *errmsg, size_t buflen)
7984{
7985 struct popen_writer_arg *pw = arg;
7986 pw->popen.modef = FMODE_WRITABLE;
7987 popen_redirect(&pw->popen);
7988 execv(pw->argv[0], pw->argv);
7989 strlcpy(errmsg, strerror(errno), buflen);
7990 return -1;
7991}
7992#endif
7993
7994 FILE *
7995ruby_popen_writer(char *const *argv, rb_pid_t *pid)
7996{
7997#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
7998# ifdef HAVE_WORKING_FORK
7999 struct popen_writer_arg pw;
8000 int *const write_pair = pw.popen.pair;
8001# else
8002 int write_pair[2];
8003# endif
8004
8005 int result = rb_cloexec_pipe(write_pair);
8006 *pid = -1;
8007 if (result == 0) {
8008# ifdef HAVE_WORKING_FORK
8009 pw.argv = argv;
8010 int status;
8011 char errmsg[80] = {'\0'};
8012 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8013# else
8014 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8015 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8016# endif
8017 close(write_pair[0]);
8018 if (*pid < 0) {
8019 close(write_pair[1]);
8020 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8021 }
8022 else {
8023 return fdopen(write_pair[1], "w");
8024 }
8025 }
8026#endif
8027 return NULL;
8028}
8029
8030static void
8031rb_scan_open_args(int argc, const VALUE *argv,
8032 VALUE *fname_p, int *oflags_p, int *fmode_p,
8033 struct rb_io_encoding *convconfig_p, mode_t *perm_p)
8034{
8035 VALUE opt, fname, vmode, vperm;
8036 int oflags, fmode;
8037 mode_t perm;
8038
8039 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
8040 FilePathValue(fname);
8041
8042 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
8043
8044 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8045
8046 *fname_p = fname;
8047 *oflags_p = oflags;
8048 *fmode_p = fmode;
8049 *perm_p = perm;
8050}
8051
8052static VALUE
8053rb_open_file(int argc, const VALUE *argv, VALUE io)
8054{
8055 VALUE fname;
8056 int oflags, fmode;
8057 struct rb_io_encoding convconfig;
8058 mode_t perm;
8059
8060 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
8061 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8062
8063 return io;
8064}
8065
8066/*
8067 * Document-method: File::open
8068 *
8069 * call-seq:
8070 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8071 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8072 *
8073 * Creates a new File object, via File.new with the given arguments.
8074 *
8075 * With no block given, returns the File object.
8076 *
8077 * With a block given, calls the block with the File object
8078 * and returns the block's value.
8079 *
8080 */
8081
8082/*
8083 * Document-method: IO::open
8084 *
8085 * call-seq:
8086 * IO.open(fd, mode = 'r', **opts) -> io
8087 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8088 *
8089 * Creates a new \IO object, via IO.new with the given arguments.
8090 *
8091 * With no block given, returns the \IO object.
8092 *
8093 * With a block given, calls the block with the \IO object
8094 * and returns the block's value.
8095 *
8096 */
8097
8098static VALUE
8099rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8100{
8101 VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
8102
8103 if (rb_block_given_p()) {
8104 return rb_ensure(rb_yield, io, io_close, io);
8105 }
8106
8107 return io;
8108}
8109
8110/*
8111 * call-seq:
8112 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8113 *
8114 * Opens the file at the given path with the given mode and permissions;
8115 * returns the integer file descriptor.
8116 *
8117 * If the file is to be readable, it must exist;
8118 * if the file is to be writable and does not exist,
8119 * it is created with the given permissions:
8120 *
8121 * File.write('t.tmp', '') # => 0
8122 * IO.sysopen('t.tmp') # => 8
8123 * IO.sysopen('t.tmp', 'w') # => 9
8124 *
8125 *
8126 */
8127
8128static VALUE
8129rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8130{
8131 VALUE fname, vmode, vperm;
8132 VALUE intmode;
8133 int oflags, fd;
8134 mode_t perm;
8135
8136 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8137 FilePathValue(fname);
8138
8139 if (NIL_P(vmode))
8140 oflags = O_RDONLY;
8141 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8142 oflags = NUM2INT(intmode);
8143 else {
8144 SafeStringValue(vmode);
8145 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8146 }
8147 if (NIL_P(vperm)) perm = 0666;
8148 else perm = NUM2MODET(vperm);
8149
8150 RB_GC_GUARD(fname) = rb_str_new4(fname);
8151 fd = rb_sysopen(fname, oflags, perm);
8152 return INT2NUM(fd);
8153}
8154
8155static VALUE
8156check_pipe_command(VALUE filename_or_command)
8157{
8158 char *s = RSTRING_PTR(filename_or_command);
8159 long l = RSTRING_LEN(filename_or_command);
8160 char *e = s + l;
8161 int chlen;
8162
8163 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8164 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8165 return cmd;
8166 }
8167 return Qnil;
8168}
8169
8170/*
8171 * call-seq:
8172 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8173 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8174 *
8175 * Creates an IO object connected to the given file.
8176 *
8177 * This method has potential security vulnerabilities if called with untrusted input;
8178 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8179 *
8180 * With no block given, file stream is returned:
8181 *
8182 * open('t.txt') # => #<File:t.txt>
8183 *
8184 * With a block given, calls the block with the open file stream,
8185 * then closes the stream:
8186 *
8187 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8188 *
8189 * Output:
8190 *
8191 * #<File:t.txt>
8192 *
8193 * See File.open for details.
8194 *
8195 */
8196
8197static VALUE
8198rb_f_open(int argc, VALUE *argv, VALUE _)
8199{
8200 ID to_open = 0;
8201 int redirect = FALSE;
8202
8203 if (argc >= 1) {
8204 CONST_ID(to_open, "to_open");
8205 if (rb_respond_to(argv[0], to_open)) {
8206 redirect = TRUE;
8207 }
8208 else {
8209 VALUE tmp = argv[0];
8210 FilePathValue(tmp);
8211 if (NIL_P(tmp)) {
8212 redirect = TRUE;
8213 }
8214 else {
8215 VALUE cmd = check_pipe_command(tmp);
8216 if (!NIL_P(cmd)) {
8217 // TODO: when removed in 4.0, update command_injection.rdoc
8218 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8219 argv[0] = cmd;
8220 return rb_io_s_popen(argc, argv, rb_cIO);
8221 }
8222 }
8223 }
8224 }
8225 if (redirect) {
8226 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8227
8228 if (rb_block_given_p()) {
8229 return rb_ensure(rb_yield, io, io_close, io);
8230 }
8231 return io;
8232 }
8233 return rb_io_s_open(argc, argv, rb_cFile);
8234}
8235
8236static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const struct rb_io_encoding *, mode_t);
8237
8238static VALUE
8239rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8240{
8241 int oflags, fmode;
8242 struct rb_io_encoding convconfig;
8243 mode_t perm;
8244
8245 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8246 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8247 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8248}
8249
8250static VALUE
8251rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8252 const struct rb_io_encoding *convconfig, mode_t perm)
8253{
8254 VALUE cmd;
8255 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8256 // TODO: when removed in 4.0, update command_injection.rdoc
8257 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8258 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8259 }
8260 else {
8261 return rb_file_open_generic(io_alloc(klass), filename,
8262 oflags, fmode, convconfig, perm);
8263 }
8264}
8265
8266static VALUE
8267io_reopen(VALUE io, VALUE nfile)
8268{
8269 rb_io_t *fptr, *orig;
8270 int fd, fd2;
8271 rb_off_t pos = 0;
8272
8273 nfile = rb_io_get_io(nfile);
8274 GetOpenFile(io, fptr);
8275 GetOpenFile(nfile, orig);
8276
8277 if (fptr == orig) return io;
8278 if (RUBY_IO_EXTERNAL_P(fptr)) {
8279 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8280 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8281 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8282 rb_raise(rb_eArgError,
8283 "%s can't change access mode from \"%s\" to \"%s\"",
8284 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8285 rb_io_fmode_modestr(orig->mode));
8286 }
8287 }
8288 if (fptr->mode & FMODE_WRITABLE) {
8289 if (io_fflush(fptr) < 0)
8290 rb_sys_fail_on_write(fptr);
8291 }
8292 else {
8293 flush_before_seek(fptr);
8294 }
8295 if (orig->mode & FMODE_READABLE) {
8296 pos = io_tell(orig);
8297 }
8298 if (orig->mode & FMODE_WRITABLE) {
8299 if (io_fflush(orig) < 0)
8300 rb_sys_fail_on_write(fptr);
8301 }
8302
8303 /* copy rb_io_t structure */
8304 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8305 fptr->pid = orig->pid;
8306 fptr->lineno = orig->lineno;
8307 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8308 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8309 fptr_copy_finalizer(fptr, orig);
8310
8311 fd = fptr->fd;
8312 fd2 = orig->fd;
8313 if (fd != fd2) {
8314 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8315 /* need to keep FILE objects of stdin, stdout and stderr */
8316 if (rb_cloexec_dup2(fd2, fd) < 0)
8317 rb_sys_fail_path(orig->pathv);
8318 rb_update_max_fd(fd);
8319 }
8320 else {
8321 fclose(fptr->stdio_file);
8322 fptr->stdio_file = 0;
8323 fptr->fd = -1;
8324 if (rb_cloexec_dup2(fd2, fd) < 0)
8325 rb_sys_fail_path(orig->pathv);
8326 rb_update_max_fd(fd);
8327 fptr->fd = fd;
8328 }
8329 rb_thread_fd_close(fd);
8330 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8331 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8332 rb_sys_fail_path(fptr->pathv);
8333 }
8334 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8335 rb_sys_fail_path(orig->pathv);
8336 }
8337 }
8338 }
8339
8340 if (fptr->mode & FMODE_BINMODE) {
8341 rb_io_binmode(io);
8342 }
8343
8344 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8345 return io;
8346}
8347
8348#ifdef _WIN32
8349int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8350#else
8351static int
8352rb_freopen(VALUE fname, const char *mode, FILE *fp)
8353{
8354 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8355 RB_GC_GUARD(fname);
8356 return errno;
8357 }
8358 return 0;
8359}
8360#endif
8361
8362/*
8363 * call-seq:
8364 * reopen(other_io) -> self
8365 * reopen(path, mode = 'r', **opts) -> self
8366 *
8367 * Reassociates the stream with another stream,
8368 * which may be of a different class.
8369 * This method may be used to redirect an existing stream
8370 * to a new destination.
8371 *
8372 * With argument +other_io+ given, reassociates with that stream:
8373 *
8374 * # Redirect $stdin from a file.
8375 * f = File.open('t.txt')
8376 * $stdin.reopen(f)
8377 * f.close
8378 *
8379 * # Redirect $stdout to a file.
8380 * f = File.open('t.tmp', 'w')
8381 * $stdout.reopen(f)
8382 * f.close
8383 *
8384 * With argument +path+ given, reassociates with a new stream to that file path:
8385 *
8386 * $stdin.reopen('t.txt')
8387 * $stdout.reopen('t.tmp', 'w')
8388 *
8389 * Optional keyword arguments +opts+ specify:
8390 *
8391 * - {Open Options}[rdoc-ref:IO@Open+Options].
8392 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8393 *
8394 */
8395
8396static VALUE
8397rb_io_reopen(int argc, VALUE *argv, VALUE file)
8398{
8399 VALUE fname, nmode, opt;
8400 int oflags;
8401 rb_io_t *fptr;
8402
8403 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8404 VALUE tmp = rb_io_check_io(fname);
8405 if (!NIL_P(tmp)) {
8406 return io_reopen(file, tmp);
8407 }
8408 }
8409
8410 FilePathValue(fname);
8411 rb_io_taint_check(file);
8412 fptr = RFILE(file)->fptr;
8413 if (!fptr) {
8414 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8415 }
8416
8417 if (!NIL_P(nmode) || !NIL_P(opt)) {
8418 int fmode;
8419 struct rb_io_encoding convconfig;
8420
8421 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8422 if (RUBY_IO_EXTERNAL_P(fptr) &&
8423 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8424 (fptr->mode & FMODE_READWRITE)) {
8425 rb_raise(rb_eArgError,
8426 "%s can't change access mode from \"%s\" to \"%s\"",
8427 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8428 rb_io_fmode_modestr(fmode));
8429 }
8430 fptr->mode = fmode;
8431 fptr->encs = convconfig;
8432 }
8433 else {
8434 oflags = rb_io_fmode_oflags(fptr->mode);
8435 }
8436
8437 fptr->pathv = fname;
8438 if (fptr->fd < 0) {
8439 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8440 fptr->stdio_file = 0;
8441 return file;
8442 }
8443
8444 if (fptr->mode & FMODE_WRITABLE) {
8445 if (io_fflush(fptr) < 0)
8446 rb_sys_fail_on_write(fptr);
8447 }
8448 fptr->rbuf.off = fptr->rbuf.len = 0;
8449
8450 if (fptr->stdio_file) {
8451 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8452 rb_io_oflags_modestr(oflags),
8453 fptr->stdio_file);
8454 if (e) rb_syserr_fail_path(e, fptr->pathv);
8455 fptr->fd = fileno(fptr->stdio_file);
8456 rb_fd_fix_cloexec(fptr->fd);
8457#ifdef USE_SETVBUF
8458 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8459 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8460#endif
8461 if (fptr->stdio_file == stderr) {
8462 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8463 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8464 }
8465 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8466 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8467 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8468 }
8469 }
8470 else {
8471 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8472 int err = 0;
8473 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8474 err = errno;
8475 (void)close(tmpfd);
8476 if (err) {
8477 rb_syserr_fail_path(err, fptr->pathv);
8478 }
8479 }
8480
8481 return file;
8482}
8483
8484/* :nodoc: */
8485static VALUE
8486rb_io_init_copy(VALUE dest, VALUE io)
8487{
8488 rb_io_t *fptr, *orig;
8489 int fd;
8490 VALUE write_io;
8491 rb_off_t pos;
8492
8493 io = rb_io_get_io(io);
8494 if (!OBJ_INIT_COPY(dest, io)) return dest;
8495 GetOpenFile(io, orig);
8496 MakeOpenFile(dest, fptr);
8497
8498 rb_io_flush(io);
8499
8500 /* copy rb_io_t structure */
8501 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8502 fptr->encs = orig->encs;
8503 fptr->pid = orig->pid;
8504 fptr->lineno = orig->lineno;
8505 fptr->timeout = orig->timeout;
8506 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8507 fptr_copy_finalizer(fptr, orig);
8508
8509 fd = ruby_dup(orig->fd);
8510 fptr->fd = fd;
8511 pos = io_tell(orig);
8512 if (0 <= pos)
8513 io_seek(fptr, pos, SEEK_SET);
8514 if (fptr->mode & FMODE_BINMODE) {
8515 rb_io_binmode(dest);
8516 }
8517
8518 write_io = GetWriteIO(io);
8519 if (io != write_io) {
8520 write_io = rb_obj_dup(write_io);
8521 fptr->tied_io_for_writing = write_io;
8522 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8523 }
8524
8525 return dest;
8526}
8527
8528/*
8529 * call-seq:
8530 * printf(format_string, *objects) -> nil
8531 *
8532 * Formats and writes +objects+ to the stream.
8533 *
8534 * For details on +format_string+, see
8535 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8536 *
8537 */
8538
8539 VALUE
8540rb_io_printf(int argc, const VALUE *argv, VALUE out)
8541{
8542 rb_io_write(out, rb_f_sprintf(argc, argv));
8543 return Qnil;
8544}
8545
8546/*
8547 * call-seq:
8548 * printf(format_string, *objects) -> nil
8549 * printf(io, format_string, *objects) -> nil
8550 *
8551 * Equivalent to:
8552 *
8553 * io.write(sprintf(format_string, *objects))
8554 *
8555 * For details on +format_string+, see
8556 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8557 *
8558 * With the single argument +format_string+, formats +objects+ into the string,
8559 * then writes the formatted string to $stdout:
8560 *
8561 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8562 *
8563 * Output (on $stdout):
8564 *
8565 * 0024 24 24.00#
8566 *
8567 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8568 * then writes the formatted string to +io+:
8569 *
8570 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8571 *
8572 * Output (on $stderr):
8573 *
8574 * 0024 24 24.00# => nil
8575 *
8576 * With no arguments, does nothing.
8577 *
8578 */
8579
8580static VALUE
8581rb_f_printf(int argc, VALUE *argv, VALUE _)
8582{
8583 VALUE out;
8584
8585 if (argc == 0) return Qnil;
8586 if (RB_TYPE_P(argv[0], T_STRING)) {
8587 out = rb_ractor_stdout();
8588 }
8589 else {
8590 out = argv[0];
8591 argv++;
8592 argc--;
8593 }
8594 rb_io_write(out, rb_f_sprintf(argc, argv));
8595
8596 return Qnil;
8597}
8598
8599static void
8600deprecated_str_setter(VALUE val, ID id, VALUE *var)
8601{
8602 rb_str_setter(val, id, &val);
8603 if (!NIL_P(val)) {
8604 rb_warn_deprecated("`%s'", NULL, rb_id2name(id));
8605 }
8606 *var = val;
8607}
8608
8609/*
8610 * call-seq:
8611 * print(*objects) -> nil
8612 *
8613 * Writes the given objects to the stream; returns +nil+.
8614 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8615 * (<tt>$\</tt>), if it is not +nil+.
8616 * See {Line IO}[rdoc-ref:IO@Line+IO].
8617 *
8618 * With argument +objects+ given, for each object:
8619 *
8620 * - Converts via its method +to_s+ if not a string.
8621 * - Writes to the stream.
8622 * - If not the last object, writes the output field separator
8623 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8624 *
8625 * With default separators:
8626 *
8627 * f = File.open('t.tmp', 'w+')
8628 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8629 * p $OUTPUT_RECORD_SEPARATOR
8630 * p $OUTPUT_FIELD_SEPARATOR
8631 * f.print(*objects)
8632 * f.rewind
8633 * p f.read
8634 * f.close
8635 *
8636 * Output:
8637 *
8638 * nil
8639 * nil
8640 * "00.00/10+0izerozero"
8641 *
8642 * With specified separators:
8643 *
8644 * $\ = "\n"
8645 * $, = ','
8646 * f.rewind
8647 * f.print(*objects)
8648 * f.rewind
8649 * p f.read
8650 *
8651 * Output:
8652 *
8653 * "0,0.0,0/1,0+0i,zero,zero\n"
8654 *
8655 * With no argument given, writes the content of <tt>$_</tt>
8656 * (which is usually the most recent user input):
8657 *
8658 * f = File.open('t.tmp', 'w+')
8659 * gets # Sets $_ to the most recent user input.
8660 * f.print
8661 * f.close
8662 *
8663 */
8664
8665 VALUE
8666rb_io_print(int argc, const VALUE *argv, VALUE out)
8667{
8668 int i;
8669 VALUE line;
8670
8671 /* if no argument given, print `$_' */
8672 if (argc == 0) {
8673 argc = 1;
8674 line = rb_lastline_get();
8675 argv = &line;
8676 }
8677 if (argc > 1 && !NIL_P(rb_output_fs)) {
8678 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8679 }
8680 for (i=0; i<argc; i++) {
8681 if (!NIL_P(rb_output_fs) && i>0) {
8682 rb_io_write(out, rb_output_fs);
8683 }
8684 rb_io_write(out, argv[i]);
8685 }
8686 if (argc > 0 && !NIL_P(rb_output_rs)) {
8687 rb_io_write(out, rb_output_rs);
8688 }
8689
8690 return Qnil;
8691}
8692
8693/*
8694 * call-seq:
8695 * print(*objects) -> nil
8696 *
8697 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8698 * this method is the straightforward way to write to <tt>$stdout</tt>.
8699 *
8700 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8701 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8702 * <tt>$\</tt>), if it is not +nil+.
8703 *
8704 * With argument +objects+ given, for each object:
8705 *
8706 * - Converts via its method +to_s+ if not a string.
8707 * - Writes to <tt>stdout</tt>.
8708 * - If not the last object, writes the output field separator
8709 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8710 *
8711 * With default separators:
8712 *
8713 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8714 * $OUTPUT_RECORD_SEPARATOR
8715 * $OUTPUT_FIELD_SEPARATOR
8716 * print(*objects)
8717 *
8718 * Output:
8719 *
8720 * nil
8721 * nil
8722 * 00.00/10+0izerozero
8723 *
8724 * With specified separators:
8725 *
8726 * $OUTPUT_RECORD_SEPARATOR = "\n"
8727 * $OUTPUT_FIELD_SEPARATOR = ','
8728 * print(*objects)
8729 *
8730 * Output:
8731 *
8732 * 0,0.0,0/1,0+0i,zero,zero
8733 *
8734 * With no argument given, writes the content of <tt>$_</tt>
8735 * (which is usually the most recent user input):
8736 *
8737 * gets # Sets $_ to the most recent user input.
8738 * print # Prints $_.
8739 *
8740 */
8741
8742static VALUE
8743rb_f_print(int argc, const VALUE *argv, VALUE _)
8744{
8745 rb_io_print(argc, argv, rb_ractor_stdout());
8746 return Qnil;
8747}
8748
8749/*
8750 * call-seq:
8751 * putc(object) -> object
8752 *
8753 * Writes a character to the stream.
8754 * See {Character IO}[rdoc-ref:IO@Character+IO].
8755 *
8756 * If +object+ is numeric, converts to integer if necessary,
8757 * then writes the character whose code is the
8758 * least significant byte;
8759 * if +object+ is a string, writes the first character:
8760 *
8761 * $stdout.putc "A"
8762 * $stdout.putc 65
8763 *
8764 * Output:
8765 *
8766 * AA
8767 *
8768 */
8769
8770static VALUE
8771rb_io_putc(VALUE io, VALUE ch)
8772{
8773 VALUE str;
8774 if (RB_TYPE_P(ch, T_STRING)) {
8775 str = rb_str_substr(ch, 0, 1);
8776 }
8777 else {
8778 char c = NUM2CHR(ch);
8779 str = rb_str_new(&c, 1);
8780 }
8781 rb_io_write(io, str);
8782 return ch;
8783}
8784
8785#define forward(obj, id, argc, argv) \
8786 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8787#define forward_public(obj, id, argc, argv) \
8788 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8789#define forward_current(id, argc, argv) \
8790 forward_public(ARGF.current_file, id, argc, argv)
8791
8792/*
8793 * call-seq:
8794 * putc(int) -> int
8795 *
8796 * Equivalent to:
8797 *
8798 * $stdout.putc(int)
8799 *
8800 * See IO#putc for important information regarding multi-byte characters.
8801 *
8802 */
8803
8804static VALUE
8805rb_f_putc(VALUE recv, VALUE ch)
8806{
8807 VALUE r_stdout = rb_ractor_stdout();
8808 if (recv == r_stdout) {
8809 return rb_io_putc(recv, ch);
8810 }
8811 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8812}
8813
8814
8815int
8816rb_str_end_with_asciichar(VALUE str, int c)
8817{
8818 long len = RSTRING_LEN(str);
8819 const char *ptr = RSTRING_PTR(str);
8820 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8821 int n;
8822
8823 if (len == 0) return 0;
8824 if ((n = rb_enc_mbminlen(enc)) == 1) {
8825 return ptr[len - 1] == c;
8826 }
8827 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8828}
8829
8830static VALUE
8831io_puts_ary(VALUE ary, VALUE out, int recur)
8832{
8833 VALUE tmp;
8834 long i;
8835
8836 if (recur) {
8837 tmp = rb_str_new2("[...]");
8838 rb_io_puts(1, &tmp, out);
8839 return Qtrue;
8840 }
8841 ary = rb_check_array_type(ary);
8842 if (NIL_P(ary)) return Qfalse;
8843 for (i=0; i<RARRAY_LEN(ary); i++) {
8844 tmp = RARRAY_AREF(ary, i);
8845 rb_io_puts(1, &tmp, out);
8846 }
8847 return Qtrue;
8848}
8849
8850/*
8851 * call-seq:
8852 * puts(*objects) -> nil
8853 *
8854 * Writes the given +objects+ to the stream, which must be open for writing;
8855 * returns +nil+.\
8856 * Writes a newline after each that does not already end with a newline sequence.
8857 * If called without arguments, writes a newline.
8858 * See {Line IO}[rdoc-ref:IO@Line+IO].
8859 *
8860 * Note that each added newline is the character <tt>"\n"<//tt>,
8861 * not the output record separator (<tt>$\</tt>).
8862 *
8863 * Treatment for each object:
8864 *
8865 * - String: writes the string.
8866 * - Neither string nor array: writes <tt>object.to_s</tt>.
8867 * - Array: writes each element of the array; arrays may be nested.
8868 *
8869 * To keep these examples brief, we define this helper method:
8870 *
8871 * def show(*objects)
8872 * # Puts objects to file.
8873 * f = File.new('t.tmp', 'w+')
8874 * f.puts(objects)
8875 * # Return file content.
8876 * f.rewind
8877 * p f.read
8878 * f.close
8879 * end
8880 *
8881 * # Strings without newlines.
8882 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8883 * # Strings, some with newlines.
8884 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8885 *
8886 * # Neither strings nor arrays:
8887 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8888 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8889 *
8890 * # Array of strings.
8891 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8892 * # Nested arrays.
8893 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8894 *
8895 */
8896
8897 VALUE
8898rb_io_puts(int argc, const VALUE *argv, VALUE out)
8899{
8900 VALUE line, args[2];
8901
8902 /* if no argument given, print newline. */
8903 if (argc == 0) {
8904 rb_io_write(out, rb_default_rs);
8905 return Qnil;
8906 }
8907 for (int i = 0; i < argc; i++) {
8908 // Convert the argument to a string:
8909 if (RB_TYPE_P(argv[i], T_STRING)) {
8910 line = argv[i];
8911 }
8912 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8913 continue;
8914 }
8915 else {
8916 line = rb_obj_as_string(argv[i]);
8917 }
8918
8919 // Write the line:
8920 int n = 0;
8921 if (RSTRING_LEN(line) == 0) {
8922 args[n++] = rb_default_rs;
8923 }
8924 else {
8925 args[n++] = line;
8926 if (!rb_str_end_with_asciichar(line, '\n')) {
8927 args[n++] = rb_default_rs;
8928 }
8929 }
8930
8931 rb_io_writev(out, n, args);
8932 }
8933
8934 return Qnil;
8935}
8936
8937/*
8938 * call-seq:
8939 * puts(*objects) -> nil
8940 *
8941 * Equivalent to
8942 *
8943 * $stdout.puts(objects)
8944 */
8945
8946static VALUE
8947rb_f_puts(int argc, VALUE *argv, VALUE recv)
8948{
8949 VALUE r_stdout = rb_ractor_stdout();
8950 if (recv == r_stdout) {
8951 return rb_io_puts(argc, argv, recv);
8952 }
8953 return forward(r_stdout, rb_intern("puts"), argc, argv);
8954}
8955
8956static VALUE
8957rb_p_write(VALUE str)
8958{
8959 VALUE args[2];
8960 args[0] = str;
8961 args[1] = rb_default_rs;
8962 VALUE r_stdout = rb_ractor_stdout();
8963 if (RB_TYPE_P(r_stdout, T_FILE) &&
8964 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
8965 io_writev(2, args, r_stdout);
8966 }
8967 else {
8968 rb_io_writev(r_stdout, 2, args);
8969 }
8970 return Qnil;
8971}
8972
8973void
8974rb_p(VALUE obj) /* for debug print within C code */
8975{
8976 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
8977}
8978
8979static VALUE
8980rb_p_result(int argc, const VALUE *argv)
8981{
8982 VALUE ret = Qnil;
8983
8984 if (argc == 1) {
8985 ret = argv[0];
8986 }
8987 else if (argc > 1) {
8988 ret = rb_ary_new4(argc, argv);
8989 }
8990 VALUE r_stdout = rb_ractor_stdout();
8991 if (RB_TYPE_P(r_stdout, T_FILE)) {
8992 rb_uninterruptible(rb_io_flush, r_stdout);
8993 }
8994 return ret;
8995}
8996
8997/*
8998 * call-seq:
8999 * p(object) -> obj
9000 * p(*objects) -> array of objects
9001 * p -> nil
9002 *
9003 * For each object +obj+, executes:
9004 *
9005 * $stdout.write(obj.inspect, "\n")
9006 *
9007 * With one object given, returns the object;
9008 * with multiple objects given, returns an array containing the objects;
9009 * with no object given, returns +nil+.
9010 *
9011 * Examples:
9012 *
9013 * r = Range.new(0, 4)
9014 * p r # => 0..4
9015 * p [r, r, r] # => [0..4, 0..4, 0..4]
9016 * p # => nil
9017 *
9018 * Output:
9019 *
9020 * 0..4
9021 * [0..4, 0..4, 0..4]
9022 *
9023 * Kernel#p is designed for debugging purposes.
9024 * Ruby implementations may define Kernel#p to be uninterruptible
9025 * in whole or in part.
9026 * On CRuby, Kernel#p's writing of data is uninterruptible.
9027 */
9028
9029static VALUE
9030rb_f_p(int argc, VALUE *argv, VALUE self)
9031{
9032 int i;
9033 for (i=0; i<argc; i++) {
9034 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9035 rb_uninterruptible(rb_p_write, inspected);
9036 }
9037 return rb_p_result(argc, argv);
9038}
9039
9040/*
9041 * call-seq:
9042 * display(port = $>) -> nil
9043 *
9044 * Writes +self+ on the given port:
9045 *
9046 * 1.display
9047 * "cat".display
9048 * [ 4, 5, 6 ].display
9049 * puts
9050 *
9051 * Output:
9052 *
9053 * 1cat[4, 5, 6]
9054 *
9055 */
9056
9057static VALUE
9058rb_obj_display(int argc, VALUE *argv, VALUE self)
9059{
9060 VALUE out;
9061
9062 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9063 rb_io_write(out, self);
9064
9065 return Qnil;
9066}
9067
9068static int
9069rb_stderr_to_original_p(VALUE err)
9070{
9071 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9072}
9073
9074void
9075rb_write_error2(const char *mesg, long len)
9076{
9077 VALUE out = rb_ractor_stderr();
9078 if (rb_stderr_to_original_p(out)) {
9079#ifdef _WIN32
9080 if (isatty(fileno(stderr))) {
9081 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9082 }
9083#endif
9084 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9085 /* failed to write to stderr, what can we do? */
9086 return;
9087 }
9088 }
9089 else {
9090 rb_io_write(out, rb_str_new(mesg, len));
9091 }
9092}
9093
9094void
9095rb_write_error(const char *mesg)
9096{
9097 rb_write_error2(mesg, strlen(mesg));
9098}
9099
9100void
9101rb_write_error_str(VALUE mesg)
9102{
9103 VALUE out = rb_ractor_stderr();
9104 /* a stopgap measure for the time being */
9105 if (rb_stderr_to_original_p(out)) {
9106 size_t len = (size_t)RSTRING_LEN(mesg);
9107#ifdef _WIN32
9108 if (isatty(fileno(stderr))) {
9109 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9110 }
9111#endif
9112 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9113 RB_GC_GUARD(mesg);
9114 return;
9115 }
9116 }
9117 else {
9118 /* may unlock GVL, and */
9119 rb_io_write(out, mesg);
9120 }
9121}
9122
9123int
9124rb_stderr_tty_p(void)
9125{
9126 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9127 return isatty(fileno(stderr));
9128 return 0;
9129}
9130
9131static void
9132must_respond_to(ID mid, VALUE val, ID id)
9133{
9134 if (!rb_respond_to(val, mid)) {
9135 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9136 rb_id2str(id), rb_id2str(mid),
9137 rb_obj_class(val));
9138 }
9139}
9140
9141static void
9142stdin_setter(VALUE val, ID id, VALUE *ptr)
9143{
9144 rb_ractor_stdin_set(val);
9145}
9146
9147static VALUE
9148stdin_getter(ID id, VALUE *ptr)
9149{
9150 return rb_ractor_stdin();
9151}
9152
9153static void
9154stdout_setter(VALUE val, ID id, VALUE *ptr)
9155{
9156 must_respond_to(id_write, val, id);
9157 rb_ractor_stdout_set(val);
9158}
9159
9160static VALUE
9161stdout_getter(ID id, VALUE *ptr)
9162{
9163 return rb_ractor_stdout();
9164}
9165
9166static void
9167stderr_setter(VALUE val, ID id, VALUE *ptr)
9168{
9169 must_respond_to(id_write, val, id);
9170 rb_ractor_stderr_set(val);
9171}
9172
9173static VALUE
9174stderr_getter(ID id, VALUE *ptr)
9175{
9176 return rb_ractor_stderr();
9177}
9178
9179static VALUE
9180allocate_and_open_new_file(VALUE klass)
9181{
9182 VALUE self = io_alloc(klass);
9183 rb_io_make_open_file(self);
9184 return self;
9185}
9186
9187 VALUE
9188rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9189{
9190 int state;
9191 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9192 if (state) {
9193 /* if we raised an exception allocating an IO object, but the caller
9194 intended to transfer ownership of this FD to us, close the fd before
9195 raising the exception. Otherwise, we would leak a FD - the caller
9196 expects GC to close the file, but we never got around to assigning
9197 it to a rb_io. */
9198 if (!(mode & FMODE_EXTERNAL)) {
9199 maygvl_close(descriptor, 0);
9200 }
9201 rb_jump_tag(state);
9202 }
9203
9204
9205 rb_io_t *io = RFILE(self)->fptr;
9206 io->self = self;
9207 io->fd = descriptor;
9208 io->mode = mode;
9209
9210 /* At this point, Ruby fully owns the descriptor, and will close it when
9211 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9212 in the rest of this method. */
9213
9214 if (NIL_P(path)) {
9215 io->pathv = Qnil;
9216 }
9217 else {
9218 StringValue(path);
9219 io->pathv = rb_str_new_frozen(path);
9220 }
9221
9222 io->timeout = timeout;
9223
9224 if (encoding) {
9225 io->encs = *encoding;
9226 }
9227
9228 rb_update_max_fd(descriptor);
9229
9230 return self;
9231}
9232
9233static VALUE
9234prep_io(int fd, int fmode, VALUE klass, const char *path)
9235{
9236 VALUE path_value = Qnil;
9237 if (path) {
9238 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9239 }
9240
9241 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, NULL);
9242 rb_io_t*io = RFILE(self)->fptr;
9243
9244 if (!io_check_tty(io)) {
9245#ifdef __CYGWIN__
9246 io->mode |= FMODE_BINMODE;
9247 setmode(fd, O_BINARY);
9248#endif
9249 }
9250
9251 return self;
9252}
9253
9254 VALUE
9255rb_io_fdopen(int fd, int oflags, const char *path)
9256{
9257 VALUE klass = rb_cIO;
9258
9259 if (path && strcmp(path, "-")) klass = rb_cFile;
9260 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9261}
9262
9263static VALUE
9264prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9265{
9266 rb_io_t *fptr;
9267 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9268
9269 GetOpenFile(io, fptr);
9270 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
9271#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9272 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9273 if (fmode & FMODE_READABLE) {
9274 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
9275 }
9276#endif
9277 fptr->stdio_file = f;
9278
9279 return io;
9280}
9281
9282 VALUE
9283rb_io_prep_stdin(void)
9284{
9285 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9286}
9287
9288 VALUE
9289rb_io_prep_stdout(void)
9290{
9291 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9292}
9293
9294 VALUE
9295rb_io_prep_stderr(void)
9296{
9297 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9298}
9299
9300 FILE *
9301rb_io_stdio_file(rb_io_t *fptr)
9302{
9303 if (!fptr->stdio_file) {
9304 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9305 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9306 }
9307 return fptr->stdio_file;
9308}
9309
9310static inline void
9311rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9312{
9313 buf->ptr = NULL;
9314 buf->off = 0;
9315 buf->len = 0;
9316 buf->capa = 0;
9317}
9318
9319static inline rb_io_t *
9320rb_io_fptr_new(void)
9321{
9322 rb_io_t *fp = ALLOC(rb_io_t);
9323 fp->self = Qnil;
9324 fp->fd = -1;
9325 fp->stdio_file = NULL;
9326 fp->mode = 0;
9327 fp->pid = 0;
9328 fp->lineno = 0;
9329 fp->pathv = Qnil;
9330 fp->finalize = 0;
9331 rb_io_buffer_init(&fp->wbuf);
9332 rb_io_buffer_init(&fp->rbuf);
9333 rb_io_buffer_init(&fp->cbuf);
9334 fp->readconv = NULL;
9335 fp->writeconv = NULL;
9336 fp->writeconv_asciicompat = Qnil;
9337 fp->writeconv_pre_ecflags = 0;
9338 fp->writeconv_pre_ecopts = Qnil;
9339 fp->writeconv_initialized = 0;
9340 fp->tied_io_for_writing = 0;
9341 fp->encs.enc = NULL;
9342 fp->encs.enc2 = NULL;
9343 fp->encs.ecflags = 0;
9344 fp->encs.ecopts = Qnil;
9345 fp->write_lock = Qnil;
9346 fp->timeout = Qnil;
9347 return fp;
9348}
9349
9350 rb_io_t *
9351rb_io_make_open_file(VALUE obj)
9352{
9353 rb_io_t *fp = 0;
9354
9355 Check_Type(obj, T_FILE);
9356 if (RFILE(obj)->fptr) {
9357 rb_io_close(obj);
9358 rb_io_fptr_finalize(RFILE(obj)->fptr);
9359 RFILE(obj)->fptr = 0;
9360 }
9361 fp = rb_io_fptr_new();
9362 fp->self = obj;
9363 RFILE(obj)->fptr = fp;
9364 return fp;
9365}
9366
9367/*
9368 * call-seq:
9369 * IO.new(fd, mode = 'r', **opts) -> io
9370 *
9371 * Creates and returns a new \IO object (file stream) from a file descriptor.
9372 *
9373 * \IO.new may be useful for interaction with low-level libraries.
9374 * For higher-level interactions, it may be simpler to create
9375 * the file stream using File.open.
9376 *
9377 * Argument +fd+ must be a valid file descriptor (integer):
9378 *
9379 * path = 't.tmp'
9380 * fd = IO.sysopen(path) # => 3
9381 * IO.new(fd) # => #<IO:fd 3>
9382 *
9383 * The new \IO object does not inherit encoding
9384 * (because the integer file descriptor does not have an encoding):
9385 *
9386 * fd = IO.sysopen('t.rus', 'rb')
9387 * io = IO.new(fd)
9388 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9389 *
9390 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9391 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9392 *
9393 * IO.new(fd, 'w') # => #<IO:fd 3>
9394 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9395 *
9396 * Optional keyword arguments +opts+ specify:
9397 *
9398 * - {Open Options}[rdoc-ref:IO@Open+Options].
9399 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9400 *
9401 * Examples:
9402 *
9403 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9404 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9405 *
9406 */
9407
9408static VALUE
9409rb_io_initialize(int argc, VALUE *argv, VALUE io)
9410{
9411 VALUE fnum, vmode;
9412 rb_io_t *fp;
9413 int fd, fmode, oflags = O_RDONLY;
9414 struct rb_io_encoding convconfig;
9415 VALUE opt;
9416#if defined(HAVE_FCNTL) && defined(F_GETFL)
9417 int ofmode;
9418#else
9419 struct stat st;
9420#endif
9421
9422
9423 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9424 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9425
9426 fd = NUM2INT(fnum);
9427 if (rb_reserved_fd_p(fd)) {
9428 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9429 }
9430#if defined(HAVE_FCNTL) && defined(F_GETFL)
9431 oflags = fcntl(fd, F_GETFL);
9432 if (oflags == -1) rb_sys_fail(0);
9433#else
9434 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9435#endif
9436 rb_update_max_fd(fd);
9437#if defined(HAVE_FCNTL) && defined(F_GETFL)
9438 ofmode = rb_io_oflags_fmode(oflags);
9439 if (NIL_P(vmode)) {
9440 fmode = ofmode;
9441 }
9442 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9443 VALUE error = INT2FIX(EINVAL);
9444 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
9445 }
9446#endif
9447 VALUE path = Qnil;
9448
9449 if (!NIL_P(opt)) {
9450 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9451 fmode |= FMODE_EXTERNAL;
9452 }
9453
9454 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9455 if (!NIL_P(path)) {
9456 StringValue(path);
9457 path = rb_str_new_frozen(path);
9458 }
9459 }
9460
9461 MakeOpenFile(io, fp);
9462 fp->self = io;
9463 fp->fd = fd;
9464 fp->mode = fmode;
9465 fp->encs = convconfig;
9466 fp->pathv = path;
9467 fp->timeout = Qnil;
9468 clear_codeconv(fp);
9469 io_check_tty(fp);
9470 if (fileno(stdin) == fd)
9471 fp->stdio_file = stdin;
9472 else if (fileno(stdout) == fd)
9473 fp->stdio_file = stdout;
9474 else if (fileno(stderr) == fd)
9475 fp->stdio_file = stderr;
9476
9477 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9478 return io;
9479}
9480
9481/*
9482 * call-seq:
9483 * set_encoding_by_bom -> encoding or nil
9484 *
9485 * If the stream begins with a BOM
9486 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9487 * consumes the BOM and sets the external encoding accordingly;
9488 * returns the result encoding if found, or +nil+ otherwise:
9489 *
9490 * File.write('t.tmp', "\u{FEFF}abc")
9491 * io = File.open('t.tmp', 'rb')
9492 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9493 * io.close
9494 *
9495 * File.write('t.tmp', 'abc')
9496 * io = File.open('t.tmp', 'rb')
9497 * io.set_encoding_by_bom # => nil
9498 * io.close
9499 *
9500 * Raises an exception if the stream is not binmode
9501 * or its encoding has already been set.
9502 *
9503 */
9504
9505static VALUE
9506rb_io_set_encoding_by_bom(VALUE io)
9507{
9508 rb_io_t *fptr;
9509
9510 GetOpenFile(io, fptr);
9511 if (!(fptr->mode & FMODE_BINMODE)) {
9512 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9513 }
9514 if (fptr->encs.enc2) {
9515 rb_raise(rb_eArgError, "encoding conversion is set");
9516 }
9517 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9518 rb_raise(rb_eArgError, "encoding is set to %s already",
9519 rb_enc_name(fptr->encs.enc));
9520 }
9521 if (!io_set_encoding_by_bom(io)) return Qnil;
9522 return rb_enc_from_encoding(fptr->encs.enc);
9523}
9524
9525/*
9526 * call-seq:
9527 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9528 *
9529 * Opens the file at the given +path+ according to the given +mode+;
9530 * creates and returns a new File object for that file.
9531 *
9532 * The new File object is buffered mode (or non-sync mode), unless
9533 * +filename+ is a tty.
9534 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9535 *
9536 * Argument +path+ must be a valid file path:
9537 *
9538 * f = File.new('/etc/fstab')
9539 * f.close
9540 * f = File.new('t.txt')
9541 * f.close
9542 *
9543 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9544 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9545 *
9546 * f = File.new('t.tmp', 'w')
9547 * f.close
9548 * f = File.new('t.tmp', File::RDONLY)
9549 * f.close
9550 *
9551 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9552 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9553 *
9554 * f = File.new('t.tmp', File::CREAT, 0644)
9555 * f.close
9556 * f = File.new('t.tmp', File::CREAT, 0444)
9557 * f.close
9558 *
9559 * Optional keyword arguments +opts+ specify:
9560 *
9561 * - {Open Options}[rdoc-ref:IO@Open+Options].
9562 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9563 *
9564 */
9565
9566static VALUE
9567rb_file_initialize(int argc, VALUE *argv, VALUE io)
9568{
9569 if (RFILE(io)->fptr) {
9570 rb_raise(rb_eRuntimeError, "reinitializing File");
9571 }
9572 if (0 < argc && argc < 3) {
9573 VALUE fd = rb_check_to_int(argv[0]);
9574
9575 if (!NIL_P(fd)) {
9576 argv[0] = fd;
9577 return rb_io_initialize(argc, argv, io);
9578 }
9579 }
9580 rb_open_file(argc, argv, io);
9581
9582 return io;
9583}
9584
9585/* :nodoc: */
9586static VALUE
9587rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9588{
9589 if (rb_block_given_p()) {
9590 VALUE cname = rb_obj_as_string(klass);
9591
9592 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9593 cname, cname);
9594 }
9595 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9596}
9597
9598
9599/*
9600 * call-seq:
9601 * IO.for_fd(fd, mode = 'r', **opts) -> io
9602 *
9603 * Synonym for IO.new.
9604 *
9605 */
9606
9607static VALUE
9608rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9609{
9610 VALUE io = rb_obj_alloc(klass);
9611 rb_io_initialize(argc, argv, io);
9612 return io;
9613}
9614
9615/*
9616 * call-seq:
9617 * ios.autoclose? -> true or false
9618 *
9619 * Returns +true+ if the underlying file descriptor of _ios_ will be
9620 * closed at its finalization or at calling #close, otherwise +false+.
9621 */
9622
9623static VALUE
9624rb_io_autoclose_p(VALUE io)
9625{
9626 rb_io_t *fptr = RFILE(io)->fptr;
9627 rb_io_check_closed(fptr);
9628 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9629}
9630
9631/*
9632 * call-seq:
9633 * io.autoclose = bool -> true or false
9634 *
9635 * Sets auto-close flag.
9636 *
9637 * f = File.open(File::NULL)
9638 * IO.for_fd(f.fileno).close
9639 * f.gets # raises Errno::EBADF
9640 *
9641 * f = File.open(File::NULL)
9642 * g = IO.for_fd(f.fileno)
9643 * g.autoclose = false
9644 * g.close
9645 * f.gets # won't cause Errno::EBADF
9646 */
9647
9648static VALUE
9649rb_io_set_autoclose(VALUE io, VALUE autoclose)
9650{
9651 rb_io_t *fptr;
9652 GetOpenFile(io, fptr);
9653 if (!RTEST(autoclose))
9654 fptr->mode |= FMODE_EXTERNAL;
9655 else
9656 fptr->mode &= ~FMODE_EXTERNAL;
9657 return autoclose;
9658}
9659
9660static VALUE
9661io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9662{
9663 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9664
9665 if (!RB_TEST(result)) {
9666 return Qnil;
9667 }
9668
9669 int mask = RB_NUM2INT(result);
9670
9671 if (mask & event) {
9672 if (return_io)
9673 return io;
9674 else
9675 return result;
9676 }
9677 else {
9678 return Qfalse;
9679 }
9680}
9681
9682/*
9683 * call-seq:
9684 * io.wait_readable -> truthy or falsy
9685 * io.wait_readable(timeout) -> truthy or falsy
9686 *
9687 * Waits until IO is readable and returns a truthy value, or a falsy
9688 * value when times out. Returns a truthy value immediately when
9689 * buffered data is available.
9690 */
9691
9692static VALUE
9693io_wait_readable(int argc, VALUE *argv, VALUE io)
9694{
9695 rb_io_t *fptr;
9696
9697 RB_IO_POINTER(io, fptr);
9698 rb_io_check_readable(fptr);
9699
9700 if (rb_io_read_pending(fptr)) return Qtrue;
9701
9702 rb_check_arity(argc, 0, 1);
9703 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9704
9705 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9706}
9707
9708/*
9709 * call-seq:
9710 * io.wait_writable -> truthy or falsy
9711 * io.wait_writable(timeout) -> truthy or falsy
9712 *
9713 * Waits until IO is writable and returns a truthy value or a falsy
9714 * value when times out.
9715 */
9716static VALUE
9717io_wait_writable(int argc, VALUE *argv, VALUE io)
9718{
9719 rb_io_t *fptr;
9720
9721 RB_IO_POINTER(io, fptr);
9722 rb_io_check_writable(fptr);
9723
9724 rb_check_arity(argc, 0, 1);
9725 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9726
9727 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9728}
9729
9730/*
9731 * call-seq:
9732 * io.wait_priority -> truthy or falsy
9733 * io.wait_priority(timeout) -> truthy or falsy
9734 *
9735 * Waits until IO is priority and returns a truthy value or a falsy
9736 * value when times out. Priority data is sent and received using
9737 * the Socket::MSG_OOB flag and is typically limited to streams.
9738 */
9739static VALUE
9740io_wait_priority(int argc, VALUE *argv, VALUE io)
9741{
9742 rb_io_t *fptr = NULL;
9743
9744 RB_IO_POINTER(io, fptr);
9745 rb_io_check_readable(fptr);
9746
9747 if (rb_io_read_pending(fptr)) return Qtrue;
9748
9749 rb_check_arity(argc, 0, 1);
9750 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9751
9752 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9753}
9754
9755static int
9756wait_mode_sym(VALUE mode)
9757{
9758 if (mode == ID2SYM(rb_intern("r"))) {
9759 return RB_WAITFD_IN;
9760 }
9761 if (mode == ID2SYM(rb_intern("read"))) {
9762 return RB_WAITFD_IN;
9763 }
9764 if (mode == ID2SYM(rb_intern("readable"))) {
9765 return RB_WAITFD_IN;
9766 }
9767 if (mode == ID2SYM(rb_intern("w"))) {
9768 return RB_WAITFD_OUT;
9769 }
9770 if (mode == ID2SYM(rb_intern("write"))) {
9771 return RB_WAITFD_OUT;
9772 }
9773 if (mode == ID2SYM(rb_intern("writable"))) {
9774 return RB_WAITFD_OUT;
9775 }
9776 if (mode == ID2SYM(rb_intern("rw"))) {
9777 return RB_WAITFD_IN|RB_WAITFD_OUT;
9778 }
9779 if (mode == ID2SYM(rb_intern("read_write"))) {
9780 return RB_WAITFD_IN|RB_WAITFD_OUT;
9781 }
9782 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9783 return RB_WAITFD_IN|RB_WAITFD_OUT;
9784 }
9785
9786 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9787}
9788
9789static inline enum rb_io_event
9790io_event_from_value(VALUE value)
9791{
9792 int events = RB_NUM2INT(value);
9793
9794 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9795
9796 return events;
9797}
9798
9799/*
9800 * call-seq:
9801 * io.wait(events, timeout) -> event mask, false or nil
9802 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9803 *
9804 * Waits until the IO becomes ready for the specified events and returns the
9805 * subset of events that become ready, or a falsy value when times out.
9806 *
9807 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9808 * +IO::PRIORITY+.
9809 *
9810 * Returns an event mask (truthy value) immediately when buffered data is available.
9811 *
9812 * Optional parameter +mode+ is one of +:read+, +:write+, or
9813 * +:read_write+.
9814 */
9815
9816static VALUE
9817io_wait(int argc, VALUE *argv, VALUE io)
9818{
9819 VALUE timeout = Qundef;
9820 enum rb_io_event events = 0;
9821 int return_io = 0;
9822
9823 // The documented signature for this method is actually incorrect.
9824 // A single timeout is allowed in any position, and multiple symbols can be given.
9825 // Whether this is intentional or not, I don't know, and as such I consider this to
9826 // be a legacy/slow path.
9827 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9828 // We'd prefer to return the actual mask, but this form would return the io itself:
9829 return_io = 1;
9830
9831 // Slow/messy path:
9832 for (int i = 0; i < argc; i += 1) {
9833 if (RB_SYMBOL_P(argv[i])) {
9834 events |= wait_mode_sym(argv[i]);
9835 }
9836 else if (UNDEF_P(timeout)) {
9837 rb_time_interval(timeout = argv[i]);
9838 }
9839 else {
9840 rb_raise(rb_eArgError, "timeout given more than once");
9841 }
9842 }
9843
9844 if (UNDEF_P(timeout)) timeout = Qnil;
9845
9846 if (events == 0) {
9847 events = RUBY_IO_READABLE;
9848 }
9849 }
9850 else /* argc == 2 and neither are symbols */ {
9851 // This is the fast path:
9852 events = io_event_from_value(argv[0]);
9853 timeout = argv[1];
9854 }
9855
9856 if (events & RUBY_IO_READABLE) {
9857 rb_io_t *fptr = NULL;
9858 RB_IO_POINTER(io, fptr);
9859
9860 if (rb_io_read_pending(fptr)) {
9861 // This was the original behaviour:
9862 if (return_io) return Qtrue;
9863 // New behaviour always returns an event mask:
9864 else return RB_INT2NUM(RUBY_IO_READABLE);
9865 }
9866 }
9867
9868 return io_wait_event(io, events, timeout, return_io);
9869}
9870
9871static void
9872argf_mark(void *ptr)
9873{
9874 struct argf *p = ptr;
9875 rb_gc_mark(p->filename);
9876 rb_gc_mark(p->current_file);
9877 rb_gc_mark(p->argv);
9878 rb_gc_mark(p->inplace);
9879 rb_gc_mark(p->encs.ecopts);
9880}
9881
9882static size_t
9883argf_memsize(const void *ptr)
9884{
9885 const struct argf *p = ptr;
9886 size_t size = sizeof(*p);
9887 return size;
9888}
9889
9890static const rb_data_type_t argf_type = {
9891 "ARGF",
9892 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9893 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9894};
9895
9896static inline void
9897argf_init(struct argf *p, VALUE v)
9898{
9899 p->filename = Qnil;
9900 p->current_file = Qnil;
9901 p->lineno = 0;
9902 p->argv = v;
9903}
9904
9905static VALUE
9906argf_alloc(VALUE klass)
9907{
9908 struct argf *p;
9909 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9910
9911 argf_init(p, Qnil);
9912 return argf;
9913}
9914
9915#undef rb_argv
9916
9917/* :nodoc: */
9918static VALUE
9919argf_initialize(VALUE argf, VALUE argv)
9920{
9921 memset(&ARGF, 0, sizeof(ARGF));
9922 argf_init(&ARGF, argv);
9923
9924 return argf;
9925}
9926
9927/* :nodoc: */
9928static VALUE
9929argf_initialize_copy(VALUE argf, VALUE orig)
9930{
9931 if (!OBJ_INIT_COPY(argf, orig)) return argf;
9932 ARGF = argf_of(orig);
9933 ARGF.argv = rb_obj_dup(ARGF.argv);
9934 return argf;
9935}
9936
9937/*
9938 * call-seq:
9939 * ARGF.lineno = integer -> integer
9940 *
9941 * Sets the line number of ARGF as a whole to the given Integer.
9942 *
9943 * ARGF sets the line number automatically as you read data, so normally
9944 * you will not need to set it explicitly. To access the current line number
9945 * use ARGF.lineno.
9946 *
9947 * For example:
9948 *
9949 * ARGF.lineno #=> 0
9950 * ARGF.readline #=> "This is line 1\n"
9951 * ARGF.lineno #=> 1
9952 * ARGF.lineno = 0 #=> 0
9953 * ARGF.lineno #=> 0
9954 */
9955static VALUE
9956argf_set_lineno(VALUE argf, VALUE val)
9957{
9958 ARGF.lineno = NUM2INT(val);
9959 ARGF.last_lineno = ARGF.lineno;
9960 return val;
9961}
9962
9963/*
9964 * call-seq:
9965 * ARGF.lineno -> integer
9966 *
9967 * Returns the current line number of ARGF as a whole. This value
9968 * can be set manually with ARGF.lineno=.
9969 *
9970 * For example:
9971 *
9972 * ARGF.lineno #=> 0
9973 * ARGF.readline #=> "This is line 1\n"
9974 * ARGF.lineno #=> 1
9975 */
9976static VALUE
9977argf_lineno(VALUE argf)
9978{
9979 return INT2FIX(ARGF.lineno);
9980}
9981
9982static VALUE
9983argf_forward(int argc, VALUE *argv, VALUE argf)
9984{
9985 return forward_current(rb_frame_this_func(), argc, argv);
9986}
9987
9988#define next_argv() argf_next_argv(argf)
9989#define ARGF_GENERIC_INPUT_P() \
9990 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
9991#define ARGF_FORWARD(argc, argv) do {\
9992 if (ARGF_GENERIC_INPUT_P())\
9993 return argf_forward((argc), (argv), argf);\
9994} while (0)
9995#define NEXT_ARGF_FORWARD(argc, argv) do {\
9996 if (!next_argv()) return Qnil;\
9997 ARGF_FORWARD((argc), (argv));\
9998} while (0)
9999
10000static void
10001argf_close(VALUE argf)
10002{
10003 VALUE file = ARGF.current_file;
10004 if (file == rb_stdin) return;
10005 if (RB_TYPE_P(file, T_FILE)) {
10006 rb_io_set_write_io(file, Qnil);
10007 }
10008 io_close(file);
10009 ARGF.init_p = -1;
10010}
10011
10012static int
10013argf_next_argv(VALUE argf)
10014{
10015 char *fn;
10016 rb_io_t *fptr;
10017 int stdout_binmode = 0;
10018 int fmode;
10019
10020 VALUE r_stdout = rb_ractor_stdout();
10021
10022 if (RB_TYPE_P(r_stdout, T_FILE)) {
10023 GetOpenFile(r_stdout, fptr);
10024 if (fptr->mode & FMODE_BINMODE)
10025 stdout_binmode = 1;
10026 }
10027
10028 if (ARGF.init_p == 0) {
10029 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10030 ARGF.next_p = 1;
10031 }
10032 else {
10033 ARGF.next_p = -1;
10034 }
10035 ARGF.init_p = 1;
10036 }
10037 else {
10038 if (NIL_P(ARGF.argv)) {
10039 ARGF.next_p = -1;
10040 }
10041 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10042 ARGF.next_p = 1;
10043 }
10044 }
10045
10046 if (ARGF.next_p == 1) {
10047 if (ARGF.init_p == 1) argf_close(argf);
10048 retry:
10049 if (RARRAY_LEN(ARGF.argv) > 0) {
10050 VALUE filename = rb_ary_shift(ARGF.argv);
10051 FilePathValue(filename);
10052 ARGF.filename = filename;
10053 filename = rb_str_encode_ospath(filename);
10054 fn = StringValueCStr(filename);
10055 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10056 ARGF.current_file = rb_stdin;
10057 if (ARGF.inplace) {
10058 rb_warn("Can't do inplace edit for stdio; skipping");
10059 goto retry;
10060 }
10061 }
10062 else {
10063 VALUE write_io = Qnil;
10064 int fr = rb_sysopen(filename, O_RDONLY, 0);
10065
10066 if (ARGF.inplace) {
10067 struct stat st;
10068#ifndef NO_SAFE_RENAME
10069 struct stat st2;
10070#endif
10071 VALUE str;
10072 int fw;
10073
10074 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10075 rb_io_close(r_stdout);
10076 }
10077 fstat(fr, &st);
10078 str = filename;
10079 if (!NIL_P(ARGF.inplace)) {
10080 VALUE suffix = ARGF.inplace;
10081 str = rb_str_dup(str);
10082 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10083 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10084 rb_enc_get(suffix), 0, Qnil))) {
10085 rb_str_append(str, suffix);
10086 }
10087#ifdef NO_SAFE_RENAME
10088 (void)close(fr);
10089 (void)unlink(RSTRING_PTR(str));
10090 if (rename(fn, RSTRING_PTR(str)) < 0) {
10091 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10092 filename, str, strerror(errno));
10093 goto retry;
10094 }
10095 fr = rb_sysopen(str, O_RDONLY, 0);
10096#else
10097 if (rename(fn, RSTRING_PTR(str)) < 0) {
10098 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10099 filename, str, strerror(errno));
10100 close(fr);
10101 goto retry;
10102 }
10103#endif
10104 }
10105 else {
10106#ifdef NO_SAFE_RENAME
10107 rb_fatal("Can't do inplace edit without backup");
10108#else
10109 if (unlink(fn) < 0) {
10110 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10111 filename, strerror(errno));
10112 close(fr);
10113 goto retry;
10114 }
10115#endif
10116 }
10117 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10118#ifndef NO_SAFE_RENAME
10119 fstat(fw, &st2);
10120#ifdef HAVE_FCHMOD
10121 fchmod(fw, st.st_mode);
10122#else
10123 chmod(fn, st.st_mode);
10124#endif
10125 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10126 int err;
10127#ifdef HAVE_FCHOWN
10128 err = fchown(fw, st.st_uid, st.st_gid);
10129#else
10130 err = chown(fn, st.st_uid, st.st_gid);
10131#endif
10132 if (err && getuid() == 0 && st2.st_uid == 0) {
10133 const char *wkfn = RSTRING_PTR(filename);
10134 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10135 filename, str, strerror(errno));
10136 (void)close(fr);
10137 (void)close(fw);
10138 (void)unlink(wkfn);
10139 goto retry;
10140 }
10141 }
10142#endif
10143 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10144 rb_ractor_stdout_set(write_io);
10145 if (stdout_binmode) rb_io_binmode(rb_stdout);
10146 }
10147 fmode = FMODE_READABLE;
10148 if (!ARGF.binmode) {
10149 fmode |= DEFAULT_TEXTMODE;
10150 }
10151 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10152 if (!NIL_P(write_io)) {
10153 rb_io_set_write_io(ARGF.current_file, write_io);
10154 }
10155 RB_GC_GUARD(filename);
10156 }
10157 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10158 GetOpenFile(ARGF.current_file, fptr);
10159 if (ARGF.encs.enc) {
10160 fptr->encs = ARGF.encs;
10161 clear_codeconv(fptr);
10162 }
10163 else {
10164 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10165 if (!ARGF.binmode) {
10166 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
10167#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10168 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10169#endif
10170 }
10171 }
10172 ARGF.next_p = 0;
10173 }
10174 else {
10175 ARGF.next_p = 1;
10176 return FALSE;
10177 }
10178 }
10179 else if (ARGF.next_p == -1) {
10180 ARGF.current_file = rb_stdin;
10181 ARGF.filename = rb_str_new2("-");
10182 if (ARGF.inplace) {
10183 rb_warn("Can't do inplace edit for stdio");
10184 rb_ractor_stdout_set(orig_stdout);
10185 }
10186 }
10187 if (ARGF.init_p == -1) ARGF.init_p = 1;
10188 return TRUE;
10189}
10190
10191static VALUE
10192argf_getline(int argc, VALUE *argv, VALUE argf)
10193{
10194 VALUE line;
10195 long lineno = ARGF.lineno;
10196
10197 retry:
10198 if (!next_argv()) return Qnil;
10199 if (ARGF_GENERIC_INPUT_P()) {
10200 line = forward_current(idGets, argc, argv);
10201 }
10202 else {
10203 if (argc == 0 && rb_rs == rb_default_rs) {
10204 line = rb_io_gets(ARGF.current_file);
10205 }
10206 else {
10207 line = rb_io_getline(argc, argv, ARGF.current_file);
10208 }
10209 if (NIL_P(line) && ARGF.next_p != -1) {
10210 argf_close(argf);
10211 ARGF.next_p = 1;
10212 goto retry;
10213 }
10214 }
10215 if (!NIL_P(line)) {
10216 ARGF.lineno = ++lineno;
10217 ARGF.last_lineno = ARGF.lineno;
10218 }
10219 return line;
10220}
10221
10222static VALUE
10223argf_lineno_getter(ID id, VALUE *var)
10224{
10225 VALUE argf = *var;
10226 return INT2FIX(ARGF.last_lineno);
10227}
10228
10229static void
10230argf_lineno_setter(VALUE val, ID id, VALUE *var)
10231{
10232 VALUE argf = *var;
10233 int n = NUM2INT(val);
10234 ARGF.last_lineno = ARGF.lineno = n;
10235}
10236
10237void
10238rb_reset_argf_lineno(long n)
10239{
10240 ARGF.last_lineno = ARGF.lineno = n;
10241}
10242
10243static VALUE argf_gets(int, VALUE *, VALUE);
10244
10245/*
10246 * call-seq:
10247 * gets(sep=$/ [, getline_args]) -> string or nil
10248 * gets(limit [, getline_args]) -> string or nil
10249 * gets(sep, limit [, getline_args]) -> string or nil
10250 *
10251 * Returns (and assigns to <code>$_</code>) the next line from the list
10252 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10253 * no files are present on the command line. Returns +nil+ at end of
10254 * file. The optional argument specifies the record separator. The
10255 * separator is included with the contents of each record. A separator
10256 * of +nil+ reads the entire contents, and a zero-length separator
10257 * reads the input one paragraph at a time, where paragraphs are
10258 * divided by two consecutive newlines. If the first argument is an
10259 * integer, or optional second argument is given, the returning string
10260 * would not be longer than the given value in bytes. If multiple
10261 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10262 * the contents one file at a time.
10263 *
10264 * ARGV << "testfile"
10265 * print while gets
10266 *
10267 * <em>produces:</em>
10268 *
10269 * This is line one
10270 * This is line two
10271 * This is line three
10272 * And so on...
10273 *
10274 * The style of programming using <code>$_</code> as an implicit
10275 * parameter is gradually losing favor in the Ruby community.
10276 */
10277
10278static VALUE
10279rb_f_gets(int argc, VALUE *argv, VALUE recv)
10280{
10281 if (recv == argf) {
10282 return argf_gets(argc, argv, argf);
10283 }
10284 return forward(argf, idGets, argc, argv);
10285}
10286
10287/*
10288 * call-seq:
10289 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10290 * ARGF.gets(limit [, getline_args]) -> string or nil
10291 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10292 *
10293 * Returns the next line from the current file in ARGF.
10294 *
10295 * By default lines are assumed to be separated by <code>$/</code>;
10296 * to use a different character as a separator, supply it as a String
10297 * for the _sep_ argument.
10298 *
10299 * The optional _limit_ argument specifies how many characters of each line
10300 * to return. By default all characters are returned.
10301 *
10302 * See IO.readlines for details about getline_args.
10303 *
10304 */
10305static VALUE
10306argf_gets(int argc, VALUE *argv, VALUE argf)
10307{
10308 VALUE line;
10309
10310 line = argf_getline(argc, argv, argf);
10311 rb_lastline_set(line);
10312
10313 return line;
10314}
10315
10316 VALUE
10317rb_gets(void)
10318{
10319 VALUE line;
10320
10321 if (rb_rs != rb_default_rs) {
10322 return rb_f_gets(0, 0, argf);
10323 }
10324
10325 retry:
10326 if (!next_argv()) return Qnil;
10327 line = rb_io_gets(ARGF.current_file);
10328 if (NIL_P(line) && ARGF.next_p != -1) {
10329 rb_io_close(ARGF.current_file);
10330 ARGF.next_p = 1;
10331 goto retry;
10332 }
10333 rb_lastline_set(line);
10334 if (!NIL_P(line)) {
10335 ARGF.lineno++;
10336 ARGF.last_lineno = ARGF.lineno;
10337 }
10338
10339 return line;
10340}
10341
10342static VALUE argf_readline(int, VALUE *, VALUE);
10343
10344/*
10345 * call-seq:
10346 * readline(sep = $/, chomp: false) -> string
10347 * readline(limit, chomp: false) -> string
10348 * readline(sep, limit, chomp: false) -> string
10349 *
10350 * Equivalent to method Kernel#gets, except that it raises an exception
10351 * if called at end-of-stream:
10352 *
10353 * $ cat t.txt | ruby -e "p readlines; readline"
10354 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10355 * in `readline': end of file reached (EOFError)
10356 *
10357 * Optional keyword argument +chomp+ specifies whether line separators
10358 * are to be omitted.
10359 */
10360
10361static VALUE
10362rb_f_readline(int argc, VALUE *argv, VALUE recv)
10363{
10364 if (recv == argf) {
10365 return argf_readline(argc, argv, argf);
10366 }
10367 return forward(argf, rb_intern("readline"), argc, argv);
10368}
10369
10370
10371/*
10372 * call-seq:
10373 * ARGF.readline(sep=$/) -> string
10374 * ARGF.readline(limit) -> string
10375 * ARGF.readline(sep, limit) -> string
10376 *
10377 * Returns the next line from the current file in ARGF.
10378 *
10379 * By default lines are assumed to be separated by <code>$/</code>;
10380 * to use a different character as a separator, supply it as a String
10381 * for the _sep_ argument.
10382 *
10383 * The optional _limit_ argument specifies how many characters of each line
10384 * to return. By default all characters are returned.
10385 *
10386 * An EOFError is raised at the end of the file.
10387 */
10388static VALUE
10389argf_readline(int argc, VALUE *argv, VALUE argf)
10390{
10391 VALUE line;
10392
10393 if (!next_argv()) rb_eof_error();
10394 ARGF_FORWARD(argc, argv);
10395 line = argf_gets(argc, argv, argf);
10396 if (NIL_P(line)) {
10397 rb_eof_error();
10398 }
10399
10400 return line;
10401}
10402
10403static VALUE argf_readlines(int, VALUE *, VALUE);
10404
10405/*
10406 * call-seq:
10407 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10408 * readlines(limit, chomp: false, **enc_opts) -> array
10409 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10410 *
10411 * Returns an array containing the lines returned by calling
10412 * Kernel#gets until the end-of-stream is reached;
10413 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10414 *
10415 * With only string argument +sep+ given,
10416 * returns the remaining lines as determined by line separator +sep+,
10417 * or +nil+ if none;
10418 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10419 *
10420 * # Default separator.
10421 * $ cat t.txt | ruby -e "p readlines"
10422 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10423 *
10424 * # Specified separator.
10425 * $ cat t.txt | ruby -e "p readlines 'li'"
10426 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10427 *
10428 * # Get-all separator.
10429 * $ cat t.txt | ruby -e "p readlines nil"
10430 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10431 *
10432 * # Get-paragraph separator.
10433 * $ cat t.txt | ruby -e "p readlines ''"
10434 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10435 *
10436 * With only integer argument +limit+ given,
10437 * limits the number of bytes in the line;
10438 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10439 *
10440 * $cat t.txt | ruby -e "p readlines 10"
10441 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10442 *
10443 * $cat t.txt | ruby -e "p readlines 11"
10444 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10445 *
10446 * $cat t.txt | ruby -e "p readlines 12"
10447 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10448 *
10449 * With arguments +sep+ and +limit+ given, combines the two behaviors;
10450 * see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit].
10451 *
10452 * Optional keyword argument +chomp+ specifies whether line separators
10453 * are to be omitted:
10454 *
10455 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10456 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10457 *
10458 * Optional keyword arguments +enc_opts+ specify encoding options;
10459 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10460 *
10461 */
10462
10463static VALUE
10464rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10465{
10466 if (recv == argf) {
10467 return argf_readlines(argc, argv, argf);
10468 }
10469 return forward(argf, rb_intern("readlines"), argc, argv);
10470}
10471
10472/*
10473 * call-seq:
10474 * ARGF.readlines(sep = $/, chomp: false) -> array
10475 * ARGF.readlines(limit, chomp: false) -> array
10476 * ARGF.readlines(sep, limit, chomp: false) -> array
10477 *
10478 * ARGF.to_a(sep = $/, chomp: false) -> array
10479 * ARGF.to_a(limit, chomp: false) -> array
10480 * ARGF.to_a(sep, limit, chomp: false) -> array
10481 *
10482 * Reads each file in ARGF in its entirety, returning an Array containing
10483 * lines from the files. Lines are assumed to be separated by _sep_.
10484 *
10485 * lines = ARGF.readlines
10486 * lines[0] #=> "This is line one\n"
10487 *
10488 * See +IO.readlines+ for a full description of all options.
10489 */
10490static VALUE
10491argf_readlines(int argc, VALUE *argv, VALUE argf)
10492{
10493 long lineno = ARGF.lineno;
10494 VALUE lines, ary;
10495
10496 ary = rb_ary_new();
10497 while (next_argv()) {
10498 if (ARGF_GENERIC_INPUT_P()) {
10499 lines = forward_current(rb_intern("readlines"), argc, argv);
10500 }
10501 else {
10502 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10503 argf_close(argf);
10504 }
10505 ARGF.next_p = 1;
10506 rb_ary_concat(ary, lines);
10507 ARGF.lineno = lineno + RARRAY_LEN(ary);
10508 ARGF.last_lineno = ARGF.lineno;
10509 }
10510 ARGF.init_p = 0;
10511 return ary;
10512}
10513
10514/*
10515 * call-seq:
10516 * `command` -> string
10517 *
10518 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10519 * sets global variable <tt>$?</tt> to the process status.
10520 *
10521 * This method has potential security vulnerabilities if called with untrusted input;
10522 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10523 *
10524 * Examples:
10525 *
10526 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10527 * $ `echo oops && exit 99` # => "oops\n"
10528 * $ $? # => #<Process::Status: pid 17088 exit 99>
10529 * $ $?.status # => 99>
10530 *
10531 * The built-in syntax <tt>%x{...}</tt> uses this method.
10532 *
10533 */
10534
10535static VALUE
10536rb_f_backquote(VALUE obj, VALUE str)
10537{
10538 VALUE port;
10539 VALUE result;
10540 rb_io_t *fptr;
10541
10542 SafeStringValue(str);
10543 rb_last_status_clear();
10544 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10545 if (NIL_P(port)) return rb_str_new(0,0);
10546
10547 GetOpenFile(port, fptr);
10548 result = read_all(fptr, remain_size(fptr), Qnil);
10549 rb_io_close(port);
10550 rb_io_fptr_cleanup_all(fptr);
10551 RB_GC_GUARD(port);
10552
10553 return result;
10554}
10555
10556#ifdef HAVE_SYS_SELECT_H
10557#include <sys/select.h>
10558#endif
10559
10560static VALUE
10561select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10562{
10563 VALUE res, list;
10564 rb_fdset_t *rp, *wp, *ep;
10565 rb_io_t *fptr;
10566 long i;
10567 int max = 0, n;
10568 int pending = 0;
10569 struct timeval timerec;
10570
10571 if (!NIL_P(read)) {
10572 Check_Type(read, T_ARRAY);
10573 for (i=0; i<RARRAY_LEN(read); i++) {
10574 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10575 rb_fd_set(fptr->fd, &fds[0]);
10576 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10577 pending++;
10578 rb_fd_set(fptr->fd, &fds[3]);
10579 }
10580 if (max < fptr->fd) max = fptr->fd;
10581 }
10582 if (pending) { /* no blocking if there's buffered data */
10583 timerec.tv_sec = timerec.tv_usec = 0;
10584 tp = &timerec;
10585 }
10586 rp = &fds[0];
10587 }
10588 else
10589 rp = 0;
10590
10591 if (!NIL_P(write)) {
10592 Check_Type(write, T_ARRAY);
10593 for (i=0; i<RARRAY_LEN(write); i++) {
10594 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10595 GetOpenFile(write_io, fptr);
10596 rb_fd_set(fptr->fd, &fds[1]);
10597 if (max < fptr->fd) max = fptr->fd;
10598 }
10599 wp = &fds[1];
10600 }
10601 else
10602 wp = 0;
10603
10604 if (!NIL_P(except)) {
10605 Check_Type(except, T_ARRAY);
10606 for (i=0; i<RARRAY_LEN(except); i++) {
10607 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10608 VALUE write_io = GetWriteIO(io);
10609 GetOpenFile(io, fptr);
10610 rb_fd_set(fptr->fd, &fds[2]);
10611 if (max < fptr->fd) max = fptr->fd;
10612 if (io != write_io) {
10613 GetOpenFile(write_io, fptr);
10614 rb_fd_set(fptr->fd, &fds[2]);
10615 if (max < fptr->fd) max = fptr->fd;
10616 }
10617 }
10618 ep = &fds[2];
10619 }
10620 else {
10621 ep = 0;
10622 }
10623
10624 max++;
10625
10626 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10627 if (n < 0) {
10628 rb_sys_fail(0);
10629 }
10630 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10631
10632 res = rb_ary_new2(3);
10633 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10634 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10635 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10636
10637 if (rp) {
10638 list = RARRAY_AREF(res, 0);
10639 for (i=0; i< RARRAY_LEN(read); i++) {
10640 VALUE obj = rb_ary_entry(read, i);
10641 VALUE io = rb_io_get_io(obj);
10642 GetOpenFile(io, fptr);
10643 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10644 rb_fd_isset(fptr->fd, &fds[3])) {
10645 rb_ary_push(list, obj);
10646 }
10647 }
10648 }
10649
10650 if (wp) {
10651 list = RARRAY_AREF(res, 1);
10652 for (i=0; i< RARRAY_LEN(write); i++) {
10653 VALUE obj = rb_ary_entry(write, i);
10654 VALUE io = rb_io_get_io(obj);
10655 VALUE write_io = GetWriteIO(io);
10656 GetOpenFile(write_io, fptr);
10657 if (rb_fd_isset(fptr->fd, &fds[1])) {
10658 rb_ary_push(list, obj);
10659 }
10660 }
10661 }
10662
10663 if (ep) {
10664 list = RARRAY_AREF(res, 2);
10665 for (i=0; i< RARRAY_LEN(except); i++) {
10666 VALUE obj = rb_ary_entry(except, i);
10667 VALUE io = rb_io_get_io(obj);
10668 VALUE write_io = GetWriteIO(io);
10669 GetOpenFile(io, fptr);
10670 if (rb_fd_isset(fptr->fd, &fds[2])) {
10671 rb_ary_push(list, obj);
10672 }
10673 else if (io != write_io) {
10674 GetOpenFile(write_io, fptr);
10675 if (rb_fd_isset(fptr->fd, &fds[2])) {
10676 rb_ary_push(list, obj);
10677 }
10678 }
10679 }
10680 }
10681
10682 return res; /* returns an empty array on interrupt */
10683}
10684
10685 struct select_args {
10686 VALUE read, write, except;
10687 struct timeval *timeout;
10688 rb_fdset_t fdsets[4];
10689};
10690
10691static VALUE
10692select_call(VALUE arg)
10693{
10694 struct select_args *p = (struct select_args *)arg;
10695
10696 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10697}
10698
10699static VALUE
10700select_end(VALUE arg)
10701{
10702 struct select_args *p = (struct select_args *)arg;
10703 int i;
10704
10705 for (i = 0; i < numberof(p->fdsets); ++i)
10706 rb_fd_term(&p->fdsets[i]);
10707 return Qnil;
10708}
10709
10710static VALUE sym_normal, sym_sequential, sym_random,
10711 sym_willneed, sym_dontneed, sym_noreuse;
10712
10713#ifdef HAVE_POSIX_FADVISE
10714struct io_advise_struct {
10715 int fd;
10716 int advice;
10717 rb_off_t offset;
10718 rb_off_t len;
10719};
10720
10721static VALUE
10722io_advise_internal(void *arg)
10723{
10724 struct io_advise_struct *ptr = arg;
10725 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10726}
10727
10728static VALUE
10729io_advise_sym_to_const(VALUE sym)
10730{
10731#ifdef POSIX_FADV_NORMAL
10732 if (sym == sym_normal)
10733 return INT2NUM(POSIX_FADV_NORMAL);
10734#endif
10735
10736#ifdef POSIX_FADV_RANDOM
10737 if (sym == sym_random)
10738 return INT2NUM(POSIX_FADV_RANDOM);
10739#endif
10740
10741#ifdef POSIX_FADV_SEQUENTIAL
10742 if (sym == sym_sequential)
10743 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10744#endif
10745
10746#ifdef POSIX_FADV_WILLNEED
10747 if (sym == sym_willneed)
10748 return INT2NUM(POSIX_FADV_WILLNEED);
10749#endif
10750
10751#ifdef POSIX_FADV_DONTNEED
10752 if (sym == sym_dontneed)
10753 return INT2NUM(POSIX_FADV_DONTNEED);
10754#endif
10755
10756#ifdef POSIX_FADV_NOREUSE
10757 if (sym == sym_noreuse)
10758 return INT2NUM(POSIX_FADV_NOREUSE);
10759#endif
10760
10761 return Qnil;
10762}
10763
10764static VALUE
10765do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10766{
10767 int rv;
10768 struct io_advise_struct ias;
10769 VALUE num_adv;
10770
10771 num_adv = io_advise_sym_to_const(advice);
10772
10773 /*
10774 * The platform doesn't support this hint. We don't raise exception, instead
10775 * silently ignore it. Because IO::advise is only hint.
10776 */
10777 if (NIL_P(num_adv))
10778 return Qnil;
10779
10780 ias.fd = fptr->fd;
10781 ias.advice = NUM2INT(num_adv);
10782 ias.offset = offset;
10783 ias.len = len;
10784
10785 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
10786 if (rv && rv != ENOSYS) {
10787 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10788 it returns the error code. */
10789 VALUE message = rb_sprintf("%"PRIsVALUE" "
10790 "(%"PRI_OFFT_PREFIX"d, "
10791 "%"PRI_OFFT_PREFIX"d, "
10792 "%"PRIsVALUE")",
10793 fptr->pathv, offset, len, advice);
10794 rb_syserr_fail_str(rv, message);
10795 }
10796
10797 return Qnil;
10798}
10799
10800#endif /* HAVE_POSIX_FADVISE */
10801
10802static void
10803advice_arg_check(VALUE advice)
10804{
10805 if (!SYMBOL_P(advice))
10806 rb_raise(rb_eTypeError, "advice must be a Symbol");
10807
10808 if (advice != sym_normal &&
10809 advice != sym_sequential &&
10810 advice != sym_random &&
10811 advice != sym_willneed &&
10812 advice != sym_dontneed &&
10813 advice != sym_noreuse) {
10814 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10815 }
10816}
10817
10818/*
10819 * call-seq:
10820 * advise(advice, offset = 0, len = 0) -> nil
10821 *
10822 * Invokes Posix system call
10823 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10824 * which announces an intention to access data from the current file
10825 * in a particular manner.
10826 *
10827 * The arguments and results are platform-dependent.
10828 *
10829 * The relevant data is specified by:
10830 *
10831 * - +offset+: The offset of the first byte of data.
10832 * - +len+: The number of bytes to be accessed;
10833 * if +len+ is zero, or is larger than the number of bytes remaining,
10834 * all remaining bytes will be accessed.
10835 *
10836 * Argument +advice+ is one of the following symbols:
10837 *
10838 * - +:normal+: The application has no advice to give
10839 * about its access pattern for the specified data.
10840 * If no advice is given for an open file, this is the default assumption.
10841 * - +:sequential+: The application expects to access the specified data sequentially
10842 * (with lower offsets read before higher ones).
10843 * - +:random+: The specified data will be accessed in random order.
10844 * - +:noreuse+: The specified data will be accessed only once.
10845 * - +:willneed+: The specified data will be accessed in the near future.
10846 * - +:dontneed+: The specified data will not be accessed in the near future.
10847 *
10848 * Not implemented on all platforms.
10849 *
10850 */
10851static VALUE
10852rb_io_advise(int argc, VALUE *argv, VALUE io)
10853{
10854 VALUE advice, offset, len;
10855 rb_off_t off, l;
10856 rb_io_t *fptr;
10857
10858 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10859 advice_arg_check(advice);
10860
10861 io = GetWriteIO(io);
10862 GetOpenFile(io, fptr);
10863
10864 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10865 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10866
10867#ifdef HAVE_POSIX_FADVISE
10868 return do_io_advise(fptr, advice, off, l);
10869#else
10870 ((void)off, (void)l); /* Ignore all hint */
10871 return Qnil;
10872#endif
10873}
10874
10875/*
10876 * call-seq:
10877 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10878 *
10879 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10880 * which monitors multiple file descriptors,
10881 * waiting until one or more of the file descriptors
10882 * becomes ready for some class of I/O operation.
10883 *
10884 * Not implemented on all platforms.
10885 *
10886 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10887 * is an array of IO objects.
10888 *
10889 * Argument +timeout+ is an integer timeout interval in seconds.
10890 *
10891 * The method monitors the \IO objects given in all three arrays,
10892 * waiting for some to be ready;
10893 * returns a 3-element array whose elements are:
10894 *
10895 * - An array of the objects in +read_ios+ that are ready for reading.
10896 * - An array of the objects in +write_ios+ that are ready for writing.
10897 * - An array of the objects in +error_ios+ have pending exceptions.
10898 *
10899 * If no object becomes ready within the given +timeout+, +nil+ is returned.
10900 *
10901 * \IO.select peeks the buffer of \IO objects for testing readability.
10902 * If the \IO buffer is not empty, \IO.select immediately notifies
10903 * readability. This "peek" only happens for \IO objects. It does not
10904 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10905 *
10906 * The best way to use \IO.select is invoking it after non-blocking
10907 * methods such as #read_nonblock, #write_nonblock, etc. The methods
10908 * raise an exception which is extended by IO::WaitReadable or
10909 * IO::WaitWritable. The modules notify how the caller should wait
10910 * with \IO.select. If IO::WaitReadable is raised, the caller should
10911 * wait for reading. If IO::WaitWritable is raised, the caller should
10912 * wait for writing.
10913 *
10914 * So, blocking read (#readpartial) can be emulated using
10915 * #read_nonblock and \IO.select as follows:
10916 *
10917 * begin
10918 * result = io_like.read_nonblock(maxlen)
10919 * rescue IO::WaitReadable
10920 * IO.select([io_like])
10921 * retry
10922 * rescue IO::WaitWritable
10923 * IO.select(nil, [io_like])
10924 * retry
10925 * end
10926 *
10927 * Especially, the combination of non-blocking methods and \IO.select is
10928 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
10929 * has #to_io method to return underlying IO object. IO.select calls
10930 * #to_io to obtain the file descriptor to wait.
10931 *
10932 * This means that readability notified by \IO.select doesn't mean
10933 * readability from OpenSSL::SSL::SSLSocket object.
10934 *
10935 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
10936 * some data. \IO.select doesn't see the buffer. So \IO.select can
10937 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
10938 *
10939 * However, several more complicated situations exist.
10940 *
10941 * SSL is a protocol which is sequence of records.
10942 * The record consists of multiple bytes.
10943 * So, the remote side of SSL sends a partial record, IO.select
10944 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
10945 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
10946 *
10947 * Also, the remote side can request SSL renegotiation which forces
10948 * the local SSL engine to write some data.
10949 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
10950 * system call and it can block.
10951 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
10952 * IO::WaitWritable instead of blocking.
10953 * So, the caller should wait for ready for writability as above
10954 * example.
10955 *
10956 * The combination of non-blocking methods and \IO.select is also useful
10957 * for streams such as tty, pipe socket socket when multiple processes
10958 * read from a stream.
10959 *
10960 * Finally, Linux kernel developers don't guarantee that
10961 * readability of select(2) means readability of following read(2) even
10962 * for a single process;
10963 * see {select(2)}[https://linux.die.net/man/2/select]
10964 *
10965 * Invoking \IO.select before IO#readpartial works well as usual.
10966 * However it is not the best way to use \IO.select.
10967 *
10968 * The writability notified by select(2) doesn't show
10969 * how many bytes are writable.
10970 * IO#write method blocks until given whole string is written.
10971 * So, <tt>IO#write(two or more bytes)</tt> can block after
10972 * writability is notified by \IO.select. IO#write_nonblock is required
10973 * to avoid the blocking.
10974 *
10975 * Blocking write (#write) can be emulated using #write_nonblock and
10976 * IO.select as follows: IO::WaitReadable should also be rescued for
10977 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
10978 *
10979 * while 0 < string.bytesize
10980 * begin
10981 * written = io_like.write_nonblock(string)
10982 * rescue IO::WaitReadable
10983 * IO.select([io_like])
10984 * retry
10985 * rescue IO::WaitWritable
10986 * IO.select(nil, [io_like])
10987 * retry
10988 * end
10989 * string = string.byteslice(written..-1)
10990 * end
10991 *
10992 * Example:
10993 *
10994 * rp, wp = IO.pipe
10995 * mesg = "ping "
10996 * 100.times {
10997 * # IO.select follows IO#read. Not the best way to use IO.select.
10998 * rs, ws, = IO.select([rp], [wp])
10999 * if r = rs[0]
11000 * ret = r.read(5)
11001 * print ret
11002 * case ret
11003 * when /ping/
11004 * mesg = "pong\n"
11005 * when /pong/
11006 * mesg = "ping "
11007 * end
11008 * end
11009 * if w = ws[0]
11010 * w.write(mesg)
11011 * end
11012 * }
11013 *
11014 * Output:
11015 *
11016 * ping pong
11017 * ping pong
11018 * ping pong
11019 * (snipped)
11020 * ping
11021 *
11022 */
11023
11024static VALUE
11025rb_f_select(int argc, VALUE *argv, VALUE obj)
11026{
11027 VALUE scheduler = rb_fiber_scheduler_current();
11028 if (scheduler != Qnil) {
11029 // It's optionally supported.
11030 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11031 if (!UNDEF_P(result)) return result;
11032 }
11033
11034 VALUE timeout;
11035 struct select_args args;
11036 struct timeval timerec;
11037 int i;
11038
11039 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11040 if (NIL_P(timeout)) {
11041 args.timeout = 0;
11042 }
11043 else {
11044 timerec = rb_time_interval(timeout);
11045 args.timeout = &timerec;
11046 }
11047
11048 for (i = 0; i < numberof(args.fdsets); ++i)
11049 rb_fd_init(&args.fdsets[i]);
11050
11051 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11052}
11053
11054#ifdef IOCTL_REQ_TYPE
11055 typedef IOCTL_REQ_TYPE ioctl_req_t;
11056#else
11057 typedef int ioctl_req_t;
11058# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11059#endif
11060
11061#ifdef HAVE_IOCTL
11062struct ioctl_arg {
11063 int fd;
11064 ioctl_req_t cmd;
11065 long narg;
11066};
11067
11068static VALUE
11069nogvl_ioctl(void *ptr)
11070{
11071 struct ioctl_arg *arg = ptr;
11072
11073 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11074}
11075
11076static int
11077do_ioctl(int fd, ioctl_req_t cmd, long narg)
11078{
11079 int retval;
11080 struct ioctl_arg arg;
11081
11082 arg.fd = fd;
11083 arg.cmd = cmd;
11084 arg.narg = narg;
11085
11086 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
11087
11088 return retval;
11089}
11090#endif
11091
11092#define DEFAULT_IOCTL_NARG_LEN (256)
11093
11094#if defined(__linux__) && defined(_IOC_SIZE)
11095static long
11096linux_iocparm_len(ioctl_req_t cmd)
11097{
11098 long len;
11099
11100 if ((cmd & 0xFFFF0000) == 0) {
11101 /* legacy and unstructured ioctl number. */
11102 return DEFAULT_IOCTL_NARG_LEN;
11103 }
11104
11105 len = _IOC_SIZE(cmd);
11106
11107 /* paranoia check for silly drivers which don't keep ioctl convention */
11108 if (len < DEFAULT_IOCTL_NARG_LEN)
11109 len = DEFAULT_IOCTL_NARG_LEN;
11110
11111 return len;
11112}
11113#endif
11114
11115#ifdef HAVE_IOCTL
11116static long
11117ioctl_narg_len(ioctl_req_t cmd)
11118{
11119 long len;
11120
11121#ifdef IOCPARM_MASK
11122#ifndef IOCPARM_LEN
11123#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11124#endif
11125#endif
11126#ifdef IOCPARM_LEN
11127 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11128#elif defined(__linux__) && defined(_IOC_SIZE)
11129 len = linux_iocparm_len(cmd);
11130#else
11131 /* otherwise guess at what's safe */
11132 len = DEFAULT_IOCTL_NARG_LEN;
11133#endif
11134
11135 return len;
11136}
11137#endif
11138
11139#ifdef HAVE_FCNTL
11140#ifdef __linux__
11141typedef long fcntl_arg_t;
11142#else
11143/* posix */
11144typedef int fcntl_arg_t;
11145#endif
11146
11147static long
11148fcntl_narg_len(ioctl_req_t cmd)
11149{
11150 long len;
11151
11152 switch (cmd) {
11153#ifdef F_DUPFD
11154 case F_DUPFD:
11155 len = sizeof(fcntl_arg_t);
11156 break;
11157#endif
11158#ifdef F_DUP2FD /* bsd specific */
11159 case F_DUP2FD:
11160 len = sizeof(int);
11161 break;
11162#endif
11163#ifdef F_DUPFD_CLOEXEC /* linux specific */
11164 case F_DUPFD_CLOEXEC:
11165 len = sizeof(fcntl_arg_t);
11166 break;
11167#endif
11168#ifdef F_GETFD
11169 case F_GETFD:
11170 len = 1;
11171 break;
11172#endif
11173#ifdef F_SETFD
11174 case F_SETFD:
11175 len = sizeof(fcntl_arg_t);
11176 break;
11177#endif
11178#ifdef F_GETFL
11179 case F_GETFL:
11180 len = 1;
11181 break;
11182#endif
11183#ifdef F_SETFL
11184 case F_SETFL:
11185 len = sizeof(fcntl_arg_t);
11186 break;
11187#endif
11188#ifdef F_GETOWN
11189 case F_GETOWN:
11190 len = 1;
11191 break;
11192#endif
11193#ifdef F_SETOWN
11194 case F_SETOWN:
11195 len = sizeof(fcntl_arg_t);
11196 break;
11197#endif
11198#ifdef F_GETOWN_EX /* linux specific */
11199 case F_GETOWN_EX:
11200 len = sizeof(struct f_owner_ex);
11201 break;
11202#endif
11203#ifdef F_SETOWN_EX /* linux specific */
11204 case F_SETOWN_EX:
11205 len = sizeof(struct f_owner_ex);
11206 break;
11207#endif
11208#ifdef F_GETLK
11209 case F_GETLK:
11210 len = sizeof(struct flock);
11211 break;
11212#endif
11213#ifdef F_SETLK
11214 case F_SETLK:
11215 len = sizeof(struct flock);
11216 break;
11217#endif
11218#ifdef F_SETLKW
11219 case F_SETLKW:
11220 len = sizeof(struct flock);
11221 break;
11222#endif
11223#ifdef F_READAHEAD /* bsd specific */
11224 case F_READAHEAD:
11225 len = sizeof(int);
11226 break;
11227#endif
11228#ifdef F_RDAHEAD /* Darwin specific */
11229 case F_RDAHEAD:
11230 len = sizeof(int);
11231 break;
11232#endif
11233#ifdef F_GETSIG /* linux specific */
11234 case F_GETSIG:
11235 len = 1;
11236 break;
11237#endif
11238#ifdef F_SETSIG /* linux specific */
11239 case F_SETSIG:
11240 len = sizeof(fcntl_arg_t);
11241 break;
11242#endif
11243#ifdef F_GETLEASE /* linux specific */
11244 case F_GETLEASE:
11245 len = 1;
11246 break;
11247#endif
11248#ifdef F_SETLEASE /* linux specific */
11249 case F_SETLEASE:
11250 len = sizeof(fcntl_arg_t);
11251 break;
11252#endif
11253#ifdef F_NOTIFY /* linux specific */
11254 case F_NOTIFY:
11255 len = sizeof(fcntl_arg_t);
11256 break;
11257#endif
11258
11259 default:
11260 len = 256;
11261 break;
11262 }
11263
11264 return len;
11265}
11266#else /* HAVE_FCNTL */
11267static long
11268fcntl_narg_len(ioctl_req_t cmd)
11269{
11270 return 0;
11271}
11272#endif /* HAVE_FCNTL */
11273
11274#define NARG_SENTINEL 17
11275
11276static long
11277setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11278{
11279 long narg = 0;
11280 VALUE arg = *argp;
11281
11282 if (!RTEST(arg)) {
11283 narg = 0;
11284 }
11285 else if (FIXNUM_P(arg)) {
11286 narg = FIX2LONG(arg);
11287 }
11288 else if (arg == Qtrue) {
11289 narg = 1;
11290 }
11291 else {
11292 VALUE tmp = rb_check_string_type(arg);
11293
11294 if (NIL_P(tmp)) {
11295 narg = NUM2LONG(arg);
11296 }
11297 else {
11298 char *ptr;
11299 long len, slen;
11300
11301 *argp = arg = tmp;
11302 len = narg_len(cmd);
11303 rb_str_modify(arg);
11304
11305 slen = RSTRING_LEN(arg);
11306 /* expand for data + sentinel. */
11307 if (slen < len+1) {
11308 rb_str_resize(arg, len+1);
11309 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11310 slen = len+1;
11311 }
11312 /* a little sanity check here */
11313 ptr = RSTRING_PTR(arg);
11314 ptr[slen - 1] = NARG_SENTINEL;
11315 narg = (long)(SIGNED_VALUE)ptr;
11316 }
11317 }
11318
11319 return narg;
11320}
11321
11322static VALUE
11323finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11324{
11325 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11326 if (RB_TYPE_P(arg, T_STRING)) {
11327 char *ptr;
11328 long slen;
11329 RSTRING_GETMEM(arg, ptr, slen);
11330 if (ptr[slen-1] != NARG_SENTINEL)
11331 rb_raise(rb_eArgError, "return value overflowed string");
11332 ptr[slen-1] = '\0';
11333 }
11334
11335 return INT2NUM(retval);
11336}
11337
11338#ifdef HAVE_IOCTL
11339static VALUE
11340rb_ioctl(VALUE io, VALUE req, VALUE arg)
11341{
11342 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11343 rb_io_t *fptr;
11344 long narg;
11345 int retval;
11346
11347 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11348 GetOpenFile(io, fptr);
11349 retval = do_ioctl(fptr->fd, cmd, narg);
11350 return finish_narg(retval, arg, fptr);
11351}
11352
11353/*
11354 * call-seq:
11355 * ioctl(integer_cmd, argument) -> integer
11356 *
11357 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11358 * which issues a low-level command to an I/O device.
11359 *
11360 * Issues a low-level command to an I/O device.
11361 * The arguments and returned value are platform-dependent.
11362 * The effect of the call is platform-dependent.
11363 *
11364 * If argument +argument+ is an integer, it is passed directly;
11365 * if it is a string, it is interpreted as a binary sequence of bytes.
11366 *
11367 * Not implemented on all platforms.
11368 *
11369 */
11370
11371static VALUE
11372rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11373{
11374 VALUE req, arg;
11375
11376 rb_scan_args(argc, argv, "11", &req, &arg);
11377 return rb_ioctl(io, req, arg);
11378}
11379#else
11380#define rb_io_ioctl rb_f_notimplement
11381#endif
11382
11383#ifdef HAVE_FCNTL
11384struct fcntl_arg {
11385 int fd;
11386 int cmd;
11387 long narg;
11388};
11389
11390static VALUE
11391nogvl_fcntl(void *ptr)
11392{
11393 struct fcntl_arg *arg = ptr;
11394
11395#if defined(F_DUPFD)
11396 if (arg->cmd == F_DUPFD)
11397 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11398#endif
11399 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11400}
11401
11402static int
11403do_fcntl(int fd, int cmd, long narg)
11404{
11405 int retval;
11406 struct fcntl_arg arg;
11407
11408 arg.fd = fd;
11409 arg.cmd = cmd;
11410 arg.narg = narg;
11411
11412 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
11413 if (retval != -1) {
11414 switch (cmd) {
11415#if defined(F_DUPFD)
11416 case F_DUPFD:
11417#endif
11418#if defined(F_DUPFD_CLOEXEC)
11419 case F_DUPFD_CLOEXEC:
11420#endif
11421 rb_update_max_fd(retval);
11422 }
11423 }
11424
11425 return retval;
11426}
11427
11428static VALUE
11429rb_fcntl(VALUE io, VALUE req, VALUE arg)
11430{
11431 int cmd = NUM2INT(req);
11432 rb_io_t *fptr;
11433 long narg;
11434 int retval;
11435
11436 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11437 GetOpenFile(io, fptr);
11438 retval = do_fcntl(fptr->fd, cmd, narg);
11439 return finish_narg(retval, arg, fptr);
11440}
11441
11442/*
11443 * call-seq:
11444 * fcntl(integer_cmd, argument) -> integer
11445 *
11446 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11447 * which provides a mechanism for issuing low-level commands to control or query
11448 * a file-oriented I/O stream. Arguments and results are platform
11449 * dependent.
11450 *
11451 * If +argument+ is a number, its value is passed directly;
11452 * if it is a string, it is interpreted as a binary sequence of bytes.
11453 * (Array#pack might be a useful way to build this string.)
11454 *
11455 * Not implemented on all platforms.
11456 *
11457 */
11458
11459static VALUE
11460rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11461{
11462 VALUE req, arg;
11463
11464 rb_scan_args(argc, argv, "11", &req, &arg);
11465 return rb_fcntl(io, req, arg);
11466}
11467#else
11468#define rb_io_fcntl rb_f_notimplement
11469#endif
11470
11471#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11472/*
11473 * call-seq:
11474 * syscall(integer_callno, *arguments) -> integer
11475 *
11476 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11477 * which calls a specified function.
11478 *
11479 * Calls the operating system function identified by +integer_callno+;
11480 * returns the result of the function or raises SystemCallError if it failed.
11481 * The effect of the call is platform-dependent.
11482 * The arguments and returned value are platform-dependent.
11483 *
11484 * For each of +arguments+: if it is an integer, it is passed directly;
11485 * if it is a string, it is interpreted as a binary sequence of bytes.
11486 * There may be as many as nine such arguments.
11487 *
11488 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11489 * are platform-dependent.
11490 *
11491 * Note: Method +syscall+ is essentially unsafe and unportable.
11492 * The DL (Fiddle) library is preferred for safer and a bit
11493 * more portable programming.
11494 *
11495 * Not implemented on all platforms.
11496 *
11497 */
11498
11499static VALUE
11500rb_f_syscall(int argc, VALUE *argv, VALUE _)
11501{
11502 VALUE arg[8];
11503#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11504# define SYSCALL __syscall
11505# define NUM2SYSCALLID(x) NUM2LONG(x)
11506# define RETVAL2NUM(x) LONG2NUM(x)
11507# if SIZEOF_LONG == 8
11508 long num, retval = -1;
11509# elif SIZEOF_LONG_LONG == 8
11510 long long num, retval = -1;
11511# else
11512# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11513# endif
11514#elif defined(__linux__)
11515# define SYSCALL syscall
11516# define NUM2SYSCALLID(x) NUM2LONG(x)
11517# define RETVAL2NUM(x) LONG2NUM(x)
11518 /*
11519 * Linux man page says, syscall(2) function prototype is below.
11520 *
11521 * int syscall(int number, ...);
11522 *
11523 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11524 */
11525 long num, retval = -1;
11526#else
11527# define SYSCALL syscall
11528# define NUM2SYSCALLID(x) NUM2INT(x)
11529# define RETVAL2NUM(x) INT2NUM(x)
11530 int num, retval = -1;
11531#endif
11532 int i;
11533
11534 if (RTEST(ruby_verbose)) {
11535 rb_category_warning(RB_WARN_CATEGORY_DEPRECATED,
11536 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11537 }
11538
11539 if (argc == 0)
11540 rb_raise(rb_eArgError, "too few arguments for syscall");
11541 if (argc > numberof(arg))
11542 rb_raise(rb_eArgError, "too many arguments for syscall");
11543 num = NUM2SYSCALLID(argv[0]); ++argv;
11544 for (i = argc - 1; i--; ) {
11545 VALUE v = rb_check_string_type(argv[i]);
11546
11547 if (!NIL_P(v)) {
11548 SafeStringValue(v);
11549 rb_str_modify(v);
11550 arg[i] = (VALUE)StringValueCStr(v);
11551 }
11552 else {
11553 arg[i] = (VALUE)NUM2LONG(argv[i]);
11554 }
11555 }
11556
11557 switch (argc) {
11558 case 1:
11559 retval = SYSCALL(num);
11560 break;
11561 case 2:
11562 retval = SYSCALL(num, arg[0]);
11563 break;
11564 case 3:
11565 retval = SYSCALL(num, arg[0],arg[1]);
11566 break;
11567 case 4:
11568 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11569 break;
11570 case 5:
11571 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11572 break;
11573 case 6:
11574 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11575 break;
11576 case 7:
11577 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11578 break;
11579 case 8:
11580 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11581 break;
11582 }
11583
11584 if (retval == -1)
11585 rb_sys_fail(0);
11586 return RETVAL2NUM(retval);
11587#undef SYSCALL
11588#undef NUM2SYSCALLID
11589#undef RETVAL2NUM
11590}
11591#else
11592#define rb_f_syscall rb_f_notimplement
11593#endif
11594
11595static VALUE
11596io_new_instance(VALUE args)
11597{
11598 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11599}
11600
11601static rb_encoding *
11602find_encoding(VALUE v)
11603{
11604 rb_encoding *enc = rb_find_encoding(v);
11605 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11606 return enc;
11607}
11608
11609static void
11610io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11611{
11612 rb_encoding *enc, *enc2;
11613 int ecflags = fptr->encs.ecflags;
11614 VALUE ecopts, tmp;
11615
11616 if (!NIL_P(v2)) {
11617 enc2 = find_encoding(v1);
11618 tmp = rb_check_string_type(v2);
11619 if (!NIL_P(tmp)) {
11620 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11621 /* Special case - "-" => no transcoding */
11622 enc = enc2;
11623 enc2 = NULL;
11624 }
11625 else
11626 enc = find_encoding(v2);
11627 if (enc == enc2) {
11628 /* Special case - "-" => no transcoding */
11629 enc2 = NULL;
11630 }
11631 }
11632 else {
11633 enc = find_encoding(v2);
11634 if (enc == enc2) {
11635 /* Special case - "-" => no transcoding */
11636 enc2 = NULL;
11637 }
11638 }
11639 if (enc2 == rb_ascii8bit_encoding()) {
11640 /* If external is ASCII-8BIT, no transcoding */
11641 enc = enc2;
11642 enc2 = NULL;
11643 }
11644 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11645 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11646 }
11647 else {
11648 if (NIL_P(v1)) {
11649 /* Set to default encodings */
11650 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11651 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11652 ecopts = Qnil;
11653 }
11654 else {
11655 tmp = rb_check_string_type(v1);
11656 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11657 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11658 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11659 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11660 }
11661 else {
11662 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11663 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11664 ecopts = Qnil;
11665 }
11666 }
11667 }
11668 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11669 fptr->encs.enc = enc;
11670 fptr->encs.enc2 = enc2;
11671 fptr->encs.ecflags = ecflags;
11672 fptr->encs.ecopts = ecopts;
11673 clear_codeconv(fptr);
11674
11675}
11676
11677 struct io_encoding_set_args {
11678 rb_io_t *fptr;
11679 VALUE v1;
11680 VALUE v2;
11681 VALUE opt;
11682};
11683
11684static VALUE
11685io_encoding_set_v(VALUE v)
11686{
11687 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11688 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11689 return Qnil;
11690}
11691
11692static VALUE
11693pipe_pair_close(VALUE rw)
11694{
11695 VALUE *rwp = (VALUE *)rw;
11696 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11697}
11698
11699/*
11700 * call-seq:
11701 * IO.pipe(**opts) -> [read_io, write_io]
11702 * IO.pipe(enc, **opts) -> [read_io, write_io]
11703 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11704 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11705 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11706 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11707 *
11708 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11709 * connected to each other.
11710 *
11711 * If argument +enc_string+ is given, it must be a string containing one of:
11712 *
11713 * - The name of the encoding to be used as the external encoding.
11714 * - The colon-separated names of two encodings to be used as the external
11715 * and internal encodings.
11716 *
11717 * If argument +int_enc+ is given, it must be an Encoding object
11718 * or encoding name string that specifies the internal encoding to be used;
11719 * if argument +ext_enc+ is also given, it must be an Encoding object
11720 * or encoding name string that specifies the external encoding to be used.
11721 *
11722 * The string read from +read_io+ is tagged with the external encoding;
11723 * if an internal encoding is also specified, the string is converted
11724 * to, and tagged with, that encoding.
11725 *
11726 * If any encoding is specified,
11727 * optional hash arguments specify the conversion option.
11728 *
11729 * Optional keyword arguments +opts+ specify:
11730 *
11731 * - {Open Options}[rdoc-ref:IO@Open+Options].
11732 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11733 *
11734 * With no block given, returns the two endpoints in an array:
11735 *
11736 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11737 *
11738 * With a block given, calls the block with the two endpoints;
11739 * closes both endpoints and returns the value of the block:
11740 *
11741 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11742 *
11743 * Output:
11744 *
11745 * #<IO:fd 6>
11746 * #<IO:fd 7>
11747 *
11748 * Not available on all platforms.
11749 *
11750 * In the example below, the two processes close the ends of the pipe
11751 * that they are not using. This is not just a cosmetic nicety. The
11752 * read end of a pipe will not generate an end of file condition if
11753 * there are any writers with the pipe still open. In the case of the
11754 * parent process, the <tt>rd.read</tt> will never return if it
11755 * does not first issue a <tt>wr.close</tt>:
11756 *
11757 * rd, wr = IO.pipe
11758 *
11759 * if fork
11760 * wr.close
11761 * puts "Parent got: <#{rd.read}>"
11762 * rd.close
11763 * Process.wait
11764 * else
11765 * rd.close
11766 * puts 'Sending message to parent'
11767 * wr.write "Hi Dad"
11768 * wr.close
11769 * end
11770 *
11771 * <em>produces:</em>
11772 *
11773 * Sending message to parent
11774 * Parent got: <Hi Dad>
11775 *
11776 */
11777
11778static VALUE
11779rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11780{
11781 int pipes[2], state;
11782 VALUE r, w, args[3], v1, v2;
11783 VALUE opt;
11784 rb_io_t *fptr, *fptr2;
11785 struct io_encoding_set_args ies_args;
11786 int fmode = 0;
11787 VALUE ret;
11788
11789 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11790 if (rb_pipe(pipes) < 0)
11791 rb_sys_fail(0);
11792
11793 args[0] = klass;
11794 args[1] = INT2NUM(pipes[0]);
11795 args[2] = INT2FIX(O_RDONLY);
11796 r = rb_protect(io_new_instance, (VALUE)args, &state);
11797 if (state) {
11798 close(pipes[0]);
11799 close(pipes[1]);
11800 rb_jump_tag(state);
11801 }
11802 GetOpenFile(r, fptr);
11803
11804 ies_args.fptr = fptr;
11805 ies_args.v1 = v1;
11806 ies_args.v2 = v2;
11807 ies_args.opt = opt;
11808 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11809 if (state) {
11810 close(pipes[1]);
11811 io_close(r);
11812 rb_jump_tag(state);
11813 }
11814
11815 args[1] = INT2NUM(pipes[1]);
11816 args[2] = INT2FIX(O_WRONLY);
11817 w = rb_protect(io_new_instance, (VALUE)args, &state);
11818 if (state) {
11819 close(pipes[1]);
11820 if (!NIL_P(r)) rb_io_close(r);
11821 rb_jump_tag(state);
11822 }
11823 GetOpenFile(w, fptr2);
11824 rb_io_synchronized(fptr2);
11825
11826 extract_binmode(opt, &fmode);
11827
11828 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11829 rb_io_ascii8bit_binmode(r);
11830 rb_io_ascii8bit_binmode(w);
11831 }
11832
11833#if DEFAULT_TEXTMODE
11834 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11835 fptr->mode &= ~FMODE_TEXTMODE;
11836 setmode(fptr->fd, O_BINARY);
11837 }
11838#if RUBY_CRLF_ENVIRONMENT
11839 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
11840 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
11841 }
11842#endif
11843#endif
11844 fptr->mode |= fmode;
11845#if DEFAULT_TEXTMODE
11846 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11847 fptr2->mode &= ~FMODE_TEXTMODE;
11848 setmode(fptr2->fd, O_BINARY);
11849 }
11850#endif
11851 fptr2->mode |= fmode;
11852
11853 ret = rb_assoc_new(r, w);
11854 if (rb_block_given_p()) {
11855 VALUE rw[2];
11856 rw[0] = r;
11857 rw[1] = w;
11858 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11859 }
11860 return ret;
11861}
11862
11863 struct foreach_arg {
11864 int argc;
11865 VALUE *argv;
11866 VALUE io;
11867};
11868
11869static void
11870open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11871{
11872 VALUE path, v;
11873 VALUE vmode = Qnil, vperm = Qnil;
11874
11875 path = *argv++;
11876 argc--;
11877 FilePathValue(path);
11878 arg->io = 0;
11879 arg->argc = argc;
11880 arg->argv = argv;
11881 if (NIL_P(opt)) {
11882 vmode = INT2NUM(O_RDONLY);
11883 vperm = INT2FIX(0666);
11884 }
11885 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11886 int n;
11887
11888 v = rb_to_array_type(v);
11889 n = RARRAY_LENINT(v);
11890 rb_check_arity(n, 0, 3); /* rb_io_open */
11891 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11892 }
11893 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11894}
11895
11896static VALUE
11897io_s_foreach(VALUE v)
11898{
11899 struct getline_arg *arg = (void *)v;
11900 VALUE str;
11901
11902 if (arg->limit == 0)
11903 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
11904 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11905 rb_lastline_set(str);
11906 rb_yield(str);
11907 }
11908 rb_lastline_set(Qnil);
11909 return Qnil;
11910}
11911
11912/*
11913 * call-seq:
11914 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
11915 * IO.foreach(path, limit, **opts) {|line| block } -> nil
11916 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
11917 * IO.foreach(...) -> an_enumerator
11918 *
11919 * Calls the block with each successive line read from the stream.
11920 *
11921 * When called from class \IO (but not subclasses of \IO),
11922 * this method has potential security vulnerabilities if called with untrusted input;
11923 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11924 *
11925 * The first argument must be a string that is the path to a file.
11926 *
11927 * With only argument +path+ given, parses lines from the file at the given +path+,
11928 * as determined by the default line separator,
11929 * and calls the block with each successive line:
11930 *
11931 * File.foreach('t.txt') {|line| p line }
11932 *
11933 * Output: the same as above.
11934 *
11935 * For both forms, command and path, the remaining arguments are the same.
11936 *
11937 * With argument +sep+ given, parses lines as determined by that line separator
11938 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
11939 *
11940 * File.foreach('t.txt', 'li') {|line| p line }
11941 *
11942 * Output:
11943 *
11944 * "First li"
11945 * "ne\nSecond li"
11946 * "ne\n\nThird li"
11947 * "ne\nFourth li"
11948 * "ne\n"
11949 *
11950 * Each paragraph:
11951 *
11952 * File.foreach('t.txt', '') {|paragraph| p paragraph }
11953 *
11954 * Output:
11955 *
11956 * "First line\nSecond line\n\n"
11957 * "Third line\nFourth line\n"
11958 *
11959 * With argument +limit+ given, parses lines as determined by the default
11960 * line separator and the given line-length limit
11961 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
11962 *
11963 * File.foreach('t.txt', 7) {|line| p line }
11964 *
11965 * Output:
11966 *
11967 * "First l"
11968 * "ine\n"
11969 * "Second "
11970 * "line\n"
11971 * "\n"
11972 * "Third l"
11973 * "ine\n"
11974 * "Fourth l"
11975 * "line\n"
11976 *
11977 * With arguments +sep+ and +limit+ given,
11978 * parses lines as determined by the given
11979 * line separator and the given line-length limit
11980 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
11981 *
11982 * Optional keyword arguments +opts+ specify:
11983 *
11984 * - {Open Options}[rdoc-ref:IO@Open+Options].
11985 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11986 * - {Line Options}[rdoc-ref:IO@Line+IO].
11987 *
11988 * Returns an Enumerator if no block is given.
11989 *
11990 */
11991
11992static VALUE
11993rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
11994{
11995 VALUE opt;
11996 int orig_argc = argc;
11997 struct foreach_arg arg;
11998 struct getline_arg garg;
11999
12000 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12001 RETURN_ENUMERATOR(self, orig_argc, argv);
12002 extract_getline_args(argc-1, argv+1, &garg);
12003 open_key_args(self, argc, argv, opt, &arg);
12004 if (NIL_P(arg.io)) return Qnil;
12005 extract_getline_opts(opt, &garg);
12006 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12007 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12008}
12009
12010static VALUE
12011io_s_readlines(VALUE v)
12012{
12013 struct getline_arg *arg = (void *)v;
12014 return io_readlines(arg, arg->io);
12015}
12016
12017/*
12018 * call-seq:
12019 * IO.readlines(path, sep = $/, **opts) -> array
12020 * IO.readlines(path, limit, **opts) -> array
12021 * IO.readlines(path, sep, limit, **opts) -> array
12022 *
12023 * Returns an array of all lines read from the stream.
12024 *
12025 * When called from class \IO (but not subclasses of \IO),
12026 * this method has potential security vulnerabilities if called with untrusted input;
12027 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12028 *
12029 * The first argument must be a string that is the path to a file.
12030 *
12031 * With only argument +path+ given, parses lines from the file at the given +path+,
12032 * as determined by the default line separator,
12033 * and returns those lines in an array:
12034 *
12035 * IO.readlines('t.txt')
12036 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12037 *
12038 * With argument +sep+ given, parses lines as determined by that line separator
12039 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12040 *
12041 * # Ordinary separator.
12042 * IO.readlines('t.txt', 'li')
12043 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12044 * # Get-paragraphs separator.
12045 * IO.readlines('t.txt', '')
12046 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12047 * # Get-all separator.
12048 * IO.readlines('t.txt', nil)
12049 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12050 *
12051 * With argument +limit+ given, parses lines as determined by the default
12052 * line separator and the given line-length limit
12053 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
12054 *
12055 * IO.readlines('t.txt', 7)
12056 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12057 *
12058 * With arguments +sep+ and +limit+ given,
12059 * parses lines as determined by the given
12060 * line separator and the given line-length limit
12061 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
12062 *
12063 * Optional keyword arguments +opts+ specify:
12064 *
12065 * - {Open Options}[rdoc-ref:IO@Open+Options].
12066 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12067 * - {Line Options}[rdoc-ref:IO@Line+IO].
12068 *
12069 */
12070
12071static VALUE
12072rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12073{
12074 VALUE opt;
12075 struct foreach_arg arg;
12076 struct getline_arg garg;
12077
12078 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12079 extract_getline_args(argc-1, argv+1, &garg);
12080 open_key_args(io, argc, argv, opt, &arg);
12081 if (NIL_P(arg.io)) return Qnil;
12082 extract_getline_opts(opt, &garg);
12083 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12084 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12085}
12086
12087static VALUE
12088io_s_read(VALUE v)
12089{
12090 struct foreach_arg *arg = (void *)v;
12091 return io_read(arg->argc, arg->argv, arg->io);
12092}
12093
12094 struct seek_arg {
12095 VALUE io;
12096 VALUE offset;
12097 int mode;
12098};
12099
12100static VALUE
12101seek_before_access(VALUE argp)
12102{
12103 struct seek_arg *arg = (struct seek_arg *)argp;
12104 rb_io_binmode(arg->io);
12105 return rb_io_seek(arg->io, arg->offset, arg->mode);
12106}
12107
12108/*
12109 * call-seq:
12110 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12111 *
12112 * Opens the stream, reads and returns some or all of its content,
12113 * and closes the stream; returns +nil+ if no bytes were read.
12114 *
12115 * When called from class \IO (but not subclasses of \IO),
12116 * this method has potential security vulnerabilities if called with untrusted input;
12117 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12118 *
12119 * The first argument must be a string that is the path to a file.
12120 *
12121 * With only argument +path+ given, reads in text mode and returns the entire content
12122 * of the file at the given path:
12123 *
12124 * IO.read('t.txt')
12125 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12126 *
12127 * On Windows, text mode can terminate reading and leave bytes in the file
12128 * unread when encountering certain special bytes. Consider using
12129 * IO.binread if all bytes in the file should be read.
12130 *
12131 * With argument +length+, returns +length+ bytes if available:
12132 *
12133 * IO.read('t.txt', 7) # => "First l"
12134 * IO.read('t.txt', 700)
12135 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12136 *
12137 * With arguments +length+ and +offset+, returns +length+ bytes
12138 * if available, beginning at the given +offset+:
12139 *
12140 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12141 * IO.read('t.txt', 10, 200) # => nil
12142 *
12143 * Optional keyword arguments +opts+ specify:
12144 *
12145 * - {Open Options}[rdoc-ref:IO@Open+Options].
12146 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12147 *
12148 */
12149
12150static VALUE
12151rb_io_s_read(int argc, VALUE *argv, VALUE io)
12152{
12153 VALUE opt, offset;
12154 long off;
12155 struct foreach_arg arg;
12156
12157 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12158 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12159 rb_raise(rb_eArgError, "negative offset %ld given", off);
12160 }
12161 open_key_args(io, argc, argv, opt, &arg);
12162 if (NIL_P(arg.io)) return Qnil;
12163 if (!NIL_P(offset)) {
12164 struct seek_arg sarg;
12165 int state = 0;
12166 sarg.io = arg.io;
12167 sarg.offset = offset;
12168 sarg.mode = SEEK_SET;
12169 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12170 if (state) {
12171 rb_io_close(arg.io);
12172 rb_jump_tag(state);
12173 }
12174 if (arg.argc == 2) arg.argc = 1;
12175 }
12176 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12177}
12178
12179/*
12180 * call-seq:
12181 * IO.binread(path, length = nil, offset = 0) -> string or nil
12182 *
12183 * Behaves like IO.read, except that the stream is opened in binary mode
12184 * with ASCII-8BIT encoding.
12185 *
12186 * When called from class \IO (but not subclasses of \IO),
12187 * this method has potential security vulnerabilities if called with untrusted input;
12188 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12189 *
12190 */
12191
12192static VALUE
12193rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12194{
12195 VALUE offset;
12196 struct foreach_arg arg;
12197 enum {
12198 fmode = FMODE_READABLE|FMODE_BINMODE,
12199 oflags = O_RDONLY
12200#ifdef O_BINARY
12201 |O_BINARY
12202#endif
12203 };
12204 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12205
12206 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12207 FilePathValue(argv[0]);
12208 convconfig.enc = rb_ascii8bit_encoding();
12209 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12210 if (NIL_P(arg.io)) return Qnil;
12211 arg.argv = argv+1;
12212 arg.argc = (argc > 1) ? 1 : 0;
12213 if (!NIL_P(offset)) {
12214 struct seek_arg sarg;
12215 int state = 0;
12216 sarg.io = arg.io;
12217 sarg.offset = offset;
12218 sarg.mode = SEEK_SET;
12219 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12220 if (state) {
12221 rb_io_close(arg.io);
12222 rb_jump_tag(state);
12223 }
12224 }
12225 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12226}
12227
12228static VALUE
12229io_s_write0(VALUE v)
12230{
12231 struct write_arg *arg = (void *)v;
12232 return io_write(arg->io,arg->str,arg->nosync);
12233}
12234
12235static VALUE
12236io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12237{
12238 VALUE string, offset, opt;
12239 struct foreach_arg arg;
12240 struct write_arg warg;
12241
12242 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12243
12244 if (NIL_P(opt)) opt = rb_hash_new();
12245 else opt = rb_hash_dup(opt);
12246
12247
12248 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12249 int mode = O_WRONLY|O_CREAT;
12250#ifdef O_BINARY
12251 if (binary) mode |= O_BINARY;
12252#endif
12253 if (NIL_P(offset)) mode |= O_TRUNC;
12254 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12255 }
12256 open_key_args(klass, argc, argv, opt, &arg);
12257
12258#ifndef O_BINARY
12259 if (binary) rb_io_binmode_m(arg.io);
12260#endif
12261
12262 if (NIL_P(arg.io)) return Qnil;
12263 if (!NIL_P(offset)) {
12264 struct seek_arg sarg;
12265 int state = 0;
12266 sarg.io = arg.io;
12267 sarg.offset = offset;
12268 sarg.mode = SEEK_SET;
12269 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12270 if (state) {
12271 rb_io_close(arg.io);
12272 rb_jump_tag(state);
12273 }
12274 }
12275
12276 warg.io = arg.io;
12277 warg.str = string;
12278 warg.nosync = 0;
12279
12280 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12281}
12282
12283/*
12284 * call-seq:
12285 * IO.write(path, data, offset = 0, **opts) -> integer
12286 *
12287 * Opens the stream, writes the given +data+ to it,
12288 * and closes the stream; returns the number of bytes written.
12289 *
12290 * When called from class \IO (but not subclasses of \IO),
12291 * this method has potential security vulnerabilities if called with untrusted input;
12292 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12293 *
12294 * The first argument must be a string that is the path to a file.
12295 *
12296 * With only argument +path+ given, writes the given +data+ to the file at that path:
12297 *
12298 * IO.write('t.tmp', 'abc') # => 3
12299 * File.read('t.tmp') # => "abc"
12300 *
12301 * If +offset+ is zero (the default), the file is overwritten:
12302 *
12303 * IO.write('t.tmp', 'A') # => 1
12304 * File.read('t.tmp') # => "A"
12305 *
12306 * If +offset+ in within the file content, the file is partly overwritten:
12307 *
12308 * IO.write('t.tmp', 'abcdef') # => 3
12309 * File.read('t.tmp') # => "abcdef"
12310 * # Offset within content.
12311 * IO.write('t.tmp', '012', 2) # => 3
12312 * File.read('t.tmp') # => "ab012f"
12313 *
12314 * If +offset+ is outside the file content,
12315 * the file is padded with null characters <tt>"\u0000"</tt>:
12316 *
12317 * IO.write('t.tmp', 'xyz', 10) # => 3
12318 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12319 *
12320 * Optional keyword arguments +opts+ specify:
12321 *
12322 * - {Open Options}[rdoc-ref:IO@Open+Options].
12323 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12324 *
12325 */
12326
12327static VALUE
12328rb_io_s_write(int argc, VALUE *argv, VALUE io)
12329{
12330 return io_s_write(argc, argv, io, 0);
12331}
12332
12333/*
12334 * call-seq:
12335 * IO.binwrite(path, string, offset = 0) -> integer
12336 *
12337 * Behaves like IO.write, except that the stream is opened in binary mode
12338 * with ASCII-8BIT encoding.
12339 *
12340 * When called from class \IO (but not subclasses of \IO),
12341 * this method has potential security vulnerabilities if called with untrusted input;
12342 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12343 *
12344 */
12345
12346static VALUE
12347rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12348{
12349 return io_s_write(argc, argv, io, 1);
12350}
12351
12352 struct copy_stream_struct {
12353 VALUE src;
12354 VALUE dst;
12355 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12356 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12357
12358 rb_io_t *src_fptr;
12359 rb_io_t *dst_fptr;
12360 unsigned close_src : 1;
12361 unsigned close_dst : 1;
12362 int error_no;
12363 rb_off_t total;
12364 const char *syserr;
12365 const char *notimp;
12366 VALUE th;
12367 struct stat src_stat;
12368 struct stat dst_stat;
12369#ifdef HAVE_FCOPYFILE
12370 copyfile_state_t copyfile_state;
12371#endif
12372};
12373
12374static void *
12375exec_interrupts(void *arg)
12376{
12377 VALUE th = (VALUE)arg;
12378 rb_thread_execute_interrupts(th);
12379 return NULL;
12380}
12381
12382/*
12383 * returns TRUE if the preceding system call was interrupted
12384 * so we can continue. If the thread was interrupted, we
12385 * reacquire the GVL to execute interrupts before continuing.
12386 */
12387static int
12388maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12389{
12390 switch (errno) {
12391 case EINTR:
12392#if defined(ERESTART)
12393 case ERESTART:
12394#endif
12395 if (rb_thread_interrupted(stp->th)) {
12396 if (has_gvl)
12397 rb_thread_execute_interrupts(stp->th);
12398 else
12399 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12400 }
12401 return TRUE;
12402 }
12403 return FALSE;
12404}
12405
12406 struct fiber_scheduler_wait_for_arguments {
12407 VALUE scheduler;
12408
12409 rb_io_t *fptr;
12410 short events;
12411
12412 VALUE result;
12413};
12414
12415static void *
12416fiber_scheduler_wait_for(void * _arguments)
12417{
12418 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12419
12420 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12421
12422 return NULL;
12423}
12424
12425#if USE_POLL
12426# define IOWAIT_SYSCALL "poll"
12427STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12428STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12429static int
12430nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12431{
12432 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
12433 if (scheduler != Qnil) {
12434 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12435 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12436 return RTEST(args.result);
12437 }
12438
12439 int fd = fptr->fd;
12440 if (fd == -1) return 0;
12441
12442 struct pollfd fds;
12443
12444 fds.fd = fd;
12445 fds.events = events;
12446
12447 int timeout_milliseconds = -1;
12448
12449 if (timeout) {
12450 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12451 }
12452
12453 return poll(&fds, 1, timeout_milliseconds);
12454}
12455#else /* !USE_POLL */
12456# define IOWAIT_SYSCALL "select"
12457static int
12458nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12459{
12460 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
12461 if (scheduler != Qnil) {
12462 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12463 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12464 return RTEST(args.result);
12465 }
12466
12467 int fd = fptr->fd;
12468
12469 if (fd == -1) {
12470 errno = EBADF;
12471 return -1;
12472 }
12473
12474 rb_fdset_t fds;
12475 int ret;
12476
12477 rb_fd_init(&fds);
12478 rb_fd_set(fd, &fds);
12479
12480 switch (events) {
12481 case RB_WAITFD_IN:
12482 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12483 break;
12484 case RB_WAITFD_OUT:
12485 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12486 break;
12487 default:
12488 VM_UNREACHABLE(nogvl_wait_for);
12489 }
12490
12491 rb_fd_term(&fds);
12492
12493 // On timeout, this returns 0.
12494 return ret;
12495}
12496#endif /* !USE_POLL */
12497
12498static int
12499maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12500{
12501 int ret;
12502
12503 do {
12504 if (has_gvl) {
12505 ret = RB_NUM2INT(rb_io_wait(stp->src, RB_INT2NUM(RUBY_IO_READABLE), Qnil));
12506 }
12507 else {
12508 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12509 }
12510 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12511
12512 if (ret < 0) {
12513 stp->syserr = IOWAIT_SYSCALL;
12514 stp->error_no = errno;
12515 return ret;
12516 }
12517 return 0;
12518}
12519
12520static int
12521nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12522{
12523 int ret;
12524
12525 do {
12526 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12527 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12528
12529 if (ret < 0) {
12530 stp->syserr = IOWAIT_SYSCALL;
12531 stp->error_no = errno;
12532 return ret;
12533 }
12534 return 0;
12535}
12536
12537#ifdef USE_COPY_FILE_RANGE
12538
12539static ssize_t
12540simple_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)
12541{
12542#ifdef HAVE_COPY_FILE_RANGE
12543 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12544#else
12545 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12546#endif
12547}
12548
12549static int
12550nogvl_copy_file_range(struct copy_stream_struct *stp)
12551{
12552 ssize_t ss;
12553 rb_off_t src_size;
12554 rb_off_t copy_length, src_offset, *src_offset_ptr;
12555
12556 if (!S_ISREG(stp->src_stat.st_mode))
12557 return 0;
12558
12559 src_size = stp->src_stat.st_size;
12560 src_offset = stp->src_offset;
12561 if (src_offset >= (rb_off_t)0) {
12562 src_offset_ptr = &src_offset;
12563 }
12564 else {
12565 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12566 }
12567
12568 copy_length = stp->copy_length;
12569 if (copy_length < (rb_off_t)0) {
12570 if (src_offset < (rb_off_t)0) {
12571 rb_off_t current_offset;
12572 errno = 0;
12573 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12574 if (current_offset < (rb_off_t)0 && errno) {
12575 stp->syserr = "lseek";
12576 stp->error_no = errno;
12577 return (int)current_offset;
12578 }
12579 copy_length = src_size - current_offset;
12580 }
12581 else {
12582 copy_length = src_size - src_offset;
12583 }
12584 }
12585
12586 retry_copy_file_range:
12587# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12588 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12589 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12590# else
12591 ss = (ssize_t)copy_length;
12592# endif
12593 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12594 if (0 < ss) {
12595 stp->total += ss;
12596 copy_length -= ss;
12597 if (0 < copy_length) {
12598 goto retry_copy_file_range;
12599 }
12600 }
12601 if (ss < 0) {
12602 if (maygvl_copy_stream_continue_p(0, stp)) {
12603 goto retry_copy_file_range;
12604 }
12605 switch (errno) {
12606 case EINVAL:
12607 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12608 docker container) */
12609#ifdef ENOSYS
12610 case ENOSYS:
12611#endif
12612#ifdef EXDEV
12613 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12614#endif
12615 return 0;
12616 case EAGAIN:
12617#if EWOULDBLOCK != EAGAIN
12618 case EWOULDBLOCK:
12619#endif
12620 {
12621 int ret = nogvl_copy_stream_wait_write(stp);
12622 if (ret < 0) return ret;
12623 }
12624 goto retry_copy_file_range;
12625 case EBADF:
12626 {
12627 int e = errno;
12628 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12629
12630 if (flags != -1 && flags & O_APPEND) {
12631 return 0;
12632 }
12633 errno = e;
12634 }
12635 }
12636 stp->syserr = "copy_file_range";
12637 stp->error_no = errno;
12638 return (int)ss;
12639 }
12640 return 1;
12641}
12642#endif
12643
12644#ifdef HAVE_FCOPYFILE
12645static int
12646nogvl_fcopyfile(struct copy_stream_struct *stp)
12647{
12648 rb_off_t cur, ss = 0;
12649 const rb_off_t src_offset = stp->src_offset;
12650 int ret;
12651
12652 if (stp->copy_length >= (rb_off_t)0) {
12653 /* copy_length can't be specified in fcopyfile(3) */
12654 return 0;
12655 }
12656
12657 if (!S_ISREG(stp->src_stat.st_mode))
12658 return 0;
12659
12660 if (!S_ISREG(stp->dst_stat.st_mode))
12661 return 0;
12662 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12663 return 0;
12664 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12665 /* fcopyfile(3) appends src IO to dst IO and then truncates
12666 * dst IO to src IO's original size. */
12667 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12668 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12669 if (end > (rb_off_t)0) return 0;
12670 }
12671
12672 if (src_offset > (rb_off_t)0) {
12673 rb_off_t r;
12674
12675 /* get current offset */
12676 errno = 0;
12677 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12678 if (cur < (rb_off_t)0 && errno) {
12679 stp->error_no = errno;
12680 return 1;
12681 }
12682
12683 errno = 0;
12684 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12685 if (r < (rb_off_t)0 && errno) {
12686 stp->error_no = errno;
12687 return 1;
12688 }
12689 }
12690
12691 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12692 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12693 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12694
12695 if (ret == 0) { /* success */
12696 stp->total = ss;
12697 if (src_offset > (rb_off_t)0) {
12698 rb_off_t r;
12699 errno = 0;
12700 /* reset offset */
12701 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12702 if (r < (rb_off_t)0 && errno) {
12703 stp->error_no = errno;
12704 return 1;
12705 }
12706 }
12707 }
12708 else {
12709 switch (errno) {
12710 case ENOTSUP:
12711 case EPERM:
12712 case EINVAL:
12713 return 0;
12714 }
12715 stp->syserr = "fcopyfile";
12716 stp->error_no = errno;
12717 return (int)ret;
12718 }
12719 return 1;
12720}
12721#endif
12722
12723#ifdef HAVE_SENDFILE
12724
12725# ifdef __linux__
12726# define USE_SENDFILE
12727
12728# ifdef HAVE_SYS_SENDFILE_H
12729# include <sys/sendfile.h>
12730# endif
12731
12732static ssize_t
12733simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12734{
12735 return sendfile(out_fd, in_fd, offset, (size_t)count);
12736}
12737
12738# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12739/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12740 * without cpuset -l 0.
12741 */
12742# define USE_SENDFILE
12743
12744static ssize_t
12745simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12746{
12747 int r;
12748 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12749 rb_off_t sbytes;
12750# ifdef __APPLE__
12751 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12752 sbytes = count;
12753# else
12754 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12755# endif
12756 if (r != 0 && sbytes == 0) return r;
12757 if (offset) {
12758 *offset += sbytes;
12759 }
12760 else {
12761 lseek(in_fd, sbytes, SEEK_CUR);
12762 }
12763 return (ssize_t)sbytes;
12764}
12765
12766# endif
12767
12768#endif
12769
12770#ifdef USE_SENDFILE
12771static int
12772nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12773{
12774 ssize_t ss;
12775 rb_off_t src_size;
12776 rb_off_t copy_length;
12777 rb_off_t src_offset;
12778 int use_pread;
12779
12780 if (!S_ISREG(stp->src_stat.st_mode))
12781 return 0;
12782
12783 src_size = stp->src_stat.st_size;
12784#ifndef __linux__
12785 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12786 return 0;
12787#endif
12788
12789 src_offset = stp->src_offset;
12790 use_pread = src_offset >= (rb_off_t)0;
12791
12792 copy_length = stp->copy_length;
12793 if (copy_length < (rb_off_t)0) {
12794 if (use_pread)
12795 copy_length = src_size - src_offset;
12796 else {
12797 rb_off_t cur;
12798 errno = 0;
12799 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12800 if (cur < (rb_off_t)0 && errno) {
12801 stp->syserr = "lseek";
12802 stp->error_no = errno;
12803 return (int)cur;
12804 }
12805 copy_length = src_size - cur;
12806 }
12807 }
12808
12809 retry_sendfile:
12810# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12811 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12812 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12813# else
12814 ss = (ssize_t)copy_length;
12815# endif
12816 if (use_pread) {
12817 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12818 }
12819 else {
12820 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12821 }
12822 if (0 < ss) {
12823 stp->total += ss;
12824 copy_length -= ss;
12825 if (0 < copy_length) {
12826 goto retry_sendfile;
12827 }
12828 }
12829 if (ss < 0) {
12830 if (maygvl_copy_stream_continue_p(0, stp))
12831 goto retry_sendfile;
12832 switch (errno) {
12833 case EINVAL:
12834#ifdef ENOSYS
12835 case ENOSYS:
12836#endif
12837#ifdef EOPNOTSUP
12838 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12839 see also: [Feature #16965] */
12840 case EOPNOTSUP:
12841#endif
12842 return 0;
12843 case EAGAIN:
12844#if EWOULDBLOCK != EAGAIN
12845 case EWOULDBLOCK:
12846#endif
12847 {
12848 int ret;
12849#ifndef __linux__
12850 /*
12851 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12852 * select() reports regular files to always be "ready", so
12853 * there is no need to select() on it.
12854 * Other OSes may have the same limitation for sendfile() which
12855 * allow us to bypass maygvl_copy_stream_wait_read()...
12856 */
12857 ret = maygvl_copy_stream_wait_read(0, stp);
12858 if (ret < 0) return ret;
12859#endif
12860 ret = nogvl_copy_stream_wait_write(stp);
12861 if (ret < 0) return ret;
12862 }
12863 goto retry_sendfile;
12864 }
12865 stp->syserr = "sendfile";
12866 stp->error_no = errno;
12867 return (int)ss;
12868 }
12869 return 1;
12870}
12871#endif
12872
12873static ssize_t
12874maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12875{
12876 if (has_gvl)
12877 return rb_io_read_memory(fptr, buf, count);
12878 else
12879 return read(fptr->fd, buf, count);
12880}
12881
12882static ssize_t
12883maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12884{
12885 ssize_t ss;
12886 retry_read:
12887 if (offset < (rb_off_t)0) {
12888 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12889 }
12890 else {
12891 ss = pread(stp->src_fptr->fd, buf, len, offset);
12892 }
12893 if (ss == 0) {
12894 return 0;
12895 }
12896 if (ss < 0) {
12897 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12898 goto retry_read;
12899 switch (errno) {
12900 case EAGAIN:
12901#if EWOULDBLOCK != EAGAIN
12902 case EWOULDBLOCK:
12903#endif
12904 {
12905 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12906 if (ret < 0) return ret;
12907 }
12908 goto retry_read;
12909#ifdef ENOSYS
12910 case ENOSYS:
12911 stp->notimp = "pread";
12912 return ss;
12913#endif
12914 }
12915 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
12916 stp->error_no = errno;
12917 }
12918 return ss;
12919}
12920
12921static int
12922nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
12923{
12924 ssize_t ss;
12925 int off = 0;
12926 while (len) {
12927 ss = write(stp->dst_fptr->fd, buf+off, len);
12928 if (ss < 0) {
12929 if (maygvl_copy_stream_continue_p(0, stp))
12930 continue;
12931 if (io_again_p(errno)) {
12932 int ret = nogvl_copy_stream_wait_write(stp);
12933 if (ret < 0) return ret;
12934 continue;
12935 }
12936 stp->syserr = "write";
12937 stp->error_no = errno;
12938 return (int)ss;
12939 }
12940 off += (int)ss;
12941 len -= (int)ss;
12942 stp->total += ss;
12943 }
12944 return 0;
12945}
12946
12947static void
12948nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
12949{
12950 char buf[1024*16];
12951 size_t len;
12952 ssize_t ss;
12953 int ret;
12954 rb_off_t copy_length;
12955 rb_off_t src_offset;
12956 int use_eof;
12957 int use_pread;
12958
12959 copy_length = stp->copy_length;
12960 use_eof = copy_length < (rb_off_t)0;
12961 src_offset = stp->src_offset;
12962 use_pread = src_offset >= (rb_off_t)0;
12963
12964 if (use_pread && stp->close_src) {
12965 rb_off_t r;
12966 errno = 0;
12967 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12968 if (r < (rb_off_t)0 && errno) {
12969 stp->syserr = "lseek";
12970 stp->error_no = errno;
12971 return;
12972 }
12973 src_offset = (rb_off_t)-1;
12974 use_pread = 0;
12975 }
12976
12977 while (use_eof || 0 < copy_length) {
12978 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
12979 len = (size_t)copy_length;
12980 }
12981 else {
12982 len = sizeof(buf);
12983 }
12984 if (use_pread) {
12985 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
12986 if (0 < ss)
12987 src_offset += ss;
12988 }
12989 else {
12990 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
12991 }
12992 if (ss <= 0) /* EOF or error */
12993 return;
12994
12995 ret = nogvl_copy_stream_write(stp, buf, ss);
12996 if (ret < 0)
12997 return;
12998
12999 if (!use_eof)
13000 copy_length -= ss;
13001 }
13002}
13003
13004static void *
13005nogvl_copy_stream_func(void *arg)
13006{
13007 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13008#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13009 int ret;
13010#endif
13011
13012#ifdef USE_COPY_FILE_RANGE
13013 ret = nogvl_copy_file_range(stp);
13014 if (ret != 0)
13015 goto finish; /* error or success */
13016#endif
13017
13018#ifdef HAVE_FCOPYFILE
13019 ret = nogvl_fcopyfile(stp);
13020 if (ret != 0)
13021 goto finish; /* error or success */
13022#endif
13023
13024#ifdef USE_SENDFILE
13025 ret = nogvl_copy_stream_sendfile(stp);
13026 if (ret != 0)
13027 goto finish; /* error or success */
13028#endif
13029
13030 nogvl_copy_stream_read_write(stp);
13031
13032#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13033 finish:
13034#endif
13035 return 0;
13036}
13037
13038static VALUE
13039copy_stream_fallback_body(VALUE arg)
13040{
13041 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13042 const int buflen = 16*1024;
13043 VALUE n;
13044 VALUE buf = rb_str_buf_new(buflen);
13045 rb_off_t rest = stp->copy_length;
13046 rb_off_t off = stp->src_offset;
13047 ID read_method = id_readpartial;
13048
13049 if (!stp->src_fptr) {
13050 if (!rb_respond_to(stp->src, read_method)) {
13051 read_method = id_read;
13052 }
13053 }
13054
13055 while (1) {
13056 long numwrote;
13057 long l;
13058 if (stp->copy_length < (rb_off_t)0) {
13059 l = buflen;
13060 }
13061 else {
13062 if (rest == 0) {
13063 rb_str_resize(buf, 0);
13064 break;
13065 }
13066 l = buflen < rest ? buflen : (long)rest;
13067 }
13068 if (!stp->src_fptr) {
13069 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13070
13071 if (read_method == id_read && NIL_P(rc))
13072 break;
13073 }
13074 else {
13075 ssize_t ss;
13076 rb_str_resize(buf, buflen);
13077 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13078 rb_str_resize(buf, ss > 0 ? ss : 0);
13079 if (ss < 0)
13080 return Qnil;
13081 if (ss == 0)
13082 rb_eof_error();
13083 if (off >= (rb_off_t)0)
13084 off += ss;
13085 }
13086 n = rb_io_write(stp->dst, buf);
13087 numwrote = NUM2LONG(n);
13088 stp->total += numwrote;
13089 rest -= numwrote;
13090 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13091 break;
13092 }
13093 }
13094
13095 return Qnil;
13096}
13097
13098static VALUE
13099copy_stream_fallback(struct copy_stream_struct *stp)
13100{
13101 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13102 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13103 }
13104 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13105 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13106 rb_eEOFError, (VALUE)0);
13107 return Qnil;
13108}
13109
13110static VALUE
13111copy_stream_body(VALUE arg)
13112{
13113 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13114 VALUE src_io = stp->src, dst_io = stp->dst;
13115 const int common_oflags = 0
13116#ifdef O_NOCTTY
13117 | O_NOCTTY
13118#endif
13119 ;
13120
13121 stp->th = rb_thread_current();
13122
13123 stp->total = 0;
13124
13125 if (src_io == argf ||
13126 !(RB_TYPE_P(src_io, T_FILE) ||
13127 RB_TYPE_P(src_io, T_STRING) ||
13128 rb_respond_to(src_io, rb_intern("to_path")))) {
13129 stp->src_fptr = NULL;
13130 }
13131 else {
13132 int stat_ret;
13133 VALUE tmp_io = rb_io_check_io(src_io);
13134 if (!NIL_P(tmp_io)) {
13135 src_io = tmp_io;
13136 }
13137 else if (!RB_TYPE_P(src_io, T_FILE)) {
13138 VALUE args[2];
13139 FilePathValue(src_io);
13140 args[0] = src_io;
13141 args[1] = INT2NUM(O_RDONLY|common_oflags);
13142 src_io = rb_class_new_instance(2, args, rb_cFile);
13143 stp->src = src_io;
13144 stp->close_src = 1;
13145 }
13146 RB_IO_POINTER(src_io, stp->src_fptr);
13147 rb_io_check_byte_readable(stp->src_fptr);
13148
13149 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13150 if (stat_ret < 0) {
13151 stp->syserr = "fstat";
13152 stp->error_no = errno;
13153 return Qnil;
13154 }
13155 }
13156
13157 if (dst_io == argf ||
13158 !(RB_TYPE_P(dst_io, T_FILE) ||
13159 RB_TYPE_P(dst_io, T_STRING) ||
13160 rb_respond_to(dst_io, rb_intern("to_path")))) {
13161 stp->dst_fptr = NULL;
13162 }
13163 else {
13164 int stat_ret;
13165 VALUE tmp_io = rb_io_check_io(dst_io);
13166 if (!NIL_P(tmp_io)) {
13167 dst_io = GetWriteIO(tmp_io);
13168 }
13169 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13170 VALUE args[3];
13171 FilePathValue(dst_io);
13172 args[0] = dst_io;
13173 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13174 args[2] = INT2FIX(0666);
13175 dst_io = rb_class_new_instance(3, args, rb_cFile);
13176 stp->dst = dst_io;
13177 stp->close_dst = 1;
13178 }
13179 else {
13180 dst_io = GetWriteIO(dst_io);
13181 stp->dst = dst_io;
13182 }
13183 RB_IO_POINTER(dst_io, stp->dst_fptr);
13184 rb_io_check_writable(stp->dst_fptr);
13185
13186 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13187 if (stat_ret < 0) {
13188 stp->syserr = "fstat";
13189 stp->error_no = errno;
13190 return Qnil;
13191 }
13192 }
13193
13194#ifdef O_BINARY
13195 if (stp->src_fptr)
13196 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13197#endif
13198 if (stp->dst_fptr)
13199 io_ascii8bit_binmode(stp->dst_fptr);
13200
13201 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13202 size_t len = stp->src_fptr->rbuf.len;
13203 VALUE str;
13204 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13205 len = (size_t)stp->copy_length;
13206 }
13207 str = rb_str_buf_new(len);
13208 rb_str_resize(str,len);
13209 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13210 if (stp->dst_fptr) { /* IO or filename */
13211 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13212 rb_sys_fail_on_write(stp->dst_fptr);
13213 }
13214 else /* others such as StringIO */
13215 rb_io_write(dst_io, str);
13216 rb_str_resize(str, 0);
13217 stp->total += len;
13218 if (stp->copy_length >= (rb_off_t)0)
13219 stp->copy_length -= len;
13220 }
13221
13222 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13223 rb_raise(rb_eIOError, "flush failed");
13224 }
13225
13226 if (stp->copy_length == 0)
13227 return Qnil;
13228
13229 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13230 return copy_stream_fallback(stp);
13231 }
13232
13233 rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
13234 return Qnil;
13235}
13236
13237static VALUE
13238copy_stream_finalize(VALUE arg)
13239{
13240 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13241
13242#ifdef HAVE_FCOPYFILE
13243 if (stp->copyfile_state) {
13244 copyfile_state_free(stp->copyfile_state);
13245 }
13246#endif
13247
13248 if (stp->close_src) {
13249 rb_io_close_m(stp->src);
13250 }
13251 if (stp->close_dst) {
13252 rb_io_close_m(stp->dst);
13253 }
13254 if (stp->syserr) {
13255 rb_syserr_fail(stp->error_no, stp->syserr);
13256 }
13257 if (stp->notimp) {
13258 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13259 }
13260 return Qnil;
13261}
13262
13263/*
13264 * call-seq:
13265 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13266 *
13267 * Copies from the given +src+ to the given +dst+,
13268 * returning the number of bytes copied.
13269 *
13270 * - The given +src+ must be one of the following:
13271 *
13272 * - The path to a readable file, from which source data is to be read.
13273 * - An \IO-like object, opened for reading and capable of responding
13274 * to method +:readpartial+ or method +:read+.
13275 *
13276 * - The given +dst+ must be one of the following:
13277 *
13278 * - The path to a writable file, to which data is to be written.
13279 * - An \IO-like object, opened for writing and capable of responding
13280 * to method +:write+.
13281 *
13282 * The examples here use file <tt>t.txt</tt> as source:
13283 *
13284 * File.read('t.txt')
13285 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13286 * File.read('t.txt').size # => 47
13287 *
13288 * If only arguments +src+ and +dst+ are given,
13289 * the entire source stream is copied:
13290 *
13291 * # Paths.
13292 * IO.copy_stream('t.txt', 't.tmp') # => 47
13293 *
13294 * # IOs (recall that a File is also an IO).
13295 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13296 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13297 * IO.copy_stream(src_io, dst_io) # => 47
13298 * src_io.close
13299 * dst_io.close
13300 *
13301 * With argument +src_length+ a non-negative integer,
13302 * no more than that many bytes are copied:
13303 *
13304 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13305 * File.read('t.tmp') # => "First line"
13306 *
13307 * With argument +src_offset+ also given,
13308 * the source stream is read beginning at that offset:
13309 *
13310 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13311 * IO.read('t.tmp') # => "Second line"
13312 *
13313 */
13314static VALUE
13315rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13316{
13317 VALUE src, dst, length, src_offset;
13318 struct copy_stream_struct st;
13319
13320 MEMZERO(&st, struct copy_stream_struct, 1);
13321
13322 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13323
13324 st.src = src;
13325 st.dst = dst;
13326
13327 st.src_fptr = NULL;
13328 st.dst_fptr = NULL;
13329
13330 if (NIL_P(length))
13331 st.copy_length = (rb_off_t)-1;
13332 else
13333 st.copy_length = NUM2OFFT(length);
13334
13335 if (NIL_P(src_offset))
13336 st.src_offset = (rb_off_t)-1;
13337 else
13338 st.src_offset = NUM2OFFT(src_offset);
13339
13340 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13341
13342 return OFFT2NUM(st.total);
13343}
13344
13345/*
13346 * call-seq:
13347 * external_encoding -> encoding or nil
13348 *
13349 * Returns the Encoding object that represents the encoding of the stream,
13350 * or +nil+ if the stream is in write mode and no encoding is specified.
13351 *
13352 * See {Encodings}[rdoc-ref:File@Encodings].
13353 *
13354 */
13355
13356static VALUE
13357rb_io_external_encoding(VALUE io)
13358{
13359 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13360
13361 if (fptr->encs.enc2) {
13362 return rb_enc_from_encoding(fptr->encs.enc2);
13363 }
13364 if (fptr->mode & FMODE_WRITABLE) {
13365 if (fptr->encs.enc)
13366 return rb_enc_from_encoding(fptr->encs.enc);
13367 return Qnil;
13368 }
13369 return rb_enc_from_encoding(io_read_encoding(fptr));
13370}
13371
13372/*
13373 * call-seq:
13374 * internal_encoding -> encoding or nil
13375 *
13376 * Returns the Encoding object that represents the encoding of the internal string,
13377 * if conversion is specified,
13378 * or +nil+ otherwise.
13379 *
13380 * See {Encodings}[rdoc-ref:File@Encodings].
13381 *
13382 */
13383
13384static VALUE
13385rb_io_internal_encoding(VALUE io)
13386{
13387 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13388
13389 if (!fptr->encs.enc2) return Qnil;
13390 return rb_enc_from_encoding(io_read_encoding(fptr));
13391}
13392
13393/*
13394 * call-seq:
13395 * set_encoding(ext_enc) -> self
13396 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13397 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13398 *
13399 * See {Encodings}[rdoc-ref:File@Encodings].
13400 *
13401 * Argument +ext_enc+, if given, must be an Encoding object
13402 * or a String with the encoding name;
13403 * it is assigned as the encoding for the stream.
13404 *
13405 * Argument +int_enc+, if given, must be an Encoding object
13406 * or a String with the encoding name;
13407 * it is assigned as the encoding for the internal string.
13408 *
13409 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13410 * containing two colon-separated encoding names;
13411 * corresponding Encoding objects are assigned as the external
13412 * and internal encodings for the stream.
13413 *
13414 * If the external encoding of a string is binary/ASCII-8BIT,
13415 * the internal encoding of the string is set to nil, since no
13416 * transcoding is needed.
13417 *
13418 * Optional keyword arguments +enc_opts+ specify
13419 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13420 *
13421 */
13422
13423static VALUE
13424rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13425{
13426 rb_io_t *fptr;
13427 VALUE v1, v2, opt;
13428
13429 if (!RB_TYPE_P(io, T_FILE)) {
13430 return forward(io, id_set_encoding, argc, argv);
13431 }
13432
13433 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13434 GetOpenFile(io, fptr);
13435 io_encoding_set(fptr, v1, v2, opt);
13436 return io;
13437}
13438
13439void
13440rb_stdio_set_default_encoding(void)
13441{
13442 VALUE val = Qnil;
13443
13444#ifdef _WIN32
13445 if (isatty(fileno(stdin))) {
13446 rb_encoding *external = rb_locale_encoding();
13447 rb_encoding *internal = rb_default_internal_encoding();
13448 if (!internal) internal = rb_default_external_encoding();
13449 io_encoding_set(RFILE(rb_stdin)->fptr,
13450 rb_enc_from_encoding(external),
13451 rb_enc_from_encoding(internal),
13452 Qnil);
13453 }
13454 else
13455#endif
13456 rb_io_set_encoding(1, &val, rb_stdin);
13457 rb_io_set_encoding(1, &val, rb_stdout);
13458 rb_io_set_encoding(1, &val, rb_stderr);
13459}
13460
13461static inline int
13462global_argf_p(VALUE arg)
13463{
13464 return arg == argf;
13465}
13466
13467typedef VALUE (*argf_encoding_func)(VALUE io);
13468
13469static VALUE
13470argf_encoding(VALUE argf, argf_encoding_func func)
13471{
13472 if (!RTEST(ARGF.current_file)) {
13473 return rb_enc_default_external();
13474 }
13475 return func(rb_io_check_io(ARGF.current_file));
13476}
13477
13478/*
13479 * call-seq:
13480 * ARGF.external_encoding -> encoding
13481 *
13482 * Returns the external encoding for files read from ARGF as an Encoding
13483 * object. The external encoding is the encoding of the text as stored in a
13484 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13485 * represent this text within Ruby.
13486 *
13487 * To set the external encoding use ARGF.set_encoding.
13488 *
13489 * For example:
13490 *
13491 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13492 *
13493 */
13494static VALUE
13495argf_external_encoding(VALUE argf)
13496{
13497 return argf_encoding(argf, rb_io_external_encoding);
13498}
13499
13500/*
13501 * call-seq:
13502 * ARGF.internal_encoding -> encoding
13503 *
13504 * Returns the internal encoding for strings read from ARGF as an
13505 * Encoding object.
13506 *
13507 * If ARGF.set_encoding has been called with two encoding names, the second
13508 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13509 * value is returned. Failing that, if a default external encoding was
13510 * specified on the command-line, that value is used. If the encoding is
13511 * unknown, +nil+ is returned.
13512 */
13513static VALUE
13514argf_internal_encoding(VALUE argf)
13515{
13516 return argf_encoding(argf, rb_io_internal_encoding);
13517}
13518
13519/*
13520 * call-seq:
13521 * ARGF.set_encoding(ext_enc) -> ARGF
13522 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13523 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13524 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13525 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13526 *
13527 * If single argument is specified, strings read from ARGF are tagged with
13528 * the encoding specified.
13529 *
13530 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13531 * the read string is converted from the first encoding (external encoding)
13532 * to the second encoding (internal encoding), then tagged with the second
13533 * encoding.
13534 *
13535 * If two arguments are specified, they must be encoding objects or encoding
13536 * names. Again, the first specifies the external encoding; the second
13537 * specifies the internal encoding.
13538 *
13539 * If the external encoding and the internal encoding are specified, the
13540 * optional Hash argument can be used to adjust the conversion process. The
13541 * structure of this hash is explained in the String#encode documentation.
13542 *
13543 * For example:
13544 *
13545 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13546 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13547 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13548 * # to UTF-8.
13549 */
13550static VALUE
13551argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13552{
13553 rb_io_t *fptr;
13554
13555 if (!next_argv()) {
13556 rb_raise(rb_eArgError, "no stream to set encoding");
13557 }
13558 rb_io_set_encoding(argc, argv, ARGF.current_file);
13559 GetOpenFile(ARGF.current_file, fptr);
13560 ARGF.encs = fptr->encs;
13561 return argf;
13562}
13563
13564/*
13565 * call-seq:
13566 * ARGF.tell -> Integer
13567 * ARGF.pos -> Integer
13568 *
13569 * Returns the current offset (in bytes) of the current file in ARGF.
13570 *
13571 * ARGF.pos #=> 0
13572 * ARGF.gets #=> "This is line one\n"
13573 * ARGF.pos #=> 17
13574 *
13575 */
13576static VALUE
13577argf_tell(VALUE argf)
13578{
13579 if (!next_argv()) {
13580 rb_raise(rb_eArgError, "no stream to tell");
13581 }
13582 ARGF_FORWARD(0, 0);
13583 return rb_io_tell(ARGF.current_file);
13584}
13585
13586/*
13587 * call-seq:
13588 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13589 *
13590 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13591 * the value of _whence_. See IO#seek for further details.
13592 */
13593static VALUE
13594argf_seek_m(int argc, VALUE *argv, VALUE argf)
13595{
13596 if (!next_argv()) {
13597 rb_raise(rb_eArgError, "no stream to seek");
13598 }
13599 ARGF_FORWARD(argc, argv);
13600 return rb_io_seek_m(argc, argv, ARGF.current_file);
13601}
13602
13603/*
13604 * call-seq:
13605 * ARGF.pos = position -> Integer
13606 *
13607 * Seeks to the position given by _position_ (in bytes) in ARGF.
13608 *
13609 * For example:
13610 *
13611 * ARGF.pos = 17
13612 * ARGF.gets #=> "This is line two\n"
13613 */
13614static VALUE
13615argf_set_pos(VALUE argf, VALUE offset)
13616{
13617 if (!next_argv()) {
13618 rb_raise(rb_eArgError, "no stream to set position");
13619 }
13620 ARGF_FORWARD(1, &offset);
13621 return rb_io_set_pos(ARGF.current_file, offset);
13622}
13623
13624/*
13625 * call-seq:
13626 * ARGF.rewind -> 0
13627 *
13628 * Positions the current file to the beginning of input, resetting
13629 * ARGF.lineno to zero.
13630 *
13631 * ARGF.readline #=> "This is line one\n"
13632 * ARGF.rewind #=> 0
13633 * ARGF.lineno #=> 0
13634 * ARGF.readline #=> "This is line one\n"
13635 */
13636static VALUE
13637argf_rewind(VALUE argf)
13638{
13639 VALUE ret;
13640 int old_lineno;
13641
13642 if (!next_argv()) {
13643 rb_raise(rb_eArgError, "no stream to rewind");
13644 }
13645 ARGF_FORWARD(0, 0);
13646 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13647 ret = rb_io_rewind(ARGF.current_file);
13648 if (!global_argf_p(argf)) {
13649 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13650 }
13651 return ret;
13652}
13653
13654/*
13655 * call-seq:
13656 * ARGF.fileno -> integer
13657 * ARGF.to_i -> integer
13658 *
13659 * Returns an integer representing the numeric file descriptor for
13660 * the current file. Raises an ArgumentError if there isn't a current file.
13661 *
13662 * ARGF.fileno #=> 3
13663 */
13664static VALUE
13665argf_fileno(VALUE argf)
13666{
13667 if (!next_argv()) {
13668 rb_raise(rb_eArgError, "no stream");
13669 }
13670 ARGF_FORWARD(0, 0);
13671 return rb_io_fileno(ARGF.current_file);
13672}
13673
13674/*
13675 * call-seq:
13676 * ARGF.to_io -> IO
13677 *
13678 * Returns an IO object representing the current file. This will be a
13679 * File object unless the current file is a stream such as STDIN.
13680 *
13681 * For example:
13682 *
13683 * ARGF.to_io #=> #<File:glark.txt>
13684 * ARGF.to_io #=> #<IO:<STDIN>>
13685 */
13686static VALUE
13687argf_to_io(VALUE argf)
13688{
13689 next_argv();
13690 ARGF_FORWARD(0, 0);
13691 return ARGF.current_file;
13692}
13693
13694/*
13695 * call-seq:
13696 * ARGF.eof? -> true or false
13697 * ARGF.eof -> true or false
13698 *
13699 * Returns true if the current file in ARGF is at end of file, i.e. it has
13700 * no data to read. The stream must be opened for reading or an IOError
13701 * will be raised.
13702 *
13703 * $ echo "eof" | ruby argf.rb
13704 *
13705 * ARGF.eof? #=> false
13706 * 3.times { ARGF.readchar }
13707 * ARGF.eof? #=> false
13708 * ARGF.readchar #=> "\n"
13709 * ARGF.eof? #=> true
13710 */
13711
13712static VALUE
13713argf_eof(VALUE argf)
13714{
13715 next_argv();
13716 if (RTEST(ARGF.current_file)) {
13717 if (ARGF.init_p == 0) return Qtrue;
13718 next_argv();
13719 ARGF_FORWARD(0, 0);
13720 if (rb_io_eof(ARGF.current_file)) {
13721 return Qtrue;
13722 }
13723 }
13724 return Qfalse;
13725}
13726
13727/*
13728 * call-seq:
13729 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13730 *
13731 * Reads _length_ bytes from ARGF. The files named on the command line
13732 * are concatenated and treated as a single file by this method, so when
13733 * called without arguments the contents of this pseudo file are returned in
13734 * their entirety.
13735 *
13736 * _length_ must be a non-negative integer or +nil+.
13737 *
13738 * If _length_ is a positive integer, +read+ tries to read
13739 * _length_ bytes without any conversion (binary mode).
13740 * It returns +nil+ if an EOF is encountered before anything can be read.
13741 * Fewer than _length_ bytes are returned if an EOF is encountered during
13742 * the read.
13743 * In the case of an integer _length_, the resulting string is always
13744 * in ASCII-8BIT encoding.
13745 *
13746 * If _length_ is omitted or is +nil+, it reads until EOF
13747 * and the encoding conversion is applied, if applicable.
13748 * A string is returned even if EOF is encountered before any data is read.
13749 *
13750 * If _length_ is zero, it returns an empty string (<code>""</code>).
13751 *
13752 * If the optional _outbuf_ argument is present,
13753 * it must reference a String, which will receive the data.
13754 * The _outbuf_ will contain only the received data after the method call
13755 * even if it is not empty at the beginning.
13756 *
13757 * For example:
13758 *
13759 * $ echo "small" > small.txt
13760 * $ echo "large" > large.txt
13761 * $ ./glark.rb small.txt large.txt
13762 *
13763 * ARGF.read #=> "small\nlarge"
13764 * ARGF.read(200) #=> "small\nlarge"
13765 * ARGF.read(2) #=> "sm"
13766 * ARGF.read(0) #=> ""
13767 *
13768 * Note that this method behaves like the fread() function in C.
13769 * This means it retries to invoke read(2) system calls to read data
13770 * with the specified length.
13771 * If you need the behavior like a single read(2) system call,
13772 * consider ARGF#readpartial or ARGF#read_nonblock.
13773 */
13774
13775static VALUE
13776argf_read(int argc, VALUE *argv, VALUE argf)
13777{
13778 VALUE tmp, str, length;
13779 long len = 0;
13780
13781 rb_scan_args(argc, argv, "02", &length, &str);
13782 if (!NIL_P(length)) {
13783 len = NUM2LONG(argv[0]);
13784 }
13785 if (!NIL_P(str)) {
13786 StringValue(str);
13787 rb_str_resize(str,0);
13788 argv[1] = Qnil;
13789 }
13790
13791 retry:
13792 if (!next_argv()) {
13793 return str;
13794 }
13795 if (ARGF_GENERIC_INPUT_P()) {
13796 tmp = argf_forward(argc, argv, argf);
13797 }
13798 else {
13799 tmp = io_read(argc, argv, ARGF.current_file);
13800 }
13801 if (NIL_P(str)) str = tmp;
13802 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13803 if (NIL_P(tmp) || NIL_P(length)) {
13804 if (ARGF.next_p != -1) {
13805 argf_close(argf);
13806 ARGF.next_p = 1;
13807 goto retry;
13808 }
13809 }
13810 else if (argc >= 1) {
13811 long slen = RSTRING_LEN(str);
13812 if (slen < len) {
13813 argv[0] = LONG2NUM(len - slen);
13814 goto retry;
13815 }
13816 }
13817 return str;
13818}
13819
13820 struct argf_call_arg {
13821 int argc;
13822 VALUE *argv;
13823 VALUE argf;
13824};
13825
13826static VALUE
13827argf_forward_call(VALUE arg)
13828{
13829 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13830 argf_forward(p->argc, p->argv, p->argf);
13831 return Qnil;
13832}
13833
13834static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13835 int nonblock);
13836
13837/*
13838 * call-seq:
13839 * ARGF.readpartial(maxlen) -> string
13840 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13841 *
13842 * Reads at most _maxlen_ bytes from the ARGF stream.
13843 *
13844 * If the optional _outbuf_ argument is present,
13845 * it must reference a String, which will receive the data.
13846 * The _outbuf_ will contain only the received data after the method call
13847 * even if it is not empty at the beginning.
13848 *
13849 * It raises EOFError on end of ARGF stream.
13850 * Since ARGF stream is a concatenation of multiple files,
13851 * internally EOF is occur for each file.
13852 * ARGF.readpartial returns empty strings for EOFs except the last one and
13853 * raises EOFError for the last one.
13854 *
13855 */
13856
13857static VALUE
13858argf_readpartial(int argc, VALUE *argv, VALUE argf)
13859{
13860 return argf_getpartial(argc, argv, argf, Qnil, 0);
13861}
13862
13863/*
13864 * call-seq:
13865 * ARGF.read_nonblock(maxlen[, options]) -> string
13866 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13867 *
13868 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13869 */
13870
13871static VALUE
13872argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13873{
13874 VALUE opts;
13875
13876 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13877
13878 if (!NIL_P(opts))
13879 argc--;
13880
13881 return argf_getpartial(argc, argv, argf, opts, 1);
13882}
13883
13884static VALUE
13885argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13886{
13887 VALUE tmp, str, length;
13888 int no_exception;
13889
13890 rb_scan_args(argc, argv, "11", &length, &str);
13891 if (!NIL_P(str)) {
13892 StringValue(str);
13893 argv[1] = str;
13894 }
13895 no_exception = no_exception_p(opts);
13896
13897 if (!next_argv()) {
13898 if (!NIL_P(str)) {
13899 rb_str_resize(str, 0);
13900 }
13901 rb_eof_error();
13902 }
13903 if (ARGF_GENERIC_INPUT_P()) {
13904 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13905 struct argf_call_arg arg;
13906 arg.argc = argc;
13907 arg.argv = argv;
13908 arg.argf = argf;
13909 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
13910 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
13911 }
13912 else {
13913 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13914 }
13915 if (NIL_P(tmp)) {
13916 if (ARGF.next_p == -1) {
13917 return io_nonblock_eof(no_exception);
13918 }
13919 argf_close(argf);
13920 ARGF.next_p = 1;
13921 if (RARRAY_LEN(ARGF.argv) == 0) {
13922 return io_nonblock_eof(no_exception);
13923 }
13924 if (NIL_P(str))
13925 str = rb_str_new(NULL, 0);
13926 return str;
13927 }
13928 return tmp;
13929}
13930
13931/*
13932 * call-seq:
13933 * ARGF.getc -> String or nil
13934 *
13935 * Reads the next character from ARGF and returns it as a String. Returns
13936 * +nil+ at the end of the stream.
13937 *
13938 * ARGF treats the files named on the command line as a single file created
13939 * by concatenating their contents. After returning the last character of the
13940 * first file, it returns the first character of the second file, and so on.
13941 *
13942 * For example:
13943 *
13944 * $ echo "foo" > file
13945 * $ ruby argf.rb file
13946 *
13947 * ARGF.getc #=> "f"
13948 * ARGF.getc #=> "o"
13949 * ARGF.getc #=> "o"
13950 * ARGF.getc #=> "\n"
13951 * ARGF.getc #=> nil
13952 * ARGF.getc #=> nil
13953 */
13954static VALUE
13955argf_getc(VALUE argf)
13956{
13957 VALUE ch;
13958
13959 retry:
13960 if (!next_argv()) return Qnil;
13961 if (ARGF_GENERIC_INPUT_P()) {
13962 ch = forward_current(rb_intern("getc"), 0, 0);
13963 }
13964 else {
13965 ch = rb_io_getc(ARGF.current_file);
13966 }
13967 if (NIL_P(ch) && ARGF.next_p != -1) {
13968 argf_close(argf);
13969 ARGF.next_p = 1;
13970 goto retry;
13971 }
13972
13973 return ch;
13974}
13975
13976/*
13977 * call-seq:
13978 * ARGF.getbyte -> Integer or nil
13979 *
13980 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
13981 * the end of the stream.
13982 *
13983 * For example:
13984 *
13985 * $ echo "foo" > file
13986 * $ ruby argf.rb file
13987 *
13988 * ARGF.getbyte #=> 102
13989 * ARGF.getbyte #=> 111
13990 * ARGF.getbyte #=> 111
13991 * ARGF.getbyte #=> 10
13992 * ARGF.getbyte #=> nil
13993 */
13994static VALUE
13995argf_getbyte(VALUE argf)
13996{
13997 VALUE ch;
13998
13999 retry:
14000 if (!next_argv()) return Qnil;
14001 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14002 ch = forward_current(rb_intern("getbyte"), 0, 0);
14003 }
14004 else {
14005 ch = rb_io_getbyte(ARGF.current_file);
14006 }
14007 if (NIL_P(ch) && ARGF.next_p != -1) {
14008 argf_close(argf);
14009 ARGF.next_p = 1;
14010 goto retry;
14011 }
14012
14013 return ch;
14014}
14015
14016/*
14017 * call-seq:
14018 * ARGF.readchar -> String or nil
14019 *
14020 * Reads the next character from ARGF and returns it as a String. Raises
14021 * an EOFError after the last character of the last file has been read.
14022 *
14023 * For example:
14024 *
14025 * $ echo "foo" > file
14026 * $ ruby argf.rb file
14027 *
14028 * ARGF.readchar #=> "f"
14029 * ARGF.readchar #=> "o"
14030 * ARGF.readchar #=> "o"
14031 * ARGF.readchar #=> "\n"
14032 * ARGF.readchar #=> end of file reached (EOFError)
14033 */
14034static VALUE
14035argf_readchar(VALUE argf)
14036{
14037 VALUE ch;
14038
14039 retry:
14040 if (!next_argv()) rb_eof_error();
14041 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14042 ch = forward_current(rb_intern("getc"), 0, 0);
14043 }
14044 else {
14045 ch = rb_io_getc(ARGF.current_file);
14046 }
14047 if (NIL_P(ch) && ARGF.next_p != -1) {
14048 argf_close(argf);
14049 ARGF.next_p = 1;
14050 goto retry;
14051 }
14052
14053 return ch;
14054}
14055
14056/*
14057 * call-seq:
14058 * ARGF.readbyte -> Integer
14059 *
14060 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14061 * an EOFError after the last byte of the last file has been read.
14062 *
14063 * For example:
14064 *
14065 * $ echo "foo" > file
14066 * $ ruby argf.rb file
14067 *
14068 * ARGF.readbyte #=> 102
14069 * ARGF.readbyte #=> 111
14070 * ARGF.readbyte #=> 111
14071 * ARGF.readbyte #=> 10
14072 * ARGF.readbyte #=> end of file reached (EOFError)
14073 */
14074static VALUE
14075argf_readbyte(VALUE argf)
14076{
14077 VALUE c;
14078
14079 NEXT_ARGF_FORWARD(0, 0);
14080 c = argf_getbyte(argf);
14081 if (NIL_P(c)) {
14082 rb_eof_error();
14083 }
14084 return c;
14085}
14086
14087#define FOREACH_ARGF() while (next_argv())
14088
14089static VALUE
14090argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14091{
14092 const VALUE current = ARGF.current_file;
14093 rb_yield_values2(argc, argv);
14094 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14095 rb_iter_break_value(Qundef);
14096 }
14097 return Qnil;
14098}
14099
14100#define ARGF_block_call(mid, argc, argv, func, argf) \
14101 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14102 func, argf, rb_keyword_given_p())
14103
14104static void
14105argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14106{
14107 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14108 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14109}
14110
14111static VALUE
14112argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14113{
14114 if (!global_argf_p(argf)) {
14115 ARGF.last_lineno = ++ARGF.lineno;
14116 }
14117 return argf_block_call_i(i, argf, argc, argv, blockarg);
14118}
14119
14120static void
14121argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14122{
14123 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14124 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14125}
14126
14127/*
14128 * call-seq:
14129 * ARGF.each(sep=$/) {|line| block } -> ARGF
14130 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14131 * ARGF.each(...) -> an_enumerator
14132 *
14133 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14134 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14135 * ARGF.each_line(...) -> an_enumerator
14136 *
14137 * Returns an enumerator which iterates over each line (separated by _sep_,
14138 * which defaults to your platform's newline character) of each file in
14139 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14140 * block, otherwise an enumerator is returned.
14141 * The optional _limit_ argument is an Integer specifying the maximum
14142 * length of each line; longer lines will be split according to this limit.
14143 *
14144 * This method allows you to treat the files supplied on the command line as
14145 * a single file consisting of the concatenation of each named file. After
14146 * the last line of the first file has been returned, the first line of the
14147 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14148 * used to determine the filename of the current line and line number of the
14149 * whole input, respectively.
14150 *
14151 * For example, the following code prints out each line of each named file
14152 * prefixed with its line number, displaying the filename once per file:
14153 *
14154 * ARGF.each_line do |line|
14155 * puts ARGF.filename if ARGF.file.lineno == 1
14156 * puts "#{ARGF.file.lineno}: #{line}"
14157 * end
14158 *
14159 * While the following code prints only the first file's name at first, and
14160 * the contents with line number counted through all named files.
14161 *
14162 * ARGF.each_line do |line|
14163 * puts ARGF.filename if ARGF.lineno == 1
14164 * puts "#{ARGF.lineno}: #{line}"
14165 * end
14166 */
14167static VALUE
14168argf_each_line(int argc, VALUE *argv, VALUE argf)
14169{
14170 RETURN_ENUMERATOR(argf, argc, argv);
14171 FOREACH_ARGF() {
14172 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14173 }
14174 return argf;
14175}
14176
14177/*
14178 * call-seq:
14179 * ARGF.each_byte {|byte| block } -> ARGF
14180 * ARGF.each_byte -> an_enumerator
14181 *
14182 * Iterates over each byte of each file in +ARGV+.
14183 * A byte is returned as an Integer in the range 0..255.
14184 *
14185 * This method allows you to treat the files supplied on the command line as
14186 * a single file consisting of the concatenation of each named file. After
14187 * the last byte of the first file has been returned, the first byte of the
14188 * second file is returned. The ARGF.filename method can be used to
14189 * determine the filename of the current byte.
14190 *
14191 * If no block is given, an enumerator is returned instead.
14192 *
14193 * For example:
14194 *
14195 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14196 *
14197 */
14198static VALUE
14199argf_each_byte(VALUE argf)
14200{
14201 RETURN_ENUMERATOR(argf, 0, 0);
14202 FOREACH_ARGF() {
14203 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14204 }
14205 return argf;
14206}
14207
14208/*
14209 * call-seq:
14210 * ARGF.each_char {|char| block } -> ARGF
14211 * ARGF.each_char -> an_enumerator
14212 *
14213 * Iterates over each character of each file in ARGF.
14214 *
14215 * This method allows you to treat the files supplied on the command line as
14216 * a single file consisting of the concatenation of each named file. After
14217 * the last character of the first file has been returned, the first
14218 * character of the second file is returned. The ARGF.filename method can
14219 * be used to determine the name of the file in which the current character
14220 * appears.
14221 *
14222 * If no block is given, an enumerator is returned instead.
14223 */
14224static VALUE
14225argf_each_char(VALUE argf)
14226{
14227 RETURN_ENUMERATOR(argf, 0, 0);
14228 FOREACH_ARGF() {
14229 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14230 }
14231 return argf;
14232}
14233
14234/*
14235 * call-seq:
14236 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14237 * ARGF.each_codepoint -> an_enumerator
14238 *
14239 * Iterates over each codepoint of each file in ARGF.
14240 *
14241 * This method allows you to treat the files supplied on the command line as
14242 * a single file consisting of the concatenation of each named file. After
14243 * the last codepoint of the first file has been returned, the first
14244 * codepoint of the second file is returned. The ARGF.filename method can
14245 * be used to determine the name of the file in which the current codepoint
14246 * appears.
14247 *
14248 * If no block is given, an enumerator is returned instead.
14249 */
14250static VALUE
14251argf_each_codepoint(VALUE argf)
14252{
14253 RETURN_ENUMERATOR(argf, 0, 0);
14254 FOREACH_ARGF() {
14255 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14256 }
14257 return argf;
14258}
14259
14260/*
14261 * call-seq:
14262 * ARGF.filename -> String
14263 * ARGF.path -> String
14264 *
14265 * Returns the current filename. "-" is returned when the current file is
14266 * STDIN.
14267 *
14268 * For example:
14269 *
14270 * $ echo "foo" > foo
14271 * $ echo "bar" > bar
14272 * $ echo "glark" > glark
14273 *
14274 * $ ruby argf.rb foo bar glark
14275 *
14276 * ARGF.filename #=> "foo"
14277 * ARGF.read(5) #=> "foo\nb"
14278 * ARGF.filename #=> "bar"
14279 * ARGF.skip
14280 * ARGF.filename #=> "glark"
14281 */
14282static VALUE
14283argf_filename(VALUE argf)
14284{
14285 next_argv();
14286 return ARGF.filename;
14287}
14288
14289static VALUE
14290argf_filename_getter(ID id, VALUE *var)
14291{
14292 return argf_filename(*var);
14293}
14294
14295/*
14296 * call-seq:
14297 * ARGF.file -> IO or File object
14298 *
14299 * Returns the current file as an IO or File object.
14300 * <code>$stdin</code> is returned when the current file is STDIN.
14301 *
14302 * For example:
14303 *
14304 * $ echo "foo" > foo
14305 * $ echo "bar" > bar
14306 *
14307 * $ ruby argf.rb foo bar
14308 *
14309 * ARGF.file #=> #<File:foo>
14310 * ARGF.read(5) #=> "foo\nb"
14311 * ARGF.file #=> #<File:bar>
14312 */
14313static VALUE
14314argf_file(VALUE argf)
14315{
14316 next_argv();
14317 return ARGF.current_file;
14318}
14319
14320/*
14321 * call-seq:
14322 * ARGF.binmode -> ARGF
14323 *
14324 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14325 * be reset to non-binary mode. This option has the following effects:
14326 *
14327 * * Newline conversion is disabled.
14328 * * Encoding conversion is disabled.
14329 * * Content is treated as ASCII-8BIT.
14330 */
14331static VALUE
14332argf_binmode_m(VALUE argf)
14333{
14334 ARGF.binmode = 1;
14335 next_argv();
14336 ARGF_FORWARD(0, 0);
14337 rb_io_ascii8bit_binmode(ARGF.current_file);
14338 return argf;
14339}
14340
14341/*
14342 * call-seq:
14343 * ARGF.binmode? -> true or false
14344 *
14345 * Returns true if ARGF is being read in binary mode; false otherwise.
14346 * To enable binary mode use ARGF.binmode.
14347 *
14348 * For example:
14349 *
14350 * ARGF.binmode? #=> false
14351 * ARGF.binmode
14352 * ARGF.binmode? #=> true
14353 */
14354static VALUE
14355argf_binmode_p(VALUE argf)
14356{
14357 return RBOOL(ARGF.binmode);
14358}
14359
14360/*
14361 * call-seq:
14362 * ARGF.skip -> ARGF
14363 *
14364 * Sets the current file to the next file in ARGV. If there aren't any more
14365 * files it has no effect.
14366 *
14367 * For example:
14368 *
14369 * $ ruby argf.rb foo bar
14370 * ARGF.filename #=> "foo"
14371 * ARGF.skip
14372 * ARGF.filename #=> "bar"
14373 */
14374static VALUE
14375argf_skip(VALUE argf)
14376{
14377 if (ARGF.init_p && ARGF.next_p == 0) {
14378 argf_close(argf);
14379 ARGF.next_p = 1;
14380 }
14381 return argf;
14382}
14383
14384/*
14385 * call-seq:
14386 * ARGF.close -> ARGF
14387 *
14388 * Closes the current file and skips to the next file in ARGV. If there are
14389 * no more files to open, just closes the current file. STDIN will not be
14390 * closed.
14391 *
14392 * For example:
14393 *
14394 * $ ruby argf.rb foo bar
14395 *
14396 * ARGF.filename #=> "foo"
14397 * ARGF.close
14398 * ARGF.filename #=> "bar"
14399 * ARGF.close
14400 */
14401static VALUE
14402argf_close_m(VALUE argf)
14403{
14404 next_argv();
14405 argf_close(argf);
14406 if (ARGF.next_p != -1) {
14407 ARGF.next_p = 1;
14408 }
14409 ARGF.lineno = 0;
14410 return argf;
14411}
14412
14413/*
14414 * call-seq:
14415 * ARGF.closed? -> true or false
14416 *
14417 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14418 * ARGF.close to actually close the current file.
14419 */
14420static VALUE
14421argf_closed(VALUE argf)
14422{
14423 next_argv();
14424 ARGF_FORWARD(0, 0);
14425 return rb_io_closed_p(ARGF.current_file);
14426}
14427
14428/*
14429 * call-seq:
14430 * ARGF.to_s -> String
14431 *
14432 * Returns "ARGF".
14433 */
14434static VALUE
14435argf_to_s(VALUE argf)
14436{
14437 return rb_str_new2("ARGF");
14438}
14439
14440/*
14441 * call-seq:
14442 * ARGF.inplace_mode -> String
14443 *
14444 * Returns the file extension appended to the names of backup copies of
14445 * modified files under in-place edit mode. This value can be set using
14446 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14447 */
14448static VALUE
14449argf_inplace_mode_get(VALUE argf)
14450{
14451 if (!ARGF.inplace) return Qnil;
14452 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14453 return rb_str_dup(ARGF.inplace);
14454}
14455
14456static VALUE
14457opt_i_get(ID id, VALUE *var)
14458{
14459 return argf_inplace_mode_get(*var);
14460}
14461
14462/*
14463 * call-seq:
14464 * ARGF.inplace_mode = ext -> ARGF
14465 *
14466 * Sets the filename extension for in-place editing mode to the given String.
14467 * The backup copy of each file being edited has this value appended to its
14468 * filename.
14469 *
14470 * For example:
14471 *
14472 * $ ruby argf.rb file.txt
14473 *
14474 * ARGF.inplace_mode = '.bak'
14475 * ARGF.each_line do |line|
14476 * print line.sub("foo","bar")
14477 * end
14478 *
14479 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14480 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14481 * "bar".
14482 */
14483static VALUE
14484argf_inplace_mode_set(VALUE argf, VALUE val)
14485{
14486 if (!RTEST(val)) {
14487 ARGF.inplace = Qfalse;
14488 }
14489 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14490 ARGF.inplace = Qnil;
14491 }
14492 else {
14493 ARGF.inplace = rb_str_new_frozen(val);
14494 }
14495 return argf;
14496}
14497
14498static void
14499opt_i_set(VALUE val, ID id, VALUE *var)
14500{
14501 argf_inplace_mode_set(*var, val);
14502}
14503
14504void
14505ruby_set_inplace_mode(const char *suffix)
14506{
14507 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14508}
14509
14510/*
14511 * call-seq:
14512 * ARGF.argv -> ARGV
14513 *
14514 * Returns the +ARGV+ array, which contains the arguments passed to your
14515 * script, one per element.
14516 *
14517 * For example:
14518 *
14519 * $ ruby argf.rb -v glark.txt
14520 *
14521 * ARGF.argv #=> ["-v", "glark.txt"]
14522 *
14523 */
14524static VALUE
14525argf_argv(VALUE argf)
14526{
14527 return ARGF.argv;
14528}
14529
14530static VALUE
14531argf_argv_getter(ID id, VALUE *var)
14532{
14533 return argf_argv(*var);
14534}
14535
14536 VALUE
14537rb_get_argv(void)
14538{
14539 return ARGF.argv;
14540}
14541
14542/*
14543 * call-seq:
14544 * ARGF.to_write_io -> io
14545 *
14546 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14547 * enabled.
14548 */
14549static VALUE
14550argf_write_io(VALUE argf)
14551{
14552 if (!RTEST(ARGF.current_file)) {
14553 rb_raise(rb_eIOError, "not opened for writing");
14554 }
14555 return GetWriteIO(ARGF.current_file);
14556}
14557
14558/*
14559 * call-seq:
14560 * ARGF.write(string) -> integer
14561 *
14562 * Writes _string_ if inplace mode.
14563 */
14564static VALUE
14565argf_write(VALUE argf, VALUE str)
14566{
14567 return rb_io_write(argf_write_io(argf), str);
14568}
14569
14570void
14571rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14572{
14573 rb_readwrite_syserr_fail(waiting, errno, mesg);
14574}
14575
14576void
14577rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14578{
14579 VALUE arg, c = Qnil;
14580 arg = mesg ? rb_str_new2(mesg) : Qnil;
14581 switch (waiting) {
14582 case RB_IO_WAIT_WRITABLE:
14583 switch (n) {
14584 case EAGAIN:
14585 c = rb_eEAGAINWaitWritable;
14586 break;
14587#if EAGAIN != EWOULDBLOCK
14588 case EWOULDBLOCK:
14589 c = rb_eEWOULDBLOCKWaitWritable;
14590 break;
14591#endif
14592 case EINPROGRESS:
14593 c = rb_eEINPROGRESSWaitWritable;
14594 break;
14595 default:
14596 rb_mod_syserr_fail_str(rb_mWaitWritable, n, arg);
14597 }
14598 break;
14599 case RB_IO_WAIT_READABLE:
14600 switch (n) {
14601 case EAGAIN:
14602 c = rb_eEAGAINWaitReadable;
14603 break;
14604#if EAGAIN != EWOULDBLOCK
14605 case EWOULDBLOCK:
14606 c = rb_eEWOULDBLOCKWaitReadable;
14607 break;
14608#endif
14609 case EINPROGRESS:
14610 c = rb_eEINPROGRESSWaitReadable;
14611 break;
14612 default:
14613 rb_mod_syserr_fail_str(rb_mWaitReadable, n, arg);
14614 }
14615 break;
14616 default:
14617 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14618 }
14619 rb_exc_raise(rb_class_new_instance(1, &arg, c));
14620}
14621
14622static VALUE
14623get_LAST_READ_LINE(ID _x, VALUE *_y)
14624{
14625 return rb_lastline_get();
14626}
14627
14628static void
14629set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14630{
14631 rb_lastline_set(val);
14632}
14633
14634/*
14635 * Document-class: IOError
14636 *
14637 * Raised when an IO operation fails.
14638 *
14639 * File.open("/etc/hosts") {|f| f << "example"}
14640 * #=> IOError: not opened for writing
14641 *
14642 * File.open("/etc/hosts") {|f| f.close; f.read }
14643 * #=> IOError: closed stream
14644 *
14645 * Note that some IO failures raise <code>SystemCallError</code>s
14646 * and these are not subclasses of IOError:
14647 *
14648 * File.open("does/not/exist")
14649 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14650 */
14651
14652/*
14653 * Document-class: EOFError
14654 *
14655 * Raised by some IO operations when reaching the end of file. Many IO
14656 * methods exist in two forms,
14657 *
14658 * one that returns +nil+ when the end of file is reached, the other
14659 * raises EOFError.
14660 *
14661 * EOFError is a subclass of IOError.
14662 *
14663 * file = File.open("/etc/hosts")
14664 * file.read
14665 * file.gets #=> nil
14666 * file.readline #=> EOFError: end of file reached
14667 * file.close
14668 */
14669
14670/*
14671 * Document-class: ARGF
14672 *
14673 * ARGF is a stream designed for use in scripts that process files given as
14674 * command-line arguments or passed in via STDIN.
14675 *
14676 * The arguments passed to your script are stored in the +ARGV+ Array, one
14677 * argument per element. ARGF assumes that any arguments that aren't
14678 * filenames have been removed from +ARGV+. For example:
14679 *
14680 * $ ruby argf.rb --verbose file1 file2
14681 *
14682 * ARGV #=> ["--verbose", "file1", "file2"]
14683 * option = ARGV.shift #=> "--verbose"
14684 * ARGV #=> ["file1", "file2"]
14685 *
14686 * You can now use ARGF to work with a concatenation of each of these named
14687 * files. For instance, ARGF.read will return the contents of _file1_
14688 * followed by the contents of _file2_.
14689 *
14690 * After a file in +ARGV+ has been read ARGF removes it from the Array.
14691 * Thus, after all files have been read +ARGV+ will be empty.
14692 *
14693 * You can manipulate +ARGV+ yourself to control what ARGF operates on. If
14694 * you remove a file from +ARGV+, it is ignored by ARGF; if you add files to
14695 * +ARGV+, they are treated as if they were named on the command line. For
14696 * example:
14697 *
14698 * ARGV.replace ["file1"]
14699 * ARGF.readlines # Returns the contents of file1 as an Array
14700 * ARGV #=> []
14701 * ARGV.replace ["file2", "file3"]
14702 * ARGF.read # Returns the contents of file2 and file3
14703 *
14704 * If +ARGV+ is empty, ARGF acts as if it contained <tt>"-"</tt> that
14705 * makes ARGF read from STDIN, i.e. the data piped or typed to your
14706 * script. For example:
14707 *
14708 * $ echo "glark" | ruby -e 'p ARGF.read'
14709 * "glark\n"
14710 *
14711 * $ echo Glark > file1
14712 * $ echo "glark" | ruby -e 'p ARGF.read' -- - file1
14713 * "glark\nGlark\n"
14714 */
14715
14716/*
14717 * An instance of class \IO (commonly called a _stream_)
14718 * represents an input/output stream in the underlying operating system.
14719 * \Class \IO is the basis for input and output in Ruby.
14720 *
14721 * \Class File is the only class in the Ruby core that is a subclass of \IO.
14722 * Some classes in the Ruby standard library are also subclasses of \IO;
14723 * these include TCPSocket and UDPSocket.
14724 *
14725 * The global constant ARGF (also accessible as <tt>$<</tt>)
14726 * provides an IO-like stream that allows access to all file paths
14727 * found in ARGV (or found in STDIN if ARGV is empty).
14728 * ARGF is not itself a subclass of \IO.
14729 *
14730 * \Class StringIO provides an IO-like stream that handles a String.
14731 * StringIO is not itself a subclass of \IO.
14732 *
14733 * Important objects based on \IO include:
14734 *
14735 * - $stdin.
14736 * - $stdout.
14737 * - $stderr.
14738 * - Instances of class File.
14739 *
14740 * An instance of \IO may be created using:
14741 *
14742 * - IO.new: returns a new \IO object for the given integer file descriptor.
14743 * - IO.open: passes a new \IO object to the given block.
14744 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
14745 * of a newly-launched subprocess.
14746 * - Kernel#open: Returns a new \IO object connected to a given source:
14747 * stream, file, or subprocess.
14748 *
14749 * Like a File stream, an \IO stream has:
14750 *
14751 * - A read/write mode, which may be read-only, write-only, or read/write;
14752 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
14753 * - A data mode, which may be text-only or binary;
14754 * see {Data Mode}[rdoc-ref:File@Data+Mode].
14755 * - Internal and external encodings;
14756 * see {Encodings}[rdoc-ref:File@Encodings].
14757 *
14758 * And like other \IO streams, it has:
14759 *
14760 * - A position, which determines where in the stream the next
14761 * read or write is to occur;
14762 * see {Position}[rdoc-ref:IO@Position].
14763 * - A line number, which is a special, line-oriented, "position"
14764 * (different from the position mentioned above);
14765 * see {Line Number}[rdoc-ref:IO@Line+Number].
14766 *
14767 * == Extension <tt>io/console</tt>
14768 *
14769 * Extension <tt>io/console</tt> provides numerous methods
14770 * for interacting with the console;
14771 * requiring it adds numerous methods to class \IO.
14772 *
14773 * == Example Files
14774 *
14775 * Many examples here use these variables:
14776 *
14777 * :include: doc/examples/files.rdoc
14778 *
14779 * == Open Options
14780 *
14781 * A number of \IO methods accept optional keyword arguments
14782 * that determine how a new stream is to be opened:
14783 *
14784 * - +:mode+: Stream mode.
14785 * - +:flags+: Integer file open flags;
14786 * If +mode+ is also given, the two are bitwise-ORed.
14787 * - +:external_encoding+: External encoding for the stream.
14788 * - +:internal_encoding+: Internal encoding for the stream.
14789 * <tt>'-'</tt> is a synonym for the default internal encoding.
14790 * If the value is +nil+ no conversion occurs.
14791 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
14792 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
14793 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
14794 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
14795 * when the stream closes; otherwise it remains open.
14796 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
14797 * #path method.
14798 *
14799 * Also available are the options offered in String#encode,
14800 * which may control conversion between external and internal encoding.
14801 *
14802 * == Basic \IO
14803 *
14804 * You can perform basic stream \IO with these methods,
14805 * which typically operate on multi-byte strings:
14806 *
14807 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
14808 * - IO#write: Writes zero or more strings to the stream;
14809 * each given object that is not already a string is converted via +to_s+.
14810 *
14811 * === Position
14812 *
14813 * An \IO stream has a nonnegative integer _position_,
14814 * which is the byte offset at which the next read or write is to occur.
14815 * A new stream has position zero (and line number zero);
14816 * method +rewind+ resets the position (and line number) to zero.
14817 *
14818 * The relevant methods:
14819 *
14820 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
14821 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
14822 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
14823 * relative to a given position +whence+
14824 * (indicating the beginning, end, or current position).
14825 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
14826 *
14827 * === Open and Closed Streams
14828 *
14829 * A new \IO stream may be open for reading, open for writing, or both.
14830 *
14831 * A stream is automatically closed when claimed by the garbage collector.
14832 *
14833 * Attempted reading or writing on a closed stream raises an exception.
14834 *
14835 * The relevant methods:
14836 *
14837 * - IO#close: Closes the stream for both reading and writing.
14838 * - IO#close_read: Closes the stream for reading.
14839 * - IO#close_write: Closes the stream for writing.
14840 * - IO#closed?: Returns whether the stream is closed.
14841 *
14842 * === End-of-Stream
14843 *
14844 * You can query whether a stream is positioned at its end:
14845 *
14846 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
14847 *
14848 * You can reposition to end-of-stream by using method IO#seek:
14849 *
14850 * f = File.new('t.txt')
14851 * f.eof? # => false
14852 * f.seek(0, :END)
14853 * f.eof? # => true
14854 * f.close
14855 *
14856 * Or by reading all stream content (which is slower than using IO#seek):
14857 *
14858 * f.rewind
14859 * f.eof? # => false
14860 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14861 * f.eof? # => true
14862 *
14863 * == Line \IO
14864 *
14865 * You can read an \IO stream line-by-line using these methods:
14866 *
14867 * - IO#each_line: Reads each remaining line, passing it to the given block.
14868 * - IO#gets: Returns the next line.
14869 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
14870 * - IO#readlines: Returns all remaining lines in an array.
14871 *
14872 * Each of these reader methods accepts:
14873 *
14874 * - An optional line separator, +sep+;
14875 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
14876 * - An optional line-size limit, +limit+;
14877 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
14878 *
14879 * For each of these reader methods, reading may begin mid-line,
14880 * depending on the stream's position;
14881 * see {Position}[rdoc-ref:IO@Position]:
14882 *
14883 * f = File.new('t.txt')
14884 * f.pos = 27
14885 * f.each_line {|line| p line }
14886 * f.close
14887 *
14888 * Output:
14889 *
14890 * "rth line\n"
14891 * "Fifth line\n"
14892 *
14893 * You can write to an \IO stream line-by-line using this method:
14894 *
14895 * - IO#puts: Writes objects to the stream.
14896 *
14897 * === Line Separator
14898 *
14899 * Each of these methods uses a <i>line separator</i>,
14900 * which is the string that delimits lines:
14901 *
14902 * - IO.foreach.
14903 * - IO.readlines.
14904 * - IO#each_line.
14905 * - IO#gets.
14906 * - IO#readline.
14907 * - IO#readlines.
14908 *
14909 * The default line separator is the given by the global variable <tt>$/</tt>,
14910 * whose value is by default <tt>"\n"</tt>.
14911 * The line to be read next is all data from the current position
14912 * to the next line separator:
14913 *
14914 * f = File.new('t.txt')
14915 * f.gets # => "First line\n"
14916 * f.gets # => "Second line\n"
14917 * f.gets # => "\n"
14918 * f.gets # => "Fourth line\n"
14919 * f.gets # => "Fifth line\n"
14920 * f.close
14921 *
14922 * You can specify a different line separator:
14923 *
14924 * f = File.new('t.txt')
14925 * f.gets('l') # => "First l"
14926 * f.gets('li') # => "ine\nSecond li"
14927 * f.gets('lin') # => "ne\n\nFourth lin"
14928 * f.gets # => "e\n"
14929 * f.close
14930 *
14931 * There are two special line separators:
14932 *
14933 * - +nil+: The entire stream is read into a single string:
14934 *
14935 * f = File.new('t.txt')
14936 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14937 * f.close
14938 *
14939 * - <tt>''</tt> (the empty string): The next "paragraph" is read
14940 * (paragraphs being separated by two consecutive line separators):
14941 *
14942 * f = File.new('t.txt')
14943 * f.gets('') # => "First line\nSecond line\n\n"
14944 * f.gets('') # => "Fourth line\nFifth line\n"
14945 * f.close
14946 *
14947 * === Line Limit
14948 *
14949 * Each of these methods uses a <i>line limit</i>,
14950 * which specifies that the number of bytes returned may not be (much) longer
14951 * than the given +limit+;
14952 *
14953 * - IO.foreach.
14954 * - IO.readlines.
14955 * - IO#each_line.
14956 * - IO#gets.
14957 * - IO#readline.
14958 * - IO#readlines.
14959 *
14960 * A multi-byte character will not be split, and so a line may be slightly longer
14961 * than the given limit.
14962 *
14963 * If +limit+ is not given, the line is determined only by +sep+.
14964 *
14965 * # Text with 1-byte characters.
14966 * File.open('t.txt') {|f| f.gets(1) } # => "F"
14967 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
14968 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
14969 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
14970 * # No more than one line.
14971 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
14972 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
14973 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
14974 *
14975 * # Text with 2-byte characters, which will not be split.
14976 * File.open('t.rus') {|f| f.gets(1).size } # => 1
14977 * File.open('t.rus') {|f| f.gets(2).size } # => 1
14978 * File.open('t.rus') {|f| f.gets(3).size } # => 2
14979 * File.open('t.rus') {|f| f.gets(4).size } # => 2
14980 *
14981 * === Line Separator and Line Limit
14982 *
14983 * With arguments +sep+ and +limit+ given,
14984 * combines the two behaviors:
14985 *
14986 * - Returns the next line as determined by line separator +sep+.
14987 * - But returns no more bytes than are allowed by the limit.
14988 *
14989 * Example:
14990 *
14991 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
14992 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
14993 *
14994 * === Line Number
14995 *
14996 * A readable \IO stream has a non-negative integer <i>line number</i>.
14997 *
14998 * The relevant methods:
14999 *
15000 * - IO#lineno: Returns the line number.
15001 * - IO#lineno=: Resets and returns the line number.
15002 *
15003 * Unless modified by a call to method IO#lineno=,
15004 * the line number is the number of lines read
15005 * by certain line-oriented methods,
15006 * according to the given line separator +sep+:
15007 *
15008 * - IO.foreach: Increments the line number on each call to the block.
15009 * - IO#each_line: Increments the line number on each call to the block.
15010 * - IO#gets: Increments the line number.
15011 * - IO#readline: Increments the line number.
15012 * - IO#readlines: Increments the line number for each line read.
15013 *
15014 * A new stream is initially has line number zero (and position zero);
15015 * method +rewind+ resets the line number (and position) to zero:
15016 *
15017 * f = File.new('t.txt')
15018 * f.lineno # => 0
15019 * f.gets # => "First line\n"
15020 * f.lineno # => 1
15021 * f.rewind
15022 * f.lineno # => 0
15023 * f.close
15024 *
15025 * Reading lines from a stream usually changes its line number:
15026 *
15027 * f = File.new('t.txt', 'r')
15028 * f.lineno # => 0
15029 * f.readline # => "This is line one.\n"
15030 * f.lineno # => 1
15031 * f.readline # => "This is the second line.\n"
15032 * f.lineno # => 2
15033 * f.readline # => "Here's the third line.\n"
15034 * f.lineno # => 3
15035 * f.eof? # => true
15036 * f.close
15037 *
15038 * Iterating over lines in a stream usually changes its line number:
15039 *
15040 * File.open('t.txt') do |f|
15041 * f.each_line do |line|
15042 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15043 * end
15044 * end
15045 *
15046 * Output:
15047 *
15048 * "position=11 eof?=false lineno=1"
15049 * "position=23 eof?=false lineno=2"
15050 * "position=24 eof?=false lineno=3"
15051 * "position=36 eof?=false lineno=4"
15052 * "position=47 eof?=true lineno=5"
15053 *
15054 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15055 * the line number does not affect where the next read or write will occur:
15056 *
15057 * f = File.new('t.txt')
15058 * f.lineno = 1000
15059 * f.lineno # => 1000
15060 * f.gets # => "First line\n"
15061 * f.lineno # => 1001
15062 * f.close
15063 *
15064 * Associated with the line number is the global variable <tt>$.</tt>:
15065 *
15066 * - When a stream is opened, <tt>$.</tt> is not set;
15067 * its value is left over from previous activity in the process:
15068 *
15069 * $. = 41
15070 * f = File.new('t.txt')
15071 * $. = 41
15072 * # => 41
15073 * f.close
15074 *
15075 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15076 *
15077 * f0 = File.new('t.txt')
15078 * f1 = File.new('t.dat')
15079 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15080 * $. # => 5
15081 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15082 * $. # => 1
15083 * f0.close
15084 * f1.close
15085 *
15086 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15087 *
15088 * f = File.new('t.txt')
15089 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15090 * $. # => 5
15091 * f.rewind
15092 * f.seek(0, :SET)
15093 * $. # => 5
15094 * f.close
15095 *
15096 * == Character \IO
15097 *
15098 * You can process an \IO stream character-by-character using these methods:
15099 *
15100 * - IO#getc: Reads and returns the next character from the stream.
15101 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15102 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15103 * - IO#putc: Writes a character to the stream.
15104 * - IO#each_char: Reads each remaining character in the stream,
15105 * passing the character to the given block.
15106 * == Byte \IO
15107 *
15108 * You can process an \IO stream byte-by-byte using these methods:
15109 *
15110 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15111 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15112 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15113 * - IO#each_byte: Reads each remaining byte in the stream,
15114 * passing the byte to the given block.
15115 *
15116 * == Codepoint \IO
15117 *
15118 * You can process an \IO stream codepoint-by-codepoint:
15119 *
15120 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15121 *
15122 * == What's Here
15123 *
15124 * First, what's elsewhere. \Class \IO:
15125 *
15126 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15127 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15128 * which provides dozens of additional methods.
15129 *
15130 * Here, class \IO provides methods that are useful for:
15131 *
15132 * - {Creating}[rdoc-ref:IO@Creating]
15133 * - {Reading}[rdoc-ref:IO@Reading]
15134 * - {Writing}[rdoc-ref:IO@Writing]
15135 * - {Positioning}[rdoc-ref:IO@Positioning]
15136 * - {Iterating}[rdoc-ref:IO@Iterating]
15137 * - {Settings}[rdoc-ref:IO@Settings]
15138 * - {Querying}[rdoc-ref:IO@Querying]
15139 * - {Buffering}[rdoc-ref:IO@Buffering]
15140 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15141 * - {Other}[rdoc-ref:IO@Other]
15142 *
15143 * === Creating
15144 *
15145 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15146 * integer file descriptor.
15147 * - ::open: Creates a new \IO object.
15148 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15149 * - ::popen: Creates an \IO object to interact with a subprocess.
15150 * - ::select: Selects which given \IO instances are ready for reading,
15151 * writing, or have pending exceptions.
15152 *
15153 * === Reading
15154 *
15155 * - ::binread: Returns a binary string with all or a subset of bytes
15156 * from the given file.
15157 * - ::read: Returns a string with all or a subset of bytes from the given file.
15158 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15159 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15160 * - #getc: Returns the next character read from +self+ as a string.
15161 * - #gets: Returns the line read from +self+.
15162 * - #pread: Returns all or the next _n_ bytes read from +self+,
15163 * not updating the receiver's offset.
15164 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15165 * for a given _n_.
15166 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15167 * in non-block mode.
15168 * - #readbyte: Returns the next byte read from +self+;
15169 * same as #getbyte, but raises an exception on end-of-stream.
15170 * - #readchar: Returns the next character read from +self+;
15171 * same as #getc, but raises an exception on end-of-stream.
15172 * - #readline: Returns the next line read from +self+;
15173 * same as #getline, but raises an exception of end-of-stream.
15174 * - #readlines: Returns an array of all lines read read from +self+.
15175 * - #readpartial: Returns up to the given number of bytes from +self+.
15176 *
15177 * === Writing
15178 *
15179 * - ::binwrite: Writes the given string to the file at the given filepath,
15180 * in binary mode.
15181 * - ::write: Writes the given string to +self+.
15182 * - #<<: Appends the given string to +self+.
15183 * - #print: Prints last read line or given objects to +self+.
15184 * - #printf: Writes to +self+ based on the given format string and objects.
15185 * - #putc: Writes a character to +self+.
15186 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15187 * - #pwrite: Writes the given string at the given offset,
15188 * not updating the receiver's offset.
15189 * - #write: Writes one or more given strings to +self+.
15190 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15191 *
15192 * === Positioning
15193 *
15194 * - #lineno: Returns the current line number in +self+.
15195 * - #lineno=: Sets the line number is +self+.
15196 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15197 * - #pos=: Sets the byte offset in +self+.
15198 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15199 * - #rewind: Positions +self+ to the beginning of input.
15200 * - #seek: Sets the offset for +self+ relative to given position.
15201 *
15202 * === Iterating
15203 *
15204 * - ::foreach: Yields each line of given file to the block.
15205 * - #each (aliased as #each_line): Calls the given block
15206 * with each successive line in +self+.
15207 * - #each_byte: Calls the given block with each successive byte in +self+
15208 * as an integer.
15209 * - #each_char: Calls the given block with each successive character in +self+
15210 * as a string.
15211 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15212 * as an integer.
15213 *
15214 * === Settings
15215 *
15216 * - #autoclose=: Sets whether +self+ auto-closes.
15217 * - #binmode: Sets +self+ to binary mode.
15218 * - #close: Closes +self+.
15219 * - #close_on_exec=: Sets the close-on-exec flag.
15220 * - #close_read: Closes +self+ for reading.
15221 * - #close_write: Closes +self+ for writing.
15222 * - #set_encoding: Sets the encoding for +self+.
15223 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15224 * Unicode byte-order-mark.
15225 * - #sync=: Sets the sync-mode to the given value.
15226 *
15227 * === Querying
15228 *
15229 * - #autoclose?: Returns whether +self+ auto-closes.
15230 * - #binmode?: Returns whether +self+ is in binary mode.
15231 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15232 * - #closed?: Returns whether +self+ is closed.
15233 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15234 * - #external_encoding: Returns the external encoding object for +self+.
15235 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15236 * - #internal_encoding: Returns the internal encoding object for +self+.
15237 * - #pid: Returns the process ID of a child process associated with +self+,
15238 * if +self+ was created by ::popen.
15239 * - #stat: Returns the File::Stat object containing status information for +self+.
15240 * - #sync: Returns whether +self+ is in sync-mode.
15241 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15242 *
15243 * === Buffering
15244 *
15245 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15246 * - #flush: Flushes any buffered data within +self+ to the underlying
15247 * operating system.
15248 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15249 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15250 * - #ungetc: Prepends buffer for +self+ with given string.
15251 *
15252 * === Low-Level Access
15253 *
15254 * - ::sysopen: Opens the file given by its path,
15255 * returning the integer file descriptor.
15256 * - #advise: Announces the intention to access data from +self+ in a specific way.
15257 * - #fcntl: Passes a low-level command to the file specified
15258 * by the given file descriptor.
15259 * - #ioctl: Passes a low-level command to the device specified
15260 * by the given file descriptor.
15261 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15262 * - #sysseek: Sets the offset for +self+.
15263 * - #syswrite: Writes the given string to +self+ using a low-level write.
15264 *
15265 * === Other
15266 *
15267 * - ::copy_stream: Copies data from a source to a destination,
15268 * each of which is a filepath or an \IO-like object.
15269 * - ::try_convert: Returns a new \IO object resulting from converting
15270 * the given object.
15271 * - #inspect: Returns the string representation of +self+.
15272 *
15273 */
15274
15275void
15276Init_IO(void)
15277{
15278 VALUE rb_cARGF;
15279#ifdef __CYGWIN__
15280#include <sys/cygwin.h>
15281 static struct __cygwin_perfile pf[] =
15282 {
15283 {"", O_RDONLY | O_BINARY},
15284 {"", O_WRONLY | O_BINARY},
15285 {"", O_RDWR | O_BINARY},
15286 {"", O_APPEND | O_BINARY},
15287 {NULL, 0}
15288 };
15289 cygwin_internal(CW_PERFILE, pf);
15290#endif
15291
15292 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15293 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15294
15295 id_write = rb_intern_const("write");
15296 id_read = rb_intern_const("read");
15297 id_getc = rb_intern_const("getc");
15298 id_flush = rb_intern_const("flush");
15299 id_readpartial = rb_intern_const("readpartial");
15300 id_set_encoding = rb_intern_const("set_encoding");
15301 id_fileno = rb_intern_const("fileno");
15302
15303 rb_define_global_function("syscall", rb_f_syscall, -1);
15304
15305 rb_define_global_function("open", rb_f_open, -1);
15306 rb_define_global_function("printf", rb_f_printf, -1);
15307 rb_define_global_function("print", rb_f_print, -1);
15308 rb_define_global_function("putc", rb_f_putc, 1);
15309 rb_define_global_function("puts", rb_f_puts, -1);
15310 rb_define_global_function("gets", rb_f_gets, -1);
15311 rb_define_global_function("readline", rb_f_readline, -1);
15312 rb_define_global_function("select", rb_f_select, -1);
15313
15314 rb_define_global_function("readlines", rb_f_readlines, -1);
15315
15316 rb_define_global_function("`", rb_f_backquote, 1);
15317
15318 rb_define_global_function("p", rb_f_p, -1);
15319 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15320
15321 rb_cIO = rb_define_class("IO", rb_cObject);
15322 rb_include_module(rb_cIO, rb_mEnumerable);
15323
15324 /* Can be raised by IO operations when IO#timeout= is set. */
15325 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15326
15327 /* Readable event mask for IO#wait. */
15328 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15329 /* Writable event mask for IO#wait. */
15330 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15331 /* Priority event mask for IO#wait. */
15332 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15333
15334 /* exception to wait for reading. see IO.select. */
15335 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15336 /* exception to wait for writing. see IO.select. */
15337 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15338 /* exception to wait for reading by EAGAIN. see IO.select. */
15339 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15340 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15341 /* exception to wait for writing by EAGAIN. see IO.select. */
15342 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15343 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15344#if EAGAIN == EWOULDBLOCK
15345 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15346 /* same as IO::EAGAINWaitReadable */
15347 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15348 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15349 /* same as IO::EAGAINWaitWritable */
15350 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15351#else
15352 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15353 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15354 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15355 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15356 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15357 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15358#endif
15359 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15360 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15361 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15362 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15363 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15364 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15365
15366#if 0
15367 /* This is necessary only for forcing rdoc handle File::open */
15368 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15369#endif
15370
15371 rb_define_alloc_func(rb_cIO, io_alloc);
15372 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15373 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15374 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15375 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15376 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15377 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15378 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15379 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15380 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15381 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15382 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15383 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15384 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15385 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15386 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15387
15388 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15389
15390 rb_output_fs = Qnil;
15391 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15392
15393 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15394 rb_gc_register_mark_object(rb_default_rs);
15395 rb_rs = rb_default_rs;
15396 rb_output_rs = Qnil;
15397 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15398 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15399 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15400
15401 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15402 rb_gvar_ractor_local("$_");
15403
15404 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15405 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15406
15407 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15408 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15409 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15410 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15411
15412 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15413 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15414 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15415 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15416 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15417
15418 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15419 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15420
15421 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15422 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15423
15424 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15425 rb_define_alias(rb_cIO, "to_i", "fileno");
15426 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15427
15428 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15429 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15430
15431 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15432 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15433 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15434 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15435
15436 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15437 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15438
15439 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15440
15441 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15442 rb_define_method(rb_cIO, "read", io_read, -1);
15443 rb_define_method(rb_cIO, "write", io_write_m, -1);
15444 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15445 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15446 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15447 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15448 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15449 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15450 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15451 rb_define_method(rb_cIO, "<<", rb_io_addstr, 1);
15452 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15453 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15454 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15455 /* Set I/O position from the beginning */
15456 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15457 /* Set I/O position from the current position */
15458 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15459 /* Set I/O position from the end */
15460 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15461#ifdef SEEK_DATA
15462 /* Set I/O position to the next location containing data */
15463 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15464#endif
15465#ifdef SEEK_HOLE
15466 /* Set I/O position to the next hole */
15467 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15468#endif
15469 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15470 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15471 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15472 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15473 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15474
15475 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15476 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15477
15478 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15479 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15480 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15481 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15482
15483 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15484 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15485 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15486 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15487 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15488 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15489
15490 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15491 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15492 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15493
15494 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15495 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15496
15497 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15498
15499 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15500 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15501 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15502 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15503
15504 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15505 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15506
15507 rb_define_method(rb_cIO, "wait", io_wait, -1);
15508
15509 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15510 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15511 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15512
15513 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15514 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15515 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15516 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15517
15518 rb_gvar_ractor_local("$stdin");
15519 rb_gvar_ractor_local("$stdout");
15520 rb_gvar_ractor_local("$>");
15521 rb_gvar_ractor_local("$stderr");
15522
15523 rb_global_variable(&rb_stdin);
15524 rb_stdin = rb_io_prep_stdin();
15525 rb_global_variable(&rb_stdout);
15526 rb_stdout = rb_io_prep_stdout();
15527 rb_global_variable(&rb_stderr);
15528 rb_stderr = rb_io_prep_stderr();
15529
15530 orig_stdout = rb_stdout;
15531 orig_stderr = rb_stderr;
15532
15533 /* Holds the original stdin */
15534 rb_define_global_const("STDIN", rb_stdin);
15535 /* Holds the original stdout */
15536 rb_define_global_const("STDOUT", rb_stdout);
15537 /* Holds the original stderr */
15538 rb_define_global_const("STDERR", rb_stderr);
15539
15540#if 0
15541 /* Hack to get rdoc to regard ARGF as a class: */
15542 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15543#endif
15544
15545 rb_cARGF = rb_class_new(rb_cObject);
15546 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15547 rb_define_alloc_func(rb_cARGF, argf_alloc);
15548
15549 rb_include_module(rb_cARGF, rb_mEnumerable);
15550
15551 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15552 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15553 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15554 rb_define_alias(rb_cARGF, "inspect", "to_s");
15555 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15556
15557 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15558 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15559 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15560 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15561 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15562 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15563 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15564 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15565 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15566
15567 rb_define_method(rb_cARGF, "read", argf_read, -1);
15568 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15569 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15570 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15571 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15572 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15573 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15574 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15575 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15576 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15577 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15578 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15579 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15580 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15581 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15582 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15583 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15584 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15585 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15586 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15587
15588 rb_define_method(rb_cARGF, "write", argf_write, 1);
15589 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15590 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15591 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15592 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15593
15594 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15595 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15596 rb_define_method(rb_cARGF, "file", argf_file, 0);
15597 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15598 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15599 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15600
15601 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15602 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15603
15604 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15605 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15606
15607 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15608 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15609 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15610
15611 argf = rb_class_new_instance(0, 0, rb_cARGF);
15612
15613 rb_define_readonly_variable("$<", &argf);
15614 /*
15615 * ARGF is a stream designed for use in scripts that process files given
15616 * as command-line arguments or passed in via STDIN.
15617 *
15618 * See ARGF (the class) for more details.
15619 */
15620 rb_define_global_const("ARGF", argf);
15621
15622 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15623 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15624 ARGF.filename = rb_str_new2("-");
15625
15626 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15627 rb_gvar_ractor_local("$-i");
15628
15629 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15630
15631#if defined (_WIN32) || defined(__CYGWIN__)
15632 atexit(pipe_atexit);
15633#endif
15634
15635 Init_File();
15636
15637 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15638
15639 sym_mode = ID2SYM(rb_intern_const("mode"));
15640 sym_perm = ID2SYM(rb_intern_const("perm"));
15641 sym_flags = ID2SYM(rb_intern_const("flags"));
15642 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15643 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15644 sym_encoding = ID2SYM(rb_id_encoding());
15645 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15646 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15647 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15648 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15649 sym_normal = ID2SYM(rb_intern_const("normal"));
15650 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15651 sym_random = ID2SYM(rb_intern_const("random"));
15652 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15653 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15654 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15655 sym_SET = ID2SYM(rb_intern_const("SET"));
15656 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15657 sym_END = ID2SYM(rb_intern_const("END"));
15658#ifdef SEEK_DATA
15659 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15660#endif
15661#ifdef SEEK_HOLE
15662 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15663#endif
15664 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15665 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15666}
15667
15668#include "io.rbinc"
rb_atomic_t
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
buffer.h
ruby_strtoul
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:137
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition cxxanyargs.hpp:670
rb_define_singleton_method
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition cxxanyargs.hpp:685
rb_define_global_function
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
Definition cxxanyargs.hpp:695
rb_include_module
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1177
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:970
rb_class_new
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:350
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1002
rb_define_module_under
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1109
rb_define_alias
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2336
rb_scan_args_kw
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
Definition class.c:2639
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:2626
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:866
rb_get_kwargs
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2415
ECONV_AFTER_OUTPUT
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
rb_str_new2
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
TYPE
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:107
NEWOBJ_OF
#define NEWOBJ_OF
Old name of RB_NEWOBJ_OF.
Definition newobj.h:61
FL_SINGLETON
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
Definition fl_type.h:58
RB_INTEGER_TYPE_P
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
ENC_CODERANGE_7BIT
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
T_FILE
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
ENC_CODERANGE_VALID
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
ECONV_UNIVERSAL_NEWLINE_DECORATOR
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
OBJ_INIT_COPY
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
ALLOC
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:394
T_STRING
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
Qundef
#define Qundef
Old name of RUBY_Qundef.
Definition special_consts.h:62
INT2FIX
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
rb_str_cat2
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
T_NIL
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
UNREACHABLE
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
ID2SYM
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
T_BIGNUM
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
OBJ_FREEZE
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:135
T_FIXNUM
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
FIX2UINT
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
SSIZET2NUM
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
ZALLOC
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:396
CLASS_OF
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
rb_ary_new4
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:653
ENCODING_MAXNAMELEN
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:110
MBCLEN_NEEDMORE_LEN
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:519
ENCODING_GET
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:108
LONG2FIX
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
NUM2UINT
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
ALLOC_N
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:393
MBCLEN_CHARFOUND_LEN
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:516
LONG2NUM
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
rb_exc_new3
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
STRNCASECMP
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
MBCLEN_INVALID_P
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:517
ISASCII
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
ECONV_STATEFUL_DECORATOR_MASK
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
Qtrue
#define Qtrue
Old name of RUBY_Qtrue.
Definition special_consts.h:61
MBCLEN_NEEDMORE_P
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:518
ECONV_PARTIAL_INPUT
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
NUM2INT
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
ECONV_ERROR_HANDLER_MASK
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
INT2NUM
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
Qnil
#define Qnil
Old name of RUBY_Qnil.
Definition special_consts.h:60
Qfalse
#define Qfalse
Old name of RUBY_Qfalse.
Definition special_consts.h:59
FIX2LONG
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
ENC_CODERANGE_BROKEN
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
T_ARRAY
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
NIL_P
#define NIL_P
Old name of RB_NIL_P.
Definition special_consts.h:55
ALLOCV_N
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:399
MBCLEN_CHARFOUND_P
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:515
NUM2CHR
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
FL_TEST
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:131
NUM2LONG
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
UINT2NUM
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
FIXNUM_P
#define FIXNUM_P
Old name of RB_FIXNUM_P.
Definition special_consts.h:53
ECONV_NEWLINE_DECORATOR_MASK
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
CONST_ID
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
rb_ary_new2
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:651
NUM2SIZET
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
ENC_CODERANGE_SET
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
rb_str_new4
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1677
ALLOCV_END
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:400
SYMBOL_P
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
ECONV_DEFAULT_NEWLINE_DECORATOR
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
rb_notimplement
void rb_notimplement(void)
Definition error.c:3498
rb_category_warn
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:433
rb_category_warning
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:465
rb_eNotImpError
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1354
rb_syserr_fail
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3567
rb_readwrite_syserr_fail
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
Definition io.c:14577
rb_eIOError
VALUE rb_eIOError
IOError exception.
Definition io.c:178
rb_eStandardError
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1341
rb_mod_syserr_fail_str
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3657
rb_syserr_fail_str
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3573
ruby_verbose
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:471
rb_eTypeError
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1344
rb_eEOFError
VALUE rb_eEOFError
EOFError exception.
Definition io.c:177
rb_readwrite_sys_fail
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14571
rb_iter_break_value
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2049
rb_io_wait_readwrite
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:69
rb_eRuntimeError
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1342
rb_warn
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:423
rb_eSystemCallError
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1364
RB_WARN_CATEGORY_DEPRECATED
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
rb_mKernel
VALUE rb_mKernel
Kernel module.
Definition object.c:63
rb_check_to_int
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3151
rb_any_to_s
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:634
rb_obj_alloc
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2058
rb_class_new_instance
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2099
rb_cIO
VALUE rb_cIO
IO class.
Definition io.c:176
rb_class_new_instance_kw
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
Definition object.c:2087
rb_mEnumerable
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
rb_stdin
VALUE rb_stdin
STDIN constant.
Definition io.c:190
rb_stderr
VALUE rb_stderr
STDERR constant.
Definition io.c:190
rb_obj_class
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:215
rb_obj_dup
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:541
rb_inspect
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:645
rb_mWaitReadable
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:180
rb_mWaitWritable
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:181
rb_check_to_integer
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
Definition object.c:3132
rb_cFile
VALUE rb_cFile
File class.
Definition file.c:175
rb_stdout
VALUE rb_stdout
STDOUT constant.
Definition io.c:190
rb_to_int
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3145
rb_enc_left_char_head
static char * rb_enc_left_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the left boundary of a character.
Definition encoding.h:682
rb_enc_codepoint
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition encoding.h:570
rb_enc_mbminlen
static int rb_enc_mbminlen(rb_encoding *enc)
Queries the minimum number of bytes that the passed encoding needs to represent a character.
Definition encoding.h:431
rb_enc_uint_chr
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3739
rb_str_coderange_scan_restartable
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:653
rb_econv_prepare_options
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2600
rb_econv_open_exc
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2097
rb_econv_convert
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1475
rb_econv_result_t
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
econv_incomplete_input
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
econv_finished
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
econv_undefined_conversion
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
econv_source_buffer_empty
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
econv_destination_buffer_full
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
econv_invalid_byte_sequence
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
rb_econv_putbackable
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1770
rb_econv_asciicompat_encoding
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1814
rb_econv_str_convert
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1931
rb_econv_open_opts
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2651
rb_econv_binmode
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:1996
rb_str_encode
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2914
rb_econv_make_exception
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4272
rb_econv_check_error
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4278
rb_econv_close
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1731
rb_econv_putback
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1781
rb_funcall
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1121
rb_funcallv_kw
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1088
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:239
rb_check_frozen
#define rb_check_frozen
Just another name of rb_check_frozen.
Definition error.h:264
rb_check_arity
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:280
rb_io_printf
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8540
rb_io_gets
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4233
rb_cloexec_pipe
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:405
rb_io_print
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8666
rb_io_addstr
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2317
rb_write_error
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9095
rb_io_ungetbyte
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
Definition io.c:5101
rb_io_getbyte
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5007
rb_cloexec_dup2
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:352
rb_io_fdopen
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
Definition io.c:9255
rb_update_max_fd
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:226
rb_cloexec_open
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:306
rb_output_rs
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:195
rb_io_eof
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2662
rb_write_error2
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9075
rb_close_before_exec
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
rb_reserved_fd_p
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
rb_fd_fix_cloexec
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
Definition io.c:276
rb_io_ascii8bit_binmode
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6308
rb_io_binmode
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6262
rb_io_ungetc
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5165
rb_pipe
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7300
rb_gets
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10317
rb_cloexec_fcntl_dupfd
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:439
rb_file_open_str
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
Definition io.c:7183
rb_cloexec_dup
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:345
rb_file_open
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7190
rb_io_close
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5688
rb_lastline_set
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:1811
rb_lastline_get
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1805
rb_obj_method_arity
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
Definition proc.c:2853
rb_waitpid
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1269
rb_last_status_set
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:682
rb_str_append
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3409
rb_str_new
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
rb_str_buf_cat
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
rb_usascii_str_new
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1532
rb_str_capacity
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:815
rb_str_locktmp
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_str_setter
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
rb_str_buf_cat_ascii
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
Definition string.c:3351
rb_check_string_type
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2681
rb_str_substr
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:2977
rb_str_unlocktmp
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3070
rb_str_modify_expand
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2486
rb_str_new_cstr
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
rb_thread_interrupted
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1435
rb_mutex_new
VALUE rb_mutex_new(void)
Creates a mutex.
Definition thread_sync.c:191
rb_thread_fd_writable
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
Definition io.c:1572
RUBY_UBF_IO
#define RUBY_UBF_IO
A special UBF for blocking IO operations.
Definition thread.h:382
rb_exec_recursive
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
Definition thread.c:5260
rb_thread_fd_close
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
Definition thread.c:2644
rb_mutex_synchronize
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
Definition thread_sync.c:634
rb_thread_check_ints
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1418
rb_thread_current
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:2921
rb_thread_wait_fd
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1566
rb_thread_sleep
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1441
rb_time_interval
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2875
rb_set_class_path
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:343
rb_ivar_set
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1854
rb_class_name
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:402
rb_respond_to
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:2937
rb_check_funcall
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:687
rb_define_alloc_func
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
rb_intern_const
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:276
RB_ID2SYM
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
rb_define_global_const
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:3702
rb_define_readonly_variable
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:722
rb_gvar_readonly_setter
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
rb_define_const
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition variable.c:3690
io.h
FMODE_READABLE
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:270
rb_io_modestr_fmode
int rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6394
rb_io_get_io
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:792
rb_io_timeout
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:838
rb_io_taint_check
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:762
rb_io_read_check
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1049
rb_io_modestr_oflags
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
Definition io.c:6527
FMODE_SETENC_BY_BOM
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
Definition io.h:368
rb_io_mode
int rb_io_mode(VALUE io)
Get the mode of the IO.
Definition io.c:2883
rb_io_event
rb_io_event
Type of events that an IO can wait.
Definition io.h:81
RUBY_IO_READABLE
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:82
RUBY_IO_PRIORITY
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:84
RUBY_IO_WRITABLE
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:83
FMODE_READWRITE
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:276
FMODE_EXTERNAL
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:360
GetOpenFile
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:402
rb_io_check_byte_readable
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:995
FMODE_TTY
#define FMODE_TTY
The IO is a TTY.
Definition io.h:300
FMODE_CREATE
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:323
rb_io_check_readable
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1004
rb_io_extract_encoding_option
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:6676
rb_io_oflags_fmode
int rb_io_oflags_fmode(int oflags)
Converts an oflags (that rb_io_modestr_oflags() returns) to a fmode (that rb_io_mode_flags() returns)...
Definition io.c:6451
rb_wait_for_single_fd
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition io.c:1560
rb_fdopen
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
Definition io.c:7007
rb_io_descriptor
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2863
FMODE_WRITABLE
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:273
rb_io_stdio_file
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
Definition io.c:9301
FMODE_APPEND
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:315
MakeOpenFile
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:425
FMODE_DUPLEX
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:308
FMODE_BINMODE
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:287
rb_io_maybe_wait_readable
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1619
capa
int capa
Designed capacity of the buffer.
Definition io.h:11
RB_IO_POINTER
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:396
rb_io_maybe_wait
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1578
rb_eIOTimeoutError
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:179
ptr
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
FMODE_SYNC
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:294
off
int off
Offset inside of ptr.
Definition io.h:5
rb_io_path
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:2937
rb_io_check_initialized
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:769
FMODE_EXCL
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
Definition io.h:331
FMODE_TEXTMODE
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:351
rb_io_check_io
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
Definition io.c:798
rb_io_closed_p
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5793
rb_io_set_timeout
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:867
rb_io_bufwrite
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:1982
rb_io_check_char_readable
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:976
FMODE_TRUNC
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:337
rb_io_read_pending
int rb_io_read_pending(rb_io_t *fptr)
Queries if the passed IO has any pending reads.
Definition io.c:1040
rb_io_get_write_io
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:804
rb_io_set_nonblock
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3389
rb_io_extract_modeenc
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:6801
rb_io_wait_writable
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1517
rb_io_open_descriptor
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
Definition io.c:9188
rb_io_set_write_io
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:815
rb_io_check_writable
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1028
rb_io_maybe_wait_writable
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
Definition io.c:1632
rb_io_check_closed
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:777
rb_eof_error
void rb_eof_error(void)
Utility function to raise rb_eEOFError.
Definition io.c:756
rb_io_wait_readable
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1483
rb_io_synchronized
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7287
rb_io_wait
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1422
len
int len
Length of the buffer.
Definition io.h:8
ractor.h
rb_ractor_stdin
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:2671
rb_ractor_stderr_set
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
Definition ractor.c:2731
rb_ractor_stdout_set
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
Definition ractor.c:2719
rb_ractor_stdin_set
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
Definition ractor.c:2707
thread.h
rb_thread_call_with_gvl
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:1832
rb_thread_call_without_gvl
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
Definition thread.c:1658
util.h
RB_NUM2INT
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
RB_INT2NUM
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
rb_f_sprintf
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:208
RB_BLOCK_CALL_FUNC_ARGLIST
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
rb_yield_values2
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1410
rb_yield
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1376
rb_fd_term
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
MEMZERO
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:354
RB_GC_GUARD
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
MEMMOVE
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:378
NUM2MODET
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
ruby::backward::cxxanyargs::rb_define_hooked_variable
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
Definition cxxanyargs.hpp:136
ruby::backward::cxxanyargs::rb_define_virtual_variable
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
Definition cxxanyargs.hpp:73
ruby::backward::cxxanyargs::rb_rescue2
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
Definition cxxanyargs.hpp:284
ruby::backward::cxxanyargs::rb_ensure
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
Definition cxxanyargs.hpp:310
PRI_OFFT_PREFIX
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
OFFT2NUM
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
NUM2OFFT
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
PIDT2NUM
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
rb_fd_isset
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
rb_fd_select
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
rb_fd_init
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
rb_fd_set
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
RARRAY_LEN
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
RARRAY_LENINT
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition rarray.h:403
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
RFILE
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
SafeStringValue
#define SafeStringValue(v)
Definition rstring.h:98
StringValue
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
RSTRING_GETMEM
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:488
StringValueCStr
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
RUBY_TYPED_DEFAULT_FREE
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:79
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:497
rb_get_argv
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14537
rb_p
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:8974
FilePathValue
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
errno
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
RB_SCAN_ARGS_LAST_HASH_KEYWORDS
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
RB_PASS_CALLED_KEYWORDS
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
scheduler.h
Scheduler APIs.
rb_fiber_scheduler_current
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:219
rb_fiber_scheduler_io_pread_memory
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:623
rb_fiber_scheduler_make_timeout
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:262
rb_fiber_scheduler_io_wait_readable
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:435
rb_fiber_scheduler_io_read_memory
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:599
rb_fiber_scheduler_io_wait
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:429
rb_fiber_scheduler_io_result_apply
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:70
rb_fiber_scheduler_io_selectv
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:465
rb_fiber_scheduler_io_pwrite_memory
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:635
rb_fiber_scheduler_current_for_thread
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:224
rb_fiber_scheduler_io_write_memory
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:611
rb_fiber_scheduler_io_wait_writable
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:441
rb_thread_fd_select
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
Definition thread.c:4269
RB_TEST
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
Definition special_consts.h:138
RTEST
#define RTEST
This is an old name of RB_TEST.
Definition special_consts.h:51
_
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
stdbool.h
C99 shim for <stdbool.h>
__sFILE
Definition vsnprintf.c:160
OnigEncodingTypeST
Definition onigmo.h:160
RFile
Ruby's File and IO.
Definition rfile.h:35
argf_call_arg
Definition io.c:13820
argf
Definition io.c:214
binwrite_arg
Definition io.c:1700
bufread_arg
Definition io.c:3057
copy_stream_struct
Definition io.c:12352
fiber_scheduler_wait_for_arguments
Definition io.c:12406
finish_writeconv_arg
Definition io.c:5395
foreach_arg
Definition io.c:11863
getline_arg
Definition io.c:4010
io_encoding_set_args
Definition io.c:11677
io_internal_read_struct
Definition io.c:1104
io_internal_write_struct
Definition io.c:1115
iovec
Definition win32.h:218
pipe_list
Definition io.c:7196
prdwr_internal_arg
Definition io.c:6091
rb_data_type_struct
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:200
rb_execarg
Definition process.h:30
rb_execution_context_struct
Definition vm_core.h:986
rb_fdset_t
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
rb_global_variable
Definition variable.c:429
rb_io_close_wait_list
Definition thread.h:57
rb_io_encoding
Decomposed encoding flags (e.g.
Definition io.h:119
rb_io_encoding::ecflags
int ecflags
Flags.
Definition io.h:129
rb_io_encoding::ecopts
VALUE ecopts
Flags as Ruby hash.
Definition io.h:137
rb_io_encoding::enc2
rb_encoding * enc2
External encoding.
Definition io.h:123
rb_io_encoding::enc
rb_encoding * enc
Internal encoding.
Definition io.h:121
rb_io_internal_buffer
IO buffers.
Definition io.h:94
rb_io_internal_buffer::ptr
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:97
rb_io_internal_buffer::off
int off
Offset inside of ptr.
Definition io.h:100
rb_io_internal_buffer::len
int len
Length of the buffer.
Definition io.h:103
rb_io_internal_buffer::capa
int capa
Designed capacity of the buffer.
Definition io.h:106
rb_io
Ruby's IO, metadata and buffers.
Definition io.h:143
rb_io::mode
int mode
mode flags: FMODE_XXXs
Definition io.h:158
rb_io::wbuf
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:178
rb_io::finalize
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:174
rb_io::readconv
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:200
rb_io::writeconv
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:211
rb_io::encs
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:196
rb_io::self
VALUE self
The IO's Ruby level counterpart.
Definition io.h:146
rb_io::write_lock
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:248
rb_io::timeout
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:254
rb_io::stdio_file
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:150
rb_io::writeconv_pre_ecopts
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:238
rb_io::tied_io_for_writing
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:193
rb_io::writeconv_initialized
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:224
rb_io::fd
int fd
file descriptor.
Definition io.h:154
rb_io::rbuf
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:185
rb_io::lineno
int lineno
number of lines read
Definition io.h:166
rb_io::writeconv_asciicompat
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:220
rb_io::cbuf
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:207
rb_io::pid
rb_pid_t pid
child's pid (for pipes)
Definition io.h:162
rb_io::writeconv_pre_ecflags
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:231
rb_io::pathv
VALUE pathv
pathname for file
Definition io.h:170
seek_arg
Definition io.c:12094
select_args
Definition io.c:10685
sysopen_struct
Definition io.c:6946
timeval
Definition missing.h:63
write_arg
Definition io.c:1707
SIGNED_VALUE
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
ID
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
RB_SYMBOL_P
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:306
Check_Type
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:432