Ruby: io.c Source File

Ruby 3.2.5p208 (2024-07-26 revision 31d0f1a2e7dbfb60731d1f05b868e1d578cda493)

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#ifdef _WIN32
20# include "ruby/ruby.h"
21# include "ruby/io.h"
22#endif
23
24#include <ctype.h>
25#include <errno.h>
26#include <stddef.h>
27
28/* non-Linux poll may not work on all FDs */
29#if defined(HAVE_POLL)
30# if defined(__linux__)
31# define USE_POLL 1
32# endif
33# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
34# define USE_POLL 1
35# endif
36#endif
37
38#ifndef USE_POLL
39# define USE_POLL 0
40#endif
41
42#undef free
43#define free(x) xfree(x)
44
45#if defined(DOSISH) || defined(__CYGWIN__)
46#include <io.h>
47#endif
48
49#include <sys/types.h>
50#if defined HAVE_NET_SOCKET_H
51# include <net/socket.h>
52#elif defined HAVE_SYS_SOCKET_H
53# include <sys/socket.h>
54#endif
55
56#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
57# define NO_SAFE_RENAME
58#endif
59
60#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
61# define USE_SETVBUF
62#endif
63
64#ifdef __QNXNTO__
65#include <unix.h>
66#endif
67
68#include <sys/types.h>
69#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
70#include <sys/ioctl.h>
71#endif
72#if defined(HAVE_FCNTL_H) || defined(_WIN32)
73#include <fcntl.h>
74#elif defined(HAVE_SYS_FCNTL_H)
75#include <sys/fcntl.h>
76#endif
77
78#ifdef HAVE_SYS_TIME_H
79# include <sys/time.h>
80#endif
81
82#include <sys/stat.h>
83
84#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
85# include <sys/param.h>
86#endif
87
88#if !defined NOFILE
89# define NOFILE 64
90#endif
91
92#ifdef HAVE_UNISTD_H
93#include <unistd.h>
94#endif
95
96#ifdef HAVE_SYSCALL_H
97#include <syscall.h>
98#elif defined HAVE_SYS_SYSCALL_H
99#include <sys/syscall.h>
100#endif
101
102#ifdef HAVE_SYS_UIO_H
103#include <sys/uio.h>
104#endif
105
106#ifdef HAVE_SYS_WAIT_H
107# include <sys/wait.h> /* for WNOHANG on BSD */
108#endif
109
110#ifdef HAVE_COPYFILE_H
111# include <copyfile.h>
112#endif
113
114#include "ruby/internal/stdbool.h"
115#include "ccan/list/list.h"
116#include "dln.h"
117#include "encindex.h"
118#include "id.h"
119#include "internal.h"
120#include "internal/encoding.h"
121#include "internal/error.h"
122#include "internal/inits.h"
123#include "internal/io.h"
124#include "internal/numeric.h"
125#include "internal/object.h"
126#include "internal/process.h"
127#include "internal/thread.h"
128#include "internal/transcode.h"
129#include "internal/variable.h"
130#include "ruby/io.h"
131#include "ruby/io/buffer.h"
132#include "ruby/missing.h"
133#include "ruby/thread.h"
134#include "ruby/util.h"
135#include "ruby_atomic.h"
136#include "ruby/ractor.h"
137
138#if !USE_POLL
139# include "vm_core.h"
140#endif
141
142#include "builtin.h"
143
144#ifndef O_ACCMODE
145#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
146#endif
147
148#ifndef PIPE_BUF
149# ifdef _POSIX_PIPE_BUF
150# define PIPE_BUF _POSIX_PIPE_BUF
151# else
152# define PIPE_BUF 512 /* is this ok? */
153# endif
154#endif
155
156#ifndef EWOULDBLOCK
157# define EWOULDBLOCK EAGAIN
158#endif
159
160#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
161/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
162off_t __syscall(quad_t number, ...);
163#endif
164
165#define IO_RBUF_CAPA_MIN 8192
166#define IO_CBUF_CAPA_MIN (128*1024)
167#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
168#define IO_WBUF_CAPA_MIN 8192
169
170#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
171
172/* define system APIs */
173#ifdef _WIN32
174#undef open
175#define open rb_w32_uopen
176#undef rename
177#define rename(f, t) rb_w32_urename((f), (t))
178#endif
179
180 VALUE rb_cIO;
181 VALUE rb_eEOFError;
182 VALUE rb_eIOError;
183 VALUE rb_eIOTimeoutError;
184 VALUE rb_mWaitReadable;
185 VALUE rb_mWaitWritable;
186
187static VALUE rb_eEAGAINWaitReadable;
188static VALUE rb_eEAGAINWaitWritable;
189static VALUE rb_eEWOULDBLOCKWaitReadable;
190static VALUE rb_eEWOULDBLOCKWaitWritable;
191static VALUE rb_eEINPROGRESSWaitWritable;
192static VALUE rb_eEINPROGRESSWaitReadable;
193
194 VALUE rb_stdin, rb_stdout, rb_stderr;
195static VALUE orig_stdout, orig_stderr;
196
197 VALUE rb_output_fs;
198 VALUE rb_rs;
199 VALUE rb_output_rs;
200 VALUE rb_default_rs;
201
202static VALUE argf;
203
204static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
205static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
206static VALUE sym_textmode, sym_binmode, sym_autoclose;
207static VALUE sym_SET, sym_CUR, sym_END;
208static VALUE sym_wait_readable, sym_wait_writable;
209#ifdef SEEK_DATA
210static VALUE sym_DATA;
211#endif
212#ifdef SEEK_HOLE
213static VALUE sym_HOLE;
214#endif
215
216static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
217
218 struct argf {
219 VALUE filename, current_file;
220 long last_lineno; /* $. */
221 long lineno;
222 VALUE argv;
223 VALUE inplace;
224 struct rb_io_enc_t encs;
225 int8_t init_p, next_p, binmode;
226};
227
228static rb_atomic_t max_file_descriptor = NOFILE;
229void
230rb_update_max_fd(int fd)
231{
232 rb_atomic_t afd = (rb_atomic_t)fd;
233 rb_atomic_t max_fd = max_file_descriptor;
234 int err;
235
236 if (fd < 0 || afd <= max_fd)
237 return;
238
239#if defined(HAVE_FCNTL) && defined(F_GETFL)
240 err = fcntl(fd, F_GETFL) == -1;
241#else
242 {
243 struct stat buf;
244 err = fstat(fd, &buf) != 0;
245 }
246#endif
247 if (err && errno == EBADF) {
248 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
249 }
250
251 while (max_fd < afd) {
252 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
253 }
254}
255
256void
257rb_maygvl_fd_fix_cloexec(int fd)
258{
259 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
260#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
261 int flags, flags2, ret;
262 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
263 if (flags == -1) {
264 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
265 }
266 if (fd <= 2)
267 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
268 else
269 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
270 if (flags != flags2) {
271 ret = fcntl(fd, F_SETFD, flags2);
272 if (ret != 0) {
273 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
274 }
275 }
276#endif
277}
278
279void
280rb_fd_fix_cloexec(int fd)
281{
282 rb_maygvl_fd_fix_cloexec(fd);
283 rb_update_max_fd(fd);
284}
285
286/* this is only called once */
287static int
288rb_fix_detect_o_cloexec(int fd)
289{
290#if defined(O_CLOEXEC) && defined(F_GETFD)
291 int flags = fcntl(fd, F_GETFD);
292
293 if (flags == -1)
294 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
295
296 if (flags & FD_CLOEXEC)
297 return 1;
298#endif /* fall through if O_CLOEXEC does not work: */
299 rb_maygvl_fd_fix_cloexec(fd);
300 return 0;
301}
302
303static inline bool
304io_again_p(int e)
305{
306 return (e == EWOULDBLOCK) || (e == EAGAIN);
307}
308
309int
310rb_cloexec_open(const char *pathname, int flags, mode_t mode)
311{
312 int ret;
313 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
314
315 static const int retry_interval = 0;
316 static const int retry_max_count = 10000;
317
318 int retry_count = 0;
319
320#ifdef O_CLOEXEC
321 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
322 flags |= O_CLOEXEC;
323#elif defined O_NOINHERIT
324 flags |= O_NOINHERIT;
325#endif
326
327 while ((ret = open(pathname, flags, mode)) == -1) {
328 int e = errno;
329 if (!io_again_p(e)) break;
330 if (retry_count++ >= retry_max_count) break;
331
332 sleep(retry_interval);
333 }
334
335 if (ret < 0) return ret;
336 if (ret <= 2 || o_cloexec_state == 0) {
337 rb_maygvl_fd_fix_cloexec(ret);
338 }
339 else if (o_cloexec_state > 0) {
340 return ret;
341 }
342 else {
343 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
344 }
345 return ret;
346}
347
348int
349rb_cloexec_dup(int oldfd)
350{
351 /* Don't allocate standard file descriptors: 0, 1, 2 */
352 return rb_cloexec_fcntl_dupfd(oldfd, 3);
353}
354
355int
356rb_cloexec_dup2(int oldfd, int newfd)
357{
358 int ret;
359
360 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
361 * rb_cloexec_dup2 succeeds as dup2. */
362 if (oldfd == newfd) {
363 ret = newfd;
364 }
365 else {
366#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
367 static int try_dup3 = 1;
368 if (2 < newfd && try_dup3) {
369 ret = dup3(oldfd, newfd, O_CLOEXEC);
370 if (ret != -1)
371 return ret;
372 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
373 if (errno == ENOSYS) {
374 try_dup3 = 0;
375 ret = dup2(oldfd, newfd);
376 }
377 }
378 else {
379 ret = dup2(oldfd, newfd);
380 }
381#else
382 ret = dup2(oldfd, newfd);
383#endif
384 if (ret < 0) return ret;
385 }
386 rb_maygvl_fd_fix_cloexec(ret);
387 return ret;
388}
389
390static int
391rb_fd_set_nonblock(int fd)
392{
393#ifdef _WIN32
394 return rb_w32_set_nonblock(fd);
395#elif defined(F_GETFL)
396 int oflags = fcntl(fd, F_GETFL);
397
398 if (oflags == -1)
399 return -1;
400 if (oflags & O_NONBLOCK)
401 return 0;
402 oflags |= O_NONBLOCK;
403 return fcntl(fd, F_SETFL, oflags);
404#endif
405 return 0;
406}
407
408int
409rb_cloexec_pipe(int descriptors[2])
410{
411#ifdef HAVE_PIPE2
412 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
413#else
414 int result = pipe(descriptors);
415#endif
416
417 if (result < 0)
418 return result;
419
420#ifdef __CYGWIN__
421 if (result == 0 && descriptors[1] == -1) {
422 close(descriptors[0]);
423 descriptors[0] = -1;
424 errno = ENFILE;
425 return -1;
426 }
427#endif
428
429#ifndef HAVE_PIPE2
430 rb_maygvl_fd_fix_cloexec(descriptors[0]);
431 rb_maygvl_fd_fix_cloexec(descriptors[1]);
432
433#ifndef _WIN32
434 rb_fd_set_nonblock(descriptors[0]);
435 rb_fd_set_nonblock(descriptors[1]);
436#endif
437#endif
438
439 return result;
440}
441
442int
443rb_cloexec_fcntl_dupfd(int fd, int minfd)
444{
445 int ret;
446
447#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
448 static int try_dupfd_cloexec = 1;
449 if (try_dupfd_cloexec) {
450 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
451 if (ret != -1) {
452 if (ret <= 2)
453 rb_maygvl_fd_fix_cloexec(ret);
454 return ret;
455 }
456 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
457 if (errno == EINVAL) {
458 ret = fcntl(fd, F_DUPFD, minfd);
459 if (ret != -1) {
460 try_dupfd_cloexec = 0;
461 }
462 }
463 }
464 else {
465 ret = fcntl(fd, F_DUPFD, minfd);
466 }
467#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
468 ret = fcntl(fd, F_DUPFD, minfd);
469#else
470 ret = dup(fd);
471 if (ret >= 0 && ret < minfd) {
472 const int prev_fd = ret;
473 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
474 close(prev_fd);
475 }
476 return ret;
477#endif
478 if (ret < 0) return ret;
479 rb_maygvl_fd_fix_cloexec(ret);
480 return ret;
481}
482
483#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
484#define ARGF argf_of(argf)
485
486#define GetWriteIO(io) rb_io_get_write_io(io)
487
488#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
489#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
490#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
491#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
492
493#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
494#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
495#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
496
497#if defined(_WIN32)
498#define WAIT_FD_IN_WIN32(fptr) \
499 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
500#else
501#define WAIT_FD_IN_WIN32(fptr)
502#endif
503
504#define READ_CHECK(fptr) do {\
505 if (!READ_DATA_PENDING(fptr)) {\
506 WAIT_FD_IN_WIN32(fptr);\
507 rb_io_check_closed(fptr);\
508 }\
509} while(0)
510
511#ifndef S_ISSOCK
512# ifdef _S_ISSOCK
513# define S_ISSOCK(m) _S_ISSOCK(m)
514# else
515# ifdef _S_IFSOCK
516# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
517# else
518# ifdef S_IFSOCK
519# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
520# endif
521# endif
522# endif
523#endif
524
525static int io_fflush(rb_io_t *);
526static rb_io_t *flush_before_seek(rb_io_t *fptr);
527
528#define FMODE_PREP (1<<16)
529#define FMODE_SIGNAL_ON_EPIPE (1<<17)
530
531#define fptr_signal_on_epipe(fptr) \
532 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
533
534#define fptr_set_signal_on_epipe(fptr, flag) \
535 ((flag) ? \
536 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
537 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
538
539extern ID ruby_static_id_signo;
540
541NORETURN(static void raise_on_write(rb_io_t *fptr, int e, VALUE errinfo));
542static void
543raise_on_write(rb_io_t *fptr, int e, VALUE errinfo)
544{
545#if defined EPIPE
546 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
547 const VALUE sig =
548# if defined SIGPIPE
549 INT2FIX(SIGPIPE) - INT2FIX(0) +
550# endif
551 INT2FIX(0);
552 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
553 }
554#endif
555 rb_exc_raise(errinfo);
556}
557
558#define rb_sys_fail_on_write(fptr) \
559 do { \
560 int e = errno; \
561 raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
562 } while (0)
563
564#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
565#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
566#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
567# define RUBY_CRLF_ENVIRONMENT 1
568#else
569# define RUBY_CRLF_ENVIRONMENT 0
570#endif
571
572#if RUBY_CRLF_ENVIRONMENT
573/* Windows */
574# define DEFAULT_TEXTMODE FMODE_TEXTMODE
575# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
576/*
577 * CRLF newline is set as default newline decorator.
578 * If only CRLF newline conversion is needed, we use binary IO process
579 * with OS's text mode for IO performance improvement.
580 * If encoding conversion is needed or a user sets text mode, we use encoding
581 * conversion IO process and universal newline decorator by default.
582 */
583#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
584#define WRITECONV_MASK ( \
585 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
586 ECONV_STATEFUL_DECORATOR_MASK|\
587 0)
588#define NEED_WRITECONV(fptr) ( \
589 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
590 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
591 0)
592#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
593
594#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
595 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
596 if (((fptr)->mode & FMODE_READABLE) &&\
597 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
598 setmode((fptr)->fd, O_BINARY);\
599 }\
600 else {\
601 setmode((fptr)->fd, O_TEXT);\
602 }\
603 }\
604} while(0)
605
606#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
607 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
608 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
609 }\
610} while(0)
611
612/*
613 * IO unread with taking care of removed '\r' in text mode.
614 */
615static void
616io_unread(rb_io_t *fptr)
617{
618 rb_off_t r, pos;
619 ssize_t read_size;
620 long i;
621 long newlines = 0;
622 long extra_max;
623 char *p;
624 char *buf;
625
626 rb_io_check_closed(fptr);
627 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
628 return;
629 }
630
631 errno = 0;
632 if (!rb_w32_fd_is_text(fptr->fd)) {
633 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
634 if (r < 0 && errno) {
635 if (errno == ESPIPE)
636 fptr->mode |= FMODE_DUPLEX;
637 return;
638 }
639
640 fptr->rbuf.off = 0;
641 fptr->rbuf.len = 0;
642 return;
643 }
644
645 pos = lseek(fptr->fd, 0, SEEK_CUR);
646 if (pos < 0 && errno) {
647 if (errno == ESPIPE)
648 fptr->mode |= FMODE_DUPLEX;
649 return;
650 }
651
652 /* add extra offset for removed '\r' in rbuf */
653 extra_max = (long)(pos - fptr->rbuf.len);
654 p = fptr->rbuf.ptr + fptr->rbuf.off;
655
656 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
657 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
658 newlines++;
659 }
660
661 for (i = 0; i < fptr->rbuf.len; i++) {
662 if (*p == '\n') newlines++;
663 if (extra_max == newlines) break;
664 p++;
665 }
666
667 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
668 while (newlines >= 0) {
669 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
670 if (newlines == 0) break;
671 if (r < 0) {
672 newlines--;
673 continue;
674 }
675 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
676 if (read_size < 0) {
677 int e = errno;
678 free(buf);
679 rb_syserr_fail_path(e, fptr->pathv);
680 }
681 if (read_size == fptr->rbuf.len) {
682 lseek(fptr->fd, r, SEEK_SET);
683 break;
684 }
685 else {
686 newlines--;
687 }
688 }
689 free(buf);
690 fptr->rbuf.off = 0;
691 fptr->rbuf.len = 0;
692 return;
693}
694
695/*
696 * We use io_seek to back cursor position when changing mode from text to binary,
697 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
698 * conversion for working properly with mode change.
699 *
700 * Return previous translation mode.
701 */
702static inline int
703set_binary_mode_with_seek_cur(rb_io_t *fptr)
704{
705 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
706
707 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
708 return setmode(fptr->fd, O_BINARY);
709 }
710 flush_before_seek(fptr);
711 return setmode(fptr->fd, O_BINARY);
712}
713#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
714
715#else
716/* Unix */
717# define DEFAULT_TEXTMODE 0
718#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
719#define NEED_WRITECONV(fptr) ( \
720 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
721 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
722 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
723 0)
724#define SET_BINARY_MODE(fptr) (void)(fptr)
725#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
726#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
728#endif
729
730#if !defined HAVE_SHUTDOWN && !defined shutdown
731#define shutdown(a,b) 0
732#endif
733
734#if defined(_WIN32)
735#define is_socket(fd, path) rb_w32_is_socket(fd)
736#elif !defined(S_ISSOCK)
737#define is_socket(fd, path) 0
738#else
739static int
740is_socket(int fd, VALUE path)
741{
742 struct stat sbuf;
743 if (fstat(fd, &sbuf) < 0)
744 rb_sys_fail_path(path);
745 return S_ISSOCK(sbuf.st_mode);
746}
747#endif
748
749static const char closed_stream[] = "closed stream";
750
751static void
752io_fd_check_closed(int fd)
753{
754 if (fd < 0) {
755 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
756 rb_raise(rb_eIOError, closed_stream);
757 }
758}
759
760void
761rb_eof_error(void)
762{
763 rb_raise(rb_eEOFError, "end of file reached");
764}
765
766 VALUE
767rb_io_taint_check(VALUE io)
768{
769 rb_check_frozen(io);
770 return io;
771}
772
773void
774rb_io_check_initialized(rb_io_t *fptr)
775{
776 if (!fptr) {
777 rb_raise(rb_eIOError, "uninitialized stream");
778 }
779}
780
781void
782rb_io_check_closed(rb_io_t *fptr)
783{
784 rb_io_check_initialized(fptr);
785 io_fd_check_closed(fptr->fd);
786}
787
788static rb_io_t *
789rb_io_get_fptr(VALUE io)
790{
791 rb_io_t *fptr = RFILE(io)->fptr;
792 rb_io_check_initialized(fptr);
793 return fptr;
794}
795
796 VALUE
797rb_io_get_io(VALUE io)
798{
799 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
800}
801
802 VALUE
803rb_io_check_io(VALUE io)
804{
805 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
806}
807
808 VALUE
809rb_io_get_write_io(VALUE io)
810{
811 VALUE write_io;
812 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
813 if (write_io) {
814 return write_io;
815 }
816 return io;
817}
818
819 VALUE
820rb_io_set_write_io(VALUE io, VALUE w)
821{
822 VALUE write_io;
823 rb_io_t *fptr = rb_io_get_fptr(io);
824 if (!RTEST(w)) {
825 w = 0;
826 }
827 else {
828 GetWriteIO(w);
829 }
830 write_io = fptr->tied_io_for_writing;
831 fptr->tied_io_for_writing = w;
832 return write_io ? write_io : Qnil;
833}
834
835/*
836 * call-seq:
837 * timeout -> duration or nil
838 *
839 * Get the internal timeout duration or nil if it was not set.
840 *
841 */
842 VALUE
843rb_io_timeout(VALUE self)
844{
845 rb_io_t *fptr = rb_io_get_fptr(self);
846
847 return fptr->timeout;
848}
849
850/*
851 * call-seq:
852 * timeout = duration -> duration
853 * timeout = nil -> nil
854 *
855 * Set the internal timeout to the specified duration or nil. The timeout
856 * applies to all blocking operations where possible.
857 *
858 * This affects the following methods (but is not limited to): #gets, #puts,
859 * #read, #write, #wait_readable and #wait_writable. This also affects
860 * blocking socket operations like Socket#accept and Socket#connect.
861 *
862 * Some operations like File#open and IO#close are not affected by the
863 * timeout. A timeout during a write operation may leave the IO in an
864 * inconsistent state, e.g. data was partially written. Generally speaking, a
865 * timeout is a last ditch effort to prevent an application from hanging on
866 * slow I/O operations, such as those that occur during a slowloris attack.
867 */
868 VALUE
869rb_io_set_timeout(VALUE self, VALUE timeout)
870{
871 // Validate it:
872 if (RTEST(timeout)) {
873 rb_time_interval(timeout);
874 }
875
876 rb_io_t *fptr = rb_io_get_fptr(self);
877
878 fptr->timeout = timeout;
879
880 return self;
881}
882
883/*
884 * call-seq:
885 * IO.try_convert(object) -> new_io or nil
886 *
887 * Attempts to convert +object+ into an \IO object via method +to_io+;
888 * returns the new \IO object if successful, or +nil+ otherwise:
889 *
890 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
891 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
892 * IO.try_convert('STDOUT') # => nil
893 *
894 */
895static VALUE
896rb_io_s_try_convert(VALUE dummy, VALUE io)
897{
898 return rb_io_check_io(io);
899}
900
901#if !RUBY_CRLF_ENVIRONMENT
902static void
903io_unread(rb_io_t *fptr)
904{
905 rb_off_t r;
906 rb_io_check_closed(fptr);
907 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
908 return;
909 /* xxx: target position may be negative if buffer is filled by ungetc */
910 errno = 0;
911 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
912 if (r < 0 && errno) {
913 if (errno == ESPIPE)
914 fptr->mode |= FMODE_DUPLEX;
915 return;
916 }
917 fptr->rbuf.off = 0;
918 fptr->rbuf.len = 0;
919 return;
920}
921#endif
922
923static rb_encoding *io_input_encoding(rb_io_t *fptr);
924
925static void
926io_ungetbyte(VALUE str, rb_io_t *fptr)
927{
928 long len = RSTRING_LEN(str);
929
930 if (fptr->rbuf.ptr == NULL) {
931 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
932 fptr->rbuf.off = 0;
933 fptr->rbuf.len = 0;
934#if SIZEOF_LONG > SIZEOF_INT
935 if (len > INT_MAX)
936 rb_raise(rb_eIOError, "ungetbyte failed");
937#endif
938 if (len > min_capa)
939 fptr->rbuf.capa = (int)len;
940 else
941 fptr->rbuf.capa = min_capa;
942 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
943 }
944 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
945 rb_raise(rb_eIOError, "ungetbyte failed");
946 }
947 if (fptr->rbuf.off < len) {
948 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
949 fptr->rbuf.ptr+fptr->rbuf.off,
950 char, fptr->rbuf.len);
951 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
952 }
953 fptr->rbuf.off-=(int)len;
954 fptr->rbuf.len+=(int)len;
955 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
956}
957
958static rb_io_t *
959flush_before_seek(rb_io_t *fptr)
960{
961 if (io_fflush(fptr) < 0)
962 rb_sys_fail_on_write(fptr);
963 io_unread(fptr);
964 errno = 0;
965 return fptr;
966}
967
968#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
969#define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
970
971#ifndef SEEK_CUR
972# define SEEK_SET 0
973# define SEEK_CUR 1
974# define SEEK_END 2
975#endif
976
977void
978rb_io_check_char_readable(rb_io_t *fptr)
979{
980 rb_io_check_closed(fptr);
981 if (!(fptr->mode & FMODE_READABLE)) {
982 rb_raise(rb_eIOError, "not opened for reading");
983 }
984 if (fptr->wbuf.len) {
985 if (io_fflush(fptr) < 0)
986 rb_sys_fail_on_write(fptr);
987 }
988 if (fptr->tied_io_for_writing) {
989 rb_io_t *wfptr;
990 GetOpenFile(fptr->tied_io_for_writing, wfptr);
991 if (io_fflush(wfptr) < 0)
992 rb_sys_fail_on_write(wfptr);
993 }
994}
995
996void
997rb_io_check_byte_readable(rb_io_t *fptr)
998{
999 rb_io_check_char_readable(fptr);
1000 if (READ_CHAR_PENDING(fptr)) {
1001 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1002 }
1003}
1004
1005void
1006rb_io_check_readable(rb_io_t *fptr)
1007{
1008 rb_io_check_byte_readable(fptr);
1009}
1010
1011static rb_encoding*
1012io_read_encoding(rb_io_t *fptr)
1013{
1014 if (fptr->encs.enc) {
1015 return fptr->encs.enc;
1016 }
1017 return rb_default_external_encoding();
1018}
1019
1020static rb_encoding*
1021io_input_encoding(rb_io_t *fptr)
1022{
1023 if (fptr->encs.enc2) {
1024 return fptr->encs.enc2;
1025 }
1026 return io_read_encoding(fptr);
1027}
1028
1029void
1030rb_io_check_writable(rb_io_t *fptr)
1031{
1032 rb_io_check_closed(fptr);
1033 if (!(fptr->mode & FMODE_WRITABLE)) {
1034 rb_raise(rb_eIOError, "not opened for writing");
1035 }
1036 if (fptr->rbuf.len) {
1037 io_unread(fptr);
1038 }
1039}
1040
1041int
1042rb_io_read_pending(rb_io_t *fptr)
1043{
1044 /* This function is used for bytes and chars. Confusing. */
1045 if (READ_CHAR_PENDING(fptr))
1046 return 1; /* should raise? */
1047 return READ_DATA_PENDING(fptr);
1048}
1049
1050void
1051rb_io_read_check(rb_io_t *fptr)
1052{
1053 if (!READ_DATA_PENDING(fptr)) {
1054 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1055 }
1056 return;
1057}
1058
1059int
1060rb_gc_for_fd(int err)
1061{
1062 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1063 rb_gc();
1064 return 1;
1065 }
1066 return 0;
1067}
1068
1069static int
1070ruby_dup(int orig)
1071{
1072 int fd;
1073
1074 fd = rb_cloexec_dup(orig);
1075 if (fd < 0) {
1076 int e = errno;
1077 if (rb_gc_for_fd(e)) {
1078 fd = rb_cloexec_dup(orig);
1079 }
1080 if (fd < 0) {
1081 rb_syserr_fail(e, 0);
1082 }
1083 }
1084 rb_update_max_fd(fd);
1085 return fd;
1086}
1087
1088static VALUE
1089io_alloc(VALUE klass)
1090{
1091 NEWOBJ_OF(io, struct RFile, klass, T_FILE);
1092
1093 io->fptr = 0;
1094
1095 return (VALUE)io;
1096}
1097
1098#ifndef S_ISREG
1099# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1100#endif
1101
1102 struct io_internal_read_struct {
1103 VALUE th;
1104 rb_io_t *fptr;
1105 int nonblock;
1106 int fd;
1107
1108 void *buf;
1109 size_t capa;
1110 struct timeval *timeout;
1111};
1112
1113 struct io_internal_write_struct {
1114 VALUE th;
1115 rb_io_t *fptr;
1116 int nonblock;
1117 int fd;
1118
1119 const void *buf;
1120 size_t capa;
1121 struct timeval *timeout;
1122};
1123
1124#ifdef HAVE_WRITEV
1125struct io_internal_writev_struct {
1126 VALUE th;
1127 rb_io_t *fptr;
1128 int nonblock;
1129 int fd;
1130
1131 int iovcnt;
1132 const struct iovec *iov;
1133 struct timeval *timeout;
1134};
1135#endif
1136
1137static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1138
1144static inline int
1145io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1146{
1147 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1148
1149 if (ready > 0) {
1150 return ready;
1151 }
1152 else if (ready == 0) {
1153 errno = ETIMEDOUT;
1154 return -1;
1155 }
1156
1157 errno = error;
1158 return -1;
1159}
1160
1161static VALUE
1162internal_read_func(void *ptr)
1163{
1164 struct io_internal_read_struct *iis = ptr;
1165 ssize_t result;
1166
1167 if (iis->timeout && !iis->nonblock) {
1168 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1169 return -1;
1170 }
1171 }
1172
1173 retry:
1174 result = read(iis->fd, iis->buf, iis->capa);
1175
1176 if (result < 0 && !iis->nonblock) {
1177 if (io_again_p(errno)) {
1178 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1179 return -1;
1180 }
1181 else {
1182 goto retry;
1183 }
1184 }
1185 }
1186
1187 return result;
1188}
1189
1190#if defined __APPLE__
1191# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1192#else
1193# define do_write_retry(code) result = code
1194#endif
1195
1196static VALUE
1197internal_write_func(void *ptr)
1198{
1199 struct io_internal_write_struct *iis = ptr;
1200 ssize_t result;
1201
1202 if (iis->timeout && !iis->nonblock) {
1203 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1204 return -1;
1205 }
1206 }
1207
1208 retry:
1209 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1210
1211 if (result < 0 && !iis->nonblock) {
1212 int e = errno;
1213 if (io_again_p(e)) {
1214 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1215 return -1;
1216 }
1217 else {
1218 goto retry;
1219 }
1220 }
1221 }
1222
1223 return result;
1224}
1225
1226#ifdef HAVE_WRITEV
1227static VALUE
1228internal_writev_func(void *ptr)
1229{
1230 struct io_internal_writev_struct *iis = ptr;
1231 ssize_t result;
1232
1233 if (iis->timeout && !iis->nonblock) {
1234 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1235 return -1;
1236 }
1237 }
1238
1239 retry:
1240 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1241
1242 if (result < 0 && !iis->nonblock) {
1243 if (io_again_p(errno)) {
1244 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1245 return -1;
1246 }
1247 else {
1248 goto retry;
1249 }
1250 }
1251 }
1252
1253 return result;
1254}
1255#endif
1256
1257static ssize_t
1258rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1259{
1260 VALUE scheduler = rb_fiber_scheduler_current();
1261 if (scheduler != Qnil) {
1262 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1263
1264 if (!UNDEF_P(result)) {
1265 return rb_fiber_scheduler_io_result_apply(result);
1266 }
1267 }
1268
1269 struct io_internal_read_struct iis = {
1270 .th = rb_thread_current(),
1271 .fptr = fptr,
1272 .nonblock = 0,
1273 .fd = fptr->fd,
1274
1275 .buf = buf,
1276 .capa = count,
1277 .timeout = NULL,
1278 };
1279
1280 struct timeval timeout_storage;
1281
1282 if (fptr->timeout != Qnil) {
1283 timeout_storage = rb_time_interval(fptr->timeout);
1284 iis.timeout = &timeout_storage;
1285 }
1286
1287 return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fptr->fd);
1288}
1289
1290static ssize_t
1291rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1292{
1293 VALUE scheduler = rb_fiber_scheduler_current();
1294 if (scheduler != Qnil) {
1295 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1296
1297 if (!UNDEF_P(result)) {
1298 return rb_fiber_scheduler_io_result_apply(result);
1299 }
1300 }
1301
1302 struct io_internal_write_struct iis = {
1303 .th = rb_thread_current(),
1304 .fptr = fptr,
1305 .nonblock = 0,
1306 .fd = fptr->fd,
1307
1308 .buf = buf,
1309 .capa = count,
1310 .timeout = NULL
1311 };
1312
1313 struct timeval timeout_storage;
1314
1315 if (fptr->timeout != Qnil) {
1316 timeout_storage = rb_time_interval(fptr->timeout);
1317 iis.timeout = &timeout_storage;
1318 }
1319
1320 return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fptr->fd);
1321}
1322
1323#ifdef HAVE_WRITEV
1324static ssize_t
1325rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1326{
1327 if (!iovcnt) return 0;
1328
1329 VALUE scheduler = rb_fiber_scheduler_current();
1330 if (scheduler != Qnil) {
1331 // This path assumes at least one `iov`:
1332 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1333
1334 if (!UNDEF_P(result)) {
1335 return rb_fiber_scheduler_io_result_apply(result);
1336 }
1337 }
1338
1339 struct io_internal_writev_struct iis = {
1340 .th = rb_thread_current(),
1341 .fptr = fptr,
1342 .nonblock = 0,
1343 .fd = fptr->fd,
1344
1345 .iov = iov,
1346 .iovcnt = iovcnt,
1347 .timeout = NULL
1348 };
1349
1350 struct timeval timeout_storage;
1351
1352 if (fptr->timeout != Qnil) {
1353 timeout_storage = rb_time_interval(fptr->timeout);
1354 iis.timeout = &timeout_storage;
1355 }
1356
1357 return (ssize_t)rb_thread_io_blocking_region(internal_writev_func, &iis, fptr->fd);
1358}
1359#endif
1360
1361static VALUE
1362io_flush_buffer_sync(void *arg)
1363{
1364 rb_io_t *fptr = arg;
1365 long l = fptr->wbuf.len;
1366 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1367
1368 if (fptr->wbuf.len <= r) {
1369 fptr->wbuf.off = 0;
1370 fptr->wbuf.len = 0;
1371 return 0;
1372 }
1373
1374 if (0 <= r) {
1375 fptr->wbuf.off += (int)r;
1376 fptr->wbuf.len -= (int)r;
1377 errno = EAGAIN;
1378 }
1379
1380 return (VALUE)-1;
1381}
1382
1383static VALUE
1384io_flush_buffer_async(VALUE arg)
1385{
1386 rb_io_t *fptr = (rb_io_t *)arg;
1387 return rb_thread_io_blocking_region(io_flush_buffer_sync, fptr, fptr->fd);
1388}
1389
1390static inline int
1391io_flush_buffer(rb_io_t *fptr)
1392{
1393 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1394 return (int)io_flush_buffer_async((VALUE)fptr);
1395 }
1396 else {
1397 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1398 }
1399}
1400
1401static int
1402io_fflush(rb_io_t *fptr)
1403{
1404 rb_io_check_closed(fptr);
1405
1406 if (fptr->wbuf.len == 0)
1407 return 0;
1408
1409 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1410 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1411 return -1;
1412
1413 rb_io_check_closed(fptr);
1414 }
1415
1416 return 0;
1417}
1418
1419 VALUE
1420rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1421{
1422 VALUE scheduler = rb_fiber_scheduler_current();
1423
1424 if (scheduler != Qnil) {
1425 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1426 }
1427
1428 rb_io_t * fptr = NULL;
1429 RB_IO_POINTER(io, fptr);
1430
1431 struct timeval tv_storage;
1432 struct timeval *tv = NULL;
1433
1434 if (NIL_OR_UNDEF_P(timeout)) {
1435 timeout = fptr->timeout;
1436 }
1437
1438 if (timeout != Qnil) {
1439 tv_storage = rb_time_interval(timeout);
1440 tv = &tv_storage;
1441 }
1442
1443 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1444
1445 if (ready < 0) {
1446 rb_sys_fail(0);
1447 }
1448
1449 // Not sure if this is necessary:
1450 rb_io_check_closed(fptr);
1451
1452 if (ready) {
1453 return RB_INT2NUM(ready);
1454 }
1455 else {
1456 return Qfalse;
1457 }
1458}
1459
1460static VALUE
1461io_from_fd(int fd)
1462{
1463 return prep_io(fd, FMODE_PREP, rb_cIO, NULL);
1464}
1465
1466static int
1467io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1468{
1469 VALUE scheduler = rb_fiber_scheduler_current();
1470
1471 if (scheduler != Qnil) {
1472 return RTEST(
1473 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1474 );
1475 }
1476
1477 return rb_thread_wait_for_single_fd(fd, events, timeout);
1478}
1479
1480int
1481rb_io_wait_readable(int f)
1482{
1483 io_fd_check_closed(f);
1484
1485 VALUE scheduler = rb_fiber_scheduler_current();
1486
1487 switch (errno) {
1488 case EINTR:
1489#if defined(ERESTART)
1490 case ERESTART:
1491#endif
1492 rb_thread_check_ints();
1493 return TRUE;
1494
1495 case EAGAIN:
1496#if EWOULDBLOCK != EAGAIN
1497 case EWOULDBLOCK:
1498#endif
1499 if (scheduler != Qnil) {
1500 return RTEST(
1501 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1502 );
1503 }
1504 else {
1505 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1506 }
1507 return TRUE;
1508
1509 default:
1510 return FALSE;
1511 }
1512}
1513
1514int
1515rb_io_wait_writable(int f)
1516{
1517 io_fd_check_closed(f);
1518
1519 VALUE scheduler = rb_fiber_scheduler_current();
1520
1521 switch (errno) {
1522 case EINTR:
1523#if defined(ERESTART)
1524 case ERESTART:
1525#endif
1526 /*
1527 * In old Linux, several special files under /proc and /sys don't handle
1528 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1529 * Otherwise, we face nasty hang up. Sigh.
1530 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1531 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1532 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1533 * Then rb_thread_check_ints() is enough.
1534 */
1535 rb_thread_check_ints();
1536 return TRUE;
1537
1538 case EAGAIN:
1539#if EWOULDBLOCK != EAGAIN
1540 case EWOULDBLOCK:
1541#endif
1542 if (scheduler != Qnil) {
1543 return RTEST(
1544 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1545 );
1546 }
1547 else {
1548 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1549 }
1550 return TRUE;
1551
1552 default:
1553 return FALSE;
1554 }
1555}
1556
1557int
1558rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1559{
1560 return io_wait_for_single_fd(fd, events, timeout);
1561}
1562
1563int
1564rb_thread_wait_fd(int fd)
1565{
1566 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1567}
1568
1569int
1570rb_thread_fd_writable(int fd)
1571{
1572 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1573}
1574
1575 VALUE
1576rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1577{
1578 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1579 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1580 // instead relies on `read(-1) -> -1` which causes this code path. We then
1581 // check here whether the IO was in fact closed. Probably it's better to
1582 // check that `fptr->fd != -1` before using it in syscall.
1583 rb_io_check_closed(RFILE(io)->fptr);
1584
1585 switch (error) {
1586 // In old Linux, several special files under /proc and /sys don't handle
1587 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1588 // Otherwise, we face nasty hang up. Sigh.
1589 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1590 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1591 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1592 // Then rb_thread_check_ints() is enough.
1593 case EINTR:
1594#if defined(ERESTART)
1595 case ERESTART:
1596#endif
1597 // We might have pending interrupts since the previous syscall was interrupted:
1598 rb_thread_check_ints();
1599
1600 // The operation was interrupted, so retry it immediately:
1601 return events;
1602
1603 case EAGAIN:
1604#if EWOULDBLOCK != EAGAIN
1605 case EWOULDBLOCK:
1606#endif
1607 // The operation would block, so wait for the specified events:
1608 return rb_io_wait(io, events, timeout);
1609
1610 default:
1611 // Non-specific error, no event is ready:
1612 return Qfalse;
1613 }
1614}
1615
1616int
1617rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
1618{
1619 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1620
1621 if (RTEST(result)) {
1622 return RB_NUM2INT(result);
1623 }
1624 else {
1625 return 0;
1626 }
1627}
1628
1629int
1630rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
1631{
1632 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1633
1634 if (RTEST(result)) {
1635 return RB_NUM2INT(result);
1636 }
1637 else {
1638 return 0;
1639 }
1640}
1641
1642static void
1643make_writeconv(rb_io_t *fptr)
1644{
1645 if (!fptr->writeconv_initialized) {
1646 const char *senc, *denc;
1647 rb_encoding *enc;
1648 int ecflags;
1649 VALUE ecopts;
1650
1651 fptr->writeconv_initialized = 1;
1652
1653 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1654 ecopts = fptr->encs.ecopts;
1655
1656 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1657 /* no encoding conversion */
1658 fptr->writeconv_pre_ecflags = 0;
1659 fptr->writeconv_pre_ecopts = Qnil;
1660 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1661 if (!fptr->writeconv)
1662 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1663 fptr->writeconv_asciicompat = Qnil;
1664 }
1665 else {
1666 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1667 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1668 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1669 /* single conversion */
1670 fptr->writeconv_pre_ecflags = ecflags;
1671 fptr->writeconv_pre_ecopts = ecopts;
1672 fptr->writeconv = NULL;
1673 fptr->writeconv_asciicompat = Qnil;
1674 }
1675 else {
1676 /* double conversion */
1677 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1678 fptr->writeconv_pre_ecopts = ecopts;
1679 if (senc) {
1680 denc = rb_enc_name(enc);
1681 fptr->writeconv_asciicompat = rb_str_new2(senc);
1682 }
1683 else {
1684 senc = denc = "";
1685 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1686 }
1687 ecflags = fptr->encs.ecflags & (ECONV_ERROR_HANDLER_MASK|ECONV_STATEFUL_DECORATOR_MASK);
1688 ecopts = fptr->encs.ecopts;
1689 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1690 if (!fptr->writeconv)
1691 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1692 }
1693 }
1694 }
1695}
1696
1697/* writing functions */
1698 struct binwrite_arg {
1699 rb_io_t *fptr;
1700 VALUE str;
1701 const char *ptr;
1702 long length;
1703};
1704
1705 struct write_arg {
1706 VALUE io;
1707 VALUE str;
1708 int nosync;
1709};
1710
1711#ifdef HAVE_WRITEV
1712static ssize_t
1713io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1714{
1715 if (fptr->wbuf.len) {
1716 struct iovec iov[2];
1717
1718 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1719 iov[0].iov_len = fptr->wbuf.len;
1720 iov[1].iov_base = (void*)ptr;
1721 iov[1].iov_len = length;
1722
1723 ssize_t result = rb_writev_internal(fptr, iov, 2);
1724
1725 if (result < 0)
1726 return result;
1727
1728 if (result >= fptr->wbuf.len) {
1729 // We wrote more than the internal buffer:
1730 result -= fptr->wbuf.len;
1731 fptr->wbuf.off = 0;
1732 fptr->wbuf.len = 0;
1733 }
1734 else {
1735 // We only wrote less data than the internal buffer:
1736 fptr->wbuf.off += (int)result;
1737 fptr->wbuf.len -= (int)result;
1738
1739 result = 0;
1740 }
1741
1742 return result;
1743 }
1744 else {
1745 return rb_io_write_memory(fptr, ptr, length);
1746 }
1747}
1748#else
1749static ssize_t
1750io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1751{
1752 long remaining = length;
1753
1754 if (fptr->wbuf.len) {
1755 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1756 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1757 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1758 fptr->wbuf.off = 0;
1759 }
1760
1761 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1762 fptr->wbuf.len += (int)length;
1763
1764 // We copied the entire incoming data to the internal buffer:
1765 remaining = 0;
1766 }
1767
1768 // Flush the internal buffer:
1769 if (io_fflush(fptr) < 0) {
1770 return -1;
1771 }
1772
1773 // If all the data was buffered, we are done:
1774 if (remaining == 0) {
1775 return length;
1776 }
1777 }
1778
1779 // Otherwise, we should write the data directly:
1780 return rb_io_write_memory(fptr, ptr, length);
1781}
1782#endif
1783
1784static VALUE
1785io_binwrite_string(VALUE arg)
1786{
1787 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1788
1789 const char *ptr = p->ptr;
1790 size_t remaining = p->length;
1791
1792 while (remaining) {
1793 // Write as much as possible:
1794 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1795
1796 if (result == 0) {
1797 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1798 // should try again immediately.
1799 }
1800 else if (result > 0) {
1801 if ((size_t)result == remaining) break;
1802 ptr += result;
1803 remaining -= result;
1804 }
1805 // Wait for it to become writable:
1806 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1807 rb_io_check_closed(p->fptr);
1808 }
1809 else {
1810 // The error was unrelated to waiting for it to become writable, so we fail:
1811 return -1;
1812 }
1813 }
1814
1815 return p->length;
1816}
1817
1818inline static void
1819io_allocate_write_buffer(rb_io_t *fptr, int sync)
1820{
1821 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1822 fptr->wbuf.off = 0;
1823 fptr->wbuf.len = 0;
1824 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1825 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1826 }
1827
1828 if (NIL_P(fptr->write_lock)) {
1829 fptr->write_lock = rb_mutex_new();
1830 rb_mutex_allow_trap(fptr->write_lock, 1);
1831 }
1832}
1833
1834static inline int
1835io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1836{
1837 // If the requested operation was synchronous and the output mode is synchronus or a TTY:
1838 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1839 return 1;
1840
1841 // If the amount of data we want to write exceeds the internal buffer:
1842 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1843 return 1;
1844
1845 // Otherwise, we can append to the internal buffer:
1846 return 0;
1847}
1848
1849static long
1850io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
1851{
1852 if (len <= 0) return len;
1853
1854 // Don't write anything if current thread has a pending interrupt:
1855 rb_thread_check_ints();
1856
1857 io_allocate_write_buffer(fptr, !nosync);
1858
1859 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1860 struct binwrite_arg arg;
1861
1862 arg.fptr = fptr;
1863 arg.str = str;
1864 arg.ptr = ptr;
1865 arg.length = len;
1866
1867 if (!NIL_P(fptr->write_lock)) {
1868 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1869 }
1870 else {
1871 return io_binwrite_string((VALUE)&arg);
1872 }
1873 }
1874 else {
1875 if (fptr->wbuf.off) {
1876 if (fptr->wbuf.len)
1877 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1878 fptr->wbuf.off = 0;
1879 }
1880
1881 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1882 fptr->wbuf.len += (int)len;
1883
1884 return len;
1885 }
1886}
1887
1888# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1889 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1890
1891#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1892 MODE_BTMODE(d, e, f) : \
1893 MODE_BTMODE(a, b, c))
1894
1895static VALUE
1896do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1897{
1898 if (NEED_WRITECONV(fptr)) {
1899 VALUE common_encoding = Qnil;
1900 SET_BINARY_MODE(fptr);
1901
1902 make_writeconv(fptr);
1903
1904 if (fptr->writeconv) {
1905#define fmode (fptr->mode)
1906 if (!NIL_P(fptr->writeconv_asciicompat))
1907 common_encoding = fptr->writeconv_asciicompat;
1908 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1909 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1910 rb_enc_name(rb_enc_get(str)));
1911 }
1912#undef fmode
1913 }
1914 else {
1915 if (fptr->encs.enc2)
1916 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1917 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1918 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1919 }
1920
1921 if (!NIL_P(common_encoding)) {
1922 str = rb_str_encode(str, common_encoding,
1923 fptr->writeconv_pre_ecflags, fptr->writeconv_pre_ecopts);
1924 *converted = 1;
1925 }
1926
1927 if (fptr->writeconv) {
1928 str = rb_econv_str_convert(fptr->writeconv, str, ECONV_PARTIAL_INPUT);
1929 *converted = 1;
1930 }
1931 }
1932#if RUBY_CRLF_ENVIRONMENT
1933#define fmode (fptr->mode)
1934 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1935 if ((fptr->mode & FMODE_READABLE) &&
1936 !(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
1937 setmode(fptr->fd, O_BINARY);
1938 }
1939 else {
1940 setmode(fptr->fd, O_TEXT);
1941 }
1942 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1943 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1944 rb_enc_name(rb_enc_get(str)));
1945 }
1946 }
1947#undef fmode
1948#endif
1949 return str;
1950}
1951
1952static long
1953io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1954{
1955 int converted = 0;
1956 VALUE tmp;
1957 long n, len;
1958 const char *ptr;
1959
1960#ifdef _WIN32
1961 if (fptr->mode & FMODE_TTY) {
1962 long len = rb_w32_write_console(str, fptr->fd);
1963 if (len > 0) return len;
1964 }
1965#endif
1966
1967 str = do_writeconv(str, fptr, &converted);
1968 if (converted)
1969 OBJ_FREEZE(str);
1970
1971 tmp = rb_str_tmp_frozen_acquire(str);
1972 RSTRING_GETMEM(tmp, ptr, len);
1973 n = io_binwrite(tmp, ptr, len, fptr, nosync);
1974 rb_str_tmp_frozen_release(str, tmp);
1975
1976 return n;
1977}
1978
1979ssize_t
1980rb_io_bufwrite(VALUE io, const void *buf, size_t size)
1981{
1982 rb_io_t *fptr;
1983
1984 GetOpenFile(io, fptr);
1985 rb_io_check_writable(fptr);
1986 return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
1987}
1988
1989static VALUE
1990io_write(VALUE io, VALUE str, int nosync)
1991{
1992 rb_io_t *fptr;
1993 long n;
1994 VALUE tmp;
1995
1996 io = GetWriteIO(io);
1997 str = rb_obj_as_string(str);
1998 tmp = rb_io_check_io(io);
1999
2000 if (NIL_P(tmp)) {
2001 /* port is not IO, call write method for it. */
2002 return rb_funcall(io, id_write, 1, str);
2003 }
2004
2005 io = tmp;
2006 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2007
2008 GetOpenFile(io, fptr);
2009 rb_io_check_writable(fptr);
2010
2011 n = io_fwrite(str, fptr, nosync);
2012 if (n < 0L) rb_sys_fail_on_write(fptr);
2013
2014 return LONG2FIX(n);
2015}
2016
2017#ifdef HAVE_WRITEV
2018struct binwritev_arg {
2019 rb_io_t *fptr;
2020 struct iovec *iov;
2021 int iovcnt;
2022 size_t total;
2023};
2024
2025static VALUE
2026io_binwritev_internal(VALUE arg)
2027{
2028 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2029
2030 size_t remaining = p->total;
2031 size_t offset = 0;
2032
2033 rb_io_t *fptr = p->fptr;
2034 struct iovec *iov = p->iov;
2035 int iovcnt = p->iovcnt;
2036
2037 while (remaining) {
2038 long result = rb_writev_internal(fptr, iov, iovcnt);
2039
2040 if (result >= 0) {
2041 offset += result;
2042 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2043 if (offset < (size_t)fptr->wbuf.len) {
2044 fptr->wbuf.off += result;
2045 fptr->wbuf.len -= result;
2046 }
2047 else {
2048 offset -= (size_t)fptr->wbuf.len;
2049 fptr->wbuf.off = 0;
2050 fptr->wbuf.len = 0;
2051 }
2052 }
2053
2054 if (offset == p->total) {
2055 return p->total;
2056 }
2057
2058 while (result >= (ssize_t)iov->iov_len) {
2059 /* iovcnt > 0 */
2060 result -= iov->iov_len;
2061 iov->iov_len = 0;
2062 iov++;
2063
2064 if (!--iovcnt) {
2065 // I don't believe this code path can ever occur.
2066 return offset;
2067 }
2068 }
2069
2070 iov->iov_base = (char *)iov->iov_base + result;
2071 iov->iov_len -= result;
2072 }
2073 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2074 rb_io_check_closed(fptr);
2075 }
2076 else {
2077 return -1;
2078 }
2079 }
2080
2081 return offset;
2082}
2083
2084static long
2085io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2086{
2087 // Don't write anything if current thread has a pending interrupt:
2088 rb_thread_check_ints();
2089
2090 if (iovcnt == 0) return 0;
2091
2092 size_t total = 0;
2093 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2094
2095 io_allocate_write_buffer(fptr, 1);
2096
2097 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2098 // The end of the buffered data:
2099 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2100
2101 if (offset + total <= (size_t)fptr->wbuf.capa) {
2102 for (int i = 1; i < iovcnt; i++) {
2103 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2104 offset += iov[i].iov_len;
2105 }
2106
2107 fptr->wbuf.len += total;
2108
2109 return total;
2110 }
2111 else {
2112 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2113 iov[0].iov_len = fptr->wbuf.len;
2114 }
2115 }
2116 else {
2117 // The first iov is reserved for the internal buffer, and it's empty.
2118 iov++;
2119
2120 if (!--iovcnt) {
2121 // If there are no other io vectors we are done.
2122 return 0;
2123 }
2124 }
2125
2126 struct binwritev_arg arg;
2127 arg.fptr = fptr;
2128 arg.iov = iov;
2129 arg.iovcnt = iovcnt;
2130 arg.total = total;
2131
2132 if (!NIL_P(fptr->write_lock)) {
2133 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2134 }
2135 else {
2136 return io_binwritev_internal((VALUE)&arg);
2137 }
2138}
2139
2140static long
2141io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2142{
2143 int i, converted, iovcnt = argc + 1;
2144 long n;
2145 VALUE v1, v2, str, tmp, *tmp_array;
2146 struct iovec *iov;
2147
2148 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2149 tmp_array = ALLOCV_N(VALUE, v2, argc);
2150
2151 for (i = 0; i < argc; i++) {
2152 str = rb_obj_as_string(argv[i]);
2153 converted = 0;
2154 str = do_writeconv(str, fptr, &converted);
2155
2156 if (converted)
2157 OBJ_FREEZE(str);
2158
2159 tmp = rb_str_tmp_frozen_acquire(str);
2160 tmp_array[i] = tmp;
2161
2162 /* iov[0] is reserved for buffer of fptr */
2163 iov[i+1].iov_base = RSTRING_PTR(tmp);
2164 iov[i+1].iov_len = RSTRING_LEN(tmp);
2165 }
2166
2167 n = io_binwritev(iov, iovcnt, fptr);
2168 if (v1) ALLOCV_END(v1);
2169
2170 for (i = 0; i < argc; i++) {
2171 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2172 }
2173
2174 if (v2) ALLOCV_END(v2);
2175
2176 return n;
2177}
2178
2179static int
2180iovcnt_ok(int iovcnt)
2181{
2182#ifdef IOV_MAX
2183 return iovcnt < IOV_MAX;
2184#else /* GNU/Hurd has writev, but no IOV_MAX */
2185 return 1;
2186#endif
2187}
2188#endif /* HAVE_WRITEV */
2189
2190static VALUE
2191io_writev(int argc, const VALUE *argv, VALUE io)
2192{
2193 rb_io_t *fptr;
2194 long n;
2195 VALUE tmp, total = INT2FIX(0);
2196 int i, cnt = 1;
2197
2198 io = GetWriteIO(io);
2199 tmp = rb_io_check_io(io);
2200
2201 if (NIL_P(tmp)) {
2202 /* port is not IO, call write method for it. */
2203 return rb_funcallv(io, id_write, argc, argv);
2204 }
2205
2206 io = tmp;
2207
2208 GetOpenFile(io, fptr);
2209 rb_io_check_writable(fptr);
2210
2211 for (i = 0; i < argc; i += cnt) {
2212#ifdef HAVE_WRITEV
2213 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2214 n = io_fwritev(cnt, &argv[i], fptr);
2215 }
2216 else
2217#endif
2218 {
2219 cnt = 1;
2220 /* sync at last item */
2221 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2222 }
2223
2224 if (n < 0L)
2225 rb_sys_fail_on_write(fptr);
2226
2227 total = rb_fix_plus(LONG2FIX(n), total);
2228 }
2229
2230 return total;
2231}
2232
2233/*
2234 * call-seq:
2235 * write(*objects) -> integer
2236 *
2237 * Writes each of the given +objects+ to +self+,
2238 * which must be opened for writing
2239 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2240 * returns the total number bytes written;
2241 * each of +objects+ that is not a string is converted via method +to_s+:
2242 *
2243 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2244 * $stdout.write('foo', :bar, 2, "\n") # => 8
2245 *
2246 * Output:
2247 *
2248 * Hello, World!
2249 * foobar2
2250 *
2251 * Related: IO#read.
2252 */
2253
2254static VALUE
2255io_write_m(int argc, VALUE *argv, VALUE io)
2256{
2257 if (argc != 1) {
2258 return io_writev(argc, argv, io);
2259 }
2260 else {
2261 VALUE str = argv[0];
2262 return io_write(io, str, 0);
2263 }
2264}
2265
2266 VALUE
2267rb_io_write(VALUE io, VALUE str)
2268{
2269 return rb_funcallv(io, id_write, 1, &str);
2270}
2271
2272static VALUE
2273rb_io_writev(VALUE io, int argc, const VALUE *argv)
2274{
2275 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2276 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2277 VALUE klass = CLASS_OF(io);
2278 char sep = FL_TEST(klass, FL_SINGLETON) ? (klass = io, '.') : '#';
2279 rb_category_warning(
2280 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2281 " which accepts just one argument",
2282 klass, sep
2283 );
2284 }
2285
2286 do rb_io_write(io, *argv++); while (--argc);
2287
2288 return Qnil;
2289 }
2290
2291 return rb_funcallv(io, id_write, argc, argv);
2292}
2293
2294/*
2295 * call-seq:
2296 * self << object -> self
2297 *
2298 * Writes the given +object+ to +self+,
2299 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2300 * returns +self+;
2301 * if +object+ is not a string, it is converted via method +to_s+:
2302 *
2303 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2304 * $stdout << 'foo' << :bar << 2 << "\n"
2305 *
2306 * Output:
2307 *
2308 * Hello, World!
2309 * foobar2
2310 *
2311 */
2312
2313
2314 VALUE
2315rb_io_addstr(VALUE io, VALUE str)
2316{
2317 rb_io_write(io, str);
2318 return io;
2319}
2320
2321#ifdef HAVE_FSYNC
2322static VALUE
2323nogvl_fsync(void *ptr)
2324{
2325 rb_io_t *fptr = ptr;
2326
2327#ifdef _WIN32
2328 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2329 return 0;
2330#endif
2331 return (VALUE)fsync(fptr->fd);
2332}
2333#endif
2334
2335 VALUE
2336rb_io_flush_raw(VALUE io, int sync)
2337{
2338 rb_io_t *fptr;
2339
2340 if (!RB_TYPE_P(io, T_FILE)) {
2341 return rb_funcall(io, id_flush, 0);
2342 }
2343
2344 io = GetWriteIO(io);
2345 GetOpenFile(io, fptr);
2346
2347 if (fptr->mode & FMODE_WRITABLE) {
2348 if (io_fflush(fptr) < 0)
2349 rb_sys_fail_on_write(fptr);
2350 }
2351 if (fptr->mode & FMODE_READABLE) {
2352 io_unread(fptr);
2353 }
2354
2355 return io;
2356}
2357
2358/*
2359 * call-seq:
2360 * flush -> self
2361 *
2362 * Flushes data buffered in +self+ to the operating system
2363 * (but does not necessarily flush data buffered in the operating system):
2364 *
2365 * $stdout.print 'no newline' # Not necessarily flushed.
2366 * $stdout.flush # Flushed.
2367 *
2368 */
2369
2370 VALUE
2371rb_io_flush(VALUE io)
2372{
2373 return rb_io_flush_raw(io, 1);
2374}
2375
2376/*
2377 * call-seq:
2378 * tell -> integer
2379 *
2380 * Returns the current position (in bytes) in +self+
2381 * (see {Position}[rdoc-ref:IO@Position]):
2382 *
2383 * f = File.open('t.txt')
2384 * f.tell # => 0
2385 * f.gets # => "First line\n"
2386 * f.tell # => 12
2387 * f.close
2388 *
2389 * Related: IO#pos=, IO#seek.
2390 *
2391 * IO#pos is an alias for IO#tell.
2392 *
2393 */
2394
2395static VALUE
2396rb_io_tell(VALUE io)
2397{
2398 rb_io_t *fptr;
2399 rb_off_t pos;
2400
2401 GetOpenFile(io, fptr);
2402 pos = io_tell(fptr);
2403 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2404 pos -= fptr->rbuf.len;
2405 return OFFT2NUM(pos);
2406}
2407
2408static VALUE
2409rb_io_seek(VALUE io, VALUE offset, int whence)
2410{
2411 rb_io_t *fptr;
2412 rb_off_t pos;
2413
2414 pos = NUM2OFFT(offset);
2415 GetOpenFile(io, fptr);
2416 pos = io_seek(fptr, pos, whence);
2417 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2418
2419 return INT2FIX(0);
2420}
2421
2422static int
2423interpret_seek_whence(VALUE vwhence)
2424{
2425 if (vwhence == sym_SET)
2426 return SEEK_SET;
2427 if (vwhence == sym_CUR)
2428 return SEEK_CUR;
2429 if (vwhence == sym_END)
2430 return SEEK_END;
2431#ifdef SEEK_DATA
2432 if (vwhence == sym_DATA)
2433 return SEEK_DATA;
2434#endif
2435#ifdef SEEK_HOLE
2436 if (vwhence == sym_HOLE)
2437 return SEEK_HOLE;
2438#endif
2439 return NUM2INT(vwhence);
2440}
2441
2442/*
2443 * call-seq:
2444 * seek(offset, whence = IO::SEEK_SET) -> 0
2445 *
2446 * Seeks to the position given by integer +offset+
2447 * (see {Position}[rdoc-ref:IO@Position])
2448 * and constant +whence+, which is one of:
2449 *
2450 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2451 * Repositions the stream to its current position plus the given +offset+:
2452 *
2453 * f = File.open('t.txt')
2454 * f.tell # => 0
2455 * f.seek(20, :CUR) # => 0
2456 * f.tell # => 20
2457 * f.seek(-10, :CUR) # => 0
2458 * f.tell # => 10
2459 * f.close
2460 *
2461 * - +:END+ or <tt>IO::SEEK_END</tt>:
2462 * Repositions the stream to its end plus the given +offset+:
2463 *
2464 * f = File.open('t.txt')
2465 * f.tell # => 0
2466 * f.seek(0, :END) # => 0 # Repositions to stream end.
2467 * f.tell # => 52
2468 * f.seek(-20, :END) # => 0
2469 * f.tell # => 32
2470 * f.seek(-40, :END) # => 0
2471 * f.tell # => 12
2472 * f.close
2473 *
2474 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2475 * Repositions the stream to the given +offset+:
2476 *
2477 * f = File.open('t.txt')
2478 * f.tell # => 0
2479 * f.seek(20, :SET) # => 0
2480 * f.tell # => 20
2481 * f.seek(40, :SET) # => 0
2482 * f.tell # => 40
2483 * f.close
2484 *
2485 * Related: IO#pos=, IO#tell.
2486 *
2487 */
2488
2489static VALUE
2490rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2491{
2492 VALUE offset, ptrname;
2493 int whence = SEEK_SET;
2494
2495 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2496 whence = interpret_seek_whence(ptrname);
2497 }
2498
2499 return rb_io_seek(io, offset, whence);
2500}
2501
2502/*
2503 * call-seq:
2504 * pos = new_position -> new_position
2505 *
2506 * Seeks to the given +new_position+ (in bytes);
2507 * see {Position}[rdoc-ref:IO@Position]:
2508 *
2509 * f = File.open('t.txt')
2510 * f.tell # => 0
2511 * f.pos = 20 # => 20
2512 * f.tell # => 20
2513 * f.close
2514 *
2515 * Related: IO#seek, IO#tell.
2516 *
2517 */
2518
2519static VALUE
2520rb_io_set_pos(VALUE io, VALUE offset)
2521{
2522 rb_io_t *fptr;
2523 rb_off_t pos;
2524
2525 pos = NUM2OFFT(offset);
2526 GetOpenFile(io, fptr);
2527 pos = io_seek(fptr, pos, SEEK_SET);
2528 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2529
2530 return OFFT2NUM(pos);
2531}
2532
2533static void clear_readconv(rb_io_t *fptr);
2534
2535/*
2536 * call-seq:
2537 * rewind -> 0
2538 *
2539 * Repositions the stream to its beginning,
2540 * setting both the position and the line number to zero;
2541 * see {Position}[rdoc-ref:IO@Position]
2542 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2543 *
2544 * f = File.open('t.txt')
2545 * f.tell # => 0
2546 * f.lineno # => 0
2547 * f.gets # => "First line\n"
2548 * f.tell # => 12
2549 * f.lineno # => 1
2550 * f.rewind # => 0
2551 * f.tell # => 0
2552 * f.lineno # => 0
2553 * f.close
2554 *
2555 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2556 *
2557 */
2558
2559static VALUE
2560rb_io_rewind(VALUE io)
2561{
2562 rb_io_t *fptr;
2563
2564 GetOpenFile(io, fptr);
2565 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2566 if (io == ARGF.current_file) {
2567 ARGF.lineno -= fptr->lineno;
2568 }
2569 fptr->lineno = 0;
2570 if (fptr->readconv) {
2571 clear_readconv(fptr);
2572 }
2573
2574 return INT2FIX(0);
2575}
2576
2577static int
2578fptr_wait_readable(rb_io_t *fptr)
2579{
2580 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2581
2582 if (result)
2583 rb_io_check_closed(fptr);
2584
2585 return result;
2586}
2587
2588static int
2589io_fillbuf(rb_io_t *fptr)
2590{
2591 ssize_t r;
2592
2593 if (fptr->rbuf.ptr == NULL) {
2594 fptr->rbuf.off = 0;
2595 fptr->rbuf.len = 0;
2596 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2597 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2598#ifdef _WIN32
2599 fptr->rbuf.capa--;
2600#endif
2601 }
2602 if (fptr->rbuf.len == 0) {
2603 retry:
2604 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2605
2606 if (r < 0) {
2607 if (fptr_wait_readable(fptr))
2608 goto retry;
2609
2610 int e = errno;
2611 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2612 if (!NIL_P(fptr->pathv)) {
2613 rb_str_append(path, fptr->pathv);
2614 }
2615
2616 rb_syserr_fail_path(e, path);
2617 }
2618 if (r > 0) rb_io_check_closed(fptr);
2619 fptr->rbuf.off = 0;
2620 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2621 if (r == 0)
2622 return -1; /* EOF */
2623 }
2624 return 0;
2625}
2626
2627/*
2628 * call-seq:
2629 * eof -> true or false
2630 *
2631 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2632 * see {Position}[rdoc-ref:IO@Position]:
2633 *
2634 * f = File.open('t.txt')
2635 * f.eof # => false
2636 * f.seek(0, :END) # => 0
2637 * f.eof # => true
2638 * f.close
2639 *
2640 * Raises an exception unless the stream is opened for reading;
2641 * see {Mode}[rdoc-ref:File@Access+Modes].
2642 *
2643 * If +self+ is a stream such as pipe or socket, this method
2644 * blocks until the other end sends some data or closes it:
2645 *
2646 * r, w = IO.pipe
2647 * Thread.new { sleep 1; w.close }
2648 * r.eof? # => true # After 1-second wait.
2649 *
2650 * r, w = IO.pipe
2651 * Thread.new { sleep 1; w.puts "a" }
2652 * r.eof? # => false # After 1-second wait.
2653 *
2654 * r, w = IO.pipe
2655 * r.eof? # blocks forever
2656 *
2657 * Note that this method reads data to the input byte buffer. So
2658 * IO#sysread may not behave as you intend with IO#eof?, unless you
2659 * call IO#rewind first (which is not available for some streams).
2660 *
2661 * IO#eof? is an alias for IO#eof.
2662 *
2663 */
2664
2665 VALUE
2666rb_io_eof(VALUE io)
2667{
2668 rb_io_t *fptr;
2669
2670 GetOpenFile(io, fptr);
2671 rb_io_check_char_readable(fptr);
2672
2673 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2674 if (READ_DATA_PENDING(fptr)) return Qfalse;
2675 READ_CHECK(fptr);
2676#if RUBY_CRLF_ENVIRONMENT
2677 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2678 return RBOOL(eof(fptr->fd));;
2679 }
2680#endif
2681 return RBOOL(io_fillbuf(fptr) < 0);
2682}
2683
2684/*
2685 * call-seq:
2686 * sync -> true or false
2687 *
2688 * Returns the current sync mode of the stream.
2689 * When sync mode is true, all output is immediately flushed to the underlying
2690 * operating system and is not buffered by Ruby internally. See also #fsync.
2691 *
2692 * f = File.open('t.tmp', 'w')
2693 * f.sync # => false
2694 * f.sync = true
2695 * f.sync # => true
2696 * f.close
2697 *
2698 */
2699
2700static VALUE
2701rb_io_sync(VALUE io)
2702{
2703 rb_io_t *fptr;
2704
2705 io = GetWriteIO(io);
2706 GetOpenFile(io, fptr);
2707 return RBOOL(fptr->mode & FMODE_SYNC);
2708}
2709
2710#ifdef HAVE_FSYNC
2711
2712/*
2713 * call-seq:
2714 * sync = boolean -> boolean
2715 *
2716 * Sets the _sync_ _mode_ for the stream to the given value;
2717 * returns the given value.
2718 *
2719 * Values for the sync mode:
2720 *
2721 * - +true+: All output is immediately flushed to the
2722 * underlying operating system and is not buffered internally.
2723 * - +false+: Output may be buffered internally.
2724 *
2725 * Example;
2726 *
2727 * f = File.open('t.tmp', 'w')
2728 * f.sync # => false
2729 * f.sync = true
2730 * f.sync # => true
2731 * f.close
2732 *
2733 * Related: IO#fsync.
2734 *
2735 */
2736
2737static VALUE
2738rb_io_set_sync(VALUE io, VALUE sync)
2739{
2740 rb_io_t *fptr;
2741
2742 io = GetWriteIO(io);
2743 GetOpenFile(io, fptr);
2744 if (RTEST(sync)) {
2745 fptr->mode |= FMODE_SYNC;
2746 }
2747 else {
2748 fptr->mode &= ~FMODE_SYNC;
2749 }
2750 return sync;
2751}
2752
2753/*
2754 * call-seq:
2755 * fsync -> 0
2756 *
2757 * Immediately writes to disk all data buffered in the stream,
2758 * via the operating system's <tt>fsync(2)</tt>.
2759
2760 * Note this difference:
2761 *
2762 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2763 * but does not guarantee that the operating system actually writes the data to disk.
2764 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2765 * and that data is written to disk.
2766 *
2767 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2768 *
2769 */
2770
2771static VALUE
2772rb_io_fsync(VALUE io)
2773{
2774 rb_io_t *fptr;
2775
2776 io = GetWriteIO(io);
2777 GetOpenFile(io, fptr);
2778
2779 if (io_fflush(fptr) < 0)
2780 rb_sys_fail_on_write(fptr);
2781 if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
2782 rb_sys_fail_path(fptr->pathv);
2783 return INT2FIX(0);
2784}
2785#else
2786# define rb_io_fsync rb_f_notimplement
2787# define rb_io_sync rb_f_notimplement
2788static VALUE
2789rb_io_set_sync(VALUE io, VALUE sync)
2790{
2791 rb_notimplement();
2792 UNREACHABLE;
2793}
2794#endif
2795
2796#ifdef HAVE_FDATASYNC
2797static VALUE
2798nogvl_fdatasync(void *ptr)
2799{
2800 rb_io_t *fptr = ptr;
2801
2802#ifdef _WIN32
2803 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2804 return 0;
2805#endif
2806 return (VALUE)fdatasync(fptr->fd);
2807}
2808
2809/*
2810 * call-seq:
2811 * fdatasync -> 0
2812 *
2813 * Immediately writes to disk all data buffered in the stream,
2814 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2815 * otherwise via <tt>fsync(2)</tt>, if supported;
2816 * otherwise raises an exception.
2817 *
2818 */
2819
2820static VALUE
2821rb_io_fdatasync(VALUE io)
2822{
2823 rb_io_t *fptr;
2824
2825 io = GetWriteIO(io);
2826 GetOpenFile(io, fptr);
2827
2828 if (io_fflush(fptr) < 0)
2829 rb_sys_fail_on_write(fptr);
2830
2831 if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
2832 return INT2FIX(0);
2833
2834 /* fall back */
2835 return rb_io_fsync(io);
2836}
2837#else
2838#define rb_io_fdatasync rb_io_fsync
2839#endif
2840
2841/*
2842 * call-seq:
2843 * fileno -> integer
2844 *
2845 * Returns the integer file descriptor for the stream:
2846 *
2847 * $stdin.fileno # => 0
2848 * $stdout.fileno # => 1
2849 * $stderr.fileno # => 2
2850 * File.open('t.txt').fileno # => 10
2851 * f.close
2852 *
2853 * IO#to_i is an alias for IO#fileno.
2854 *
2855 */
2856
2857static VALUE
2858rb_io_fileno(VALUE io)
2859{
2860 rb_io_t *fptr = RFILE(io)->fptr;
2861 int fd;
2862
2863 rb_io_check_closed(fptr);
2864 fd = fptr->fd;
2865 return INT2FIX(fd);
2866}
2867
2868int
2869rb_io_descriptor(VALUE io)
2870{
2871 if (RB_TYPE_P(io, T_FILE)) {
2872 rb_io_t *fptr = RFILE(io)->fptr;
2873 rb_io_check_closed(fptr);
2874 return fptr->fd;
2875 }
2876 else {
2877 return RB_NUM2INT(rb_funcall(io, id_fileno, 0));
2878 }
2879}
2880
2881/*
2882 * call-seq:
2883 * pid -> integer or nil
2884 *
2885 * Returns the process ID of a child process associated with the stream,
2886 * which will have been set by IO#popen, or +nil+ if the stream was not
2887 * created by IO#popen:
2888 *
2889 * pipe = IO.popen("-")
2890 * if pipe
2891 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2892 * else
2893 * $stderr.puts "In child, pid is #{$$}"
2894 * end
2895 *
2896 * Output:
2897 *
2898 * In child, pid is 26209
2899 * In parent, child pid is 26209
2900 *
2901 */
2902
2903static VALUE
2904rb_io_pid(VALUE io)
2905{
2906 rb_io_t *fptr;
2907
2908 GetOpenFile(io, fptr);
2909 if (!fptr->pid)
2910 return Qnil;
2911 return PIDT2NUM(fptr->pid);
2912}
2913
2914/*
2915 * call-seq:
2916 * path -> string or nil
2917 *
2918 * Returns the path associated with the IO, or +nil+ if there is no path
2919 * associated with the IO. It is not guaranteed that the path exists on
2920 * the filesystem.
2921 *
2922 * $stdin.path # => "<STDIN>"
2923 *
2924 * File.open("testfile") {|f| f.path} # => "testfile"
2925 */
2926
2927static VALUE
2928rb_io_path(VALUE io)
2929{
2930 rb_io_t *fptr = RFILE(io)->fptr;
2931
2932 if (!fptr)
2933 return Qnil;
2934
2935 return rb_obj_dup(fptr->pathv);
2936}
2937
2938/*
2939 * call-seq:
2940 * inspect -> string
2941 *
2942 * Returns a string representation of +self+:
2943 *
2944 * f = File.open('t.txt')
2945 * f.inspect # => "#<File:t.txt>"
2946 * f.close
2947 *
2948 */
2949
2950static VALUE
2951rb_io_inspect(VALUE obj)
2952{
2953 rb_io_t *fptr;
2954 VALUE result;
2955 static const char closed[] = " (closed)";
2956
2957 fptr = RFILE(obj)->fptr;
2958 if (!fptr) return rb_any_to_s(obj);
2959 result = rb_str_new_cstr("#<");
2960 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2961 rb_str_cat2(result, ":");
2962 if (NIL_P(fptr->pathv)) {
2963 if (fptr->fd < 0) {
2964 rb_str_cat(result, closed+1, strlen(closed)-1);
2965 }
2966 else {
2967 rb_str_catf(result, "fd %d", fptr->fd);
2968 }
2969 }
2970 else {
2971 rb_str_append(result, fptr->pathv);
2972 if (fptr->fd < 0) {
2973 rb_str_cat(result, closed, strlen(closed));
2974 }
2975 }
2976 return rb_str_cat2(result, ">");
2977}
2978
2979/*
2980 * call-seq:
2981 * to_io -> self
2982 *
2983 * Returns +self+.
2984 *
2985 */
2986
2987static VALUE
2988rb_io_to_io(VALUE io)
2989{
2990 return io;
2991}
2992
2993/* reading functions */
2994static long
2995read_buffered_data(char *ptr, long len, rb_io_t *fptr)
2996{
2997 int n;
2998
2999 n = READ_DATA_PENDING_COUNT(fptr);
3000 if (n <= 0) return 0;
3001 if (n > len) n = (int)len;
3002 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3003 fptr->rbuf.off += n;
3004 fptr->rbuf.len -= n;
3005 return n;
3006}
3007
3008static long
3009io_bufread(char *ptr, long len, rb_io_t *fptr)
3010{
3011 long offset = 0;
3012 long n = len;
3013 long c;
3014
3015 if (READ_DATA_PENDING(fptr) == 0) {
3016 while (n > 0) {
3017 again:
3018 rb_io_check_closed(fptr);
3019 c = rb_io_read_memory(fptr, ptr+offset, n);
3020 if (c == 0) break;
3021 if (c < 0) {
3022 if (fptr_wait_readable(fptr))
3023 goto again;
3024 return -1;
3025 }
3026 offset += c;
3027 if ((n -= c) <= 0) break;
3028 }
3029 return len - n;
3030 }
3031
3032 while (n > 0) {
3033 c = read_buffered_data(ptr+offset, n, fptr);
3034 if (c > 0) {
3035 offset += c;
3036 if ((n -= c) <= 0) break;
3037 }
3038 rb_io_check_closed(fptr);
3039 if (io_fillbuf(fptr) < 0) {
3040 break;
3041 }
3042 }
3043 return len - n;
3044}
3045
3046static int io_setstrbuf(VALUE *str, long len);
3047
3048 struct bufread_arg {
3049 char *str_ptr;
3050 long len;
3051 rb_io_t *fptr;
3052};
3053
3054static VALUE
3055bufread_call(VALUE arg)
3056{
3057 struct bufread_arg *p = (struct bufread_arg *)arg;
3058 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3059 return Qundef;
3060}
3061
3062static long
3063io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3064{
3065 long len;
3066 struct bufread_arg arg;
3067
3068 io_setstrbuf(&str, offset + size);
3069 arg.str_ptr = RSTRING_PTR(str) + offset;
3070 arg.len = size;
3071 arg.fptr = fptr;
3072 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3073 len = arg.len;
3074 if (len < 0) rb_sys_fail_path(fptr->pathv);
3075 return len;
3076}
3077
3078static long
3079remain_size(rb_io_t *fptr)
3080{
3081 struct stat st;
3082 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3083 rb_off_t pos;
3084
3085 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3086#if defined(__HAIKU__)
3087 && (st.st_dev > 3)
3088#endif
3089 )
3090 {
3091 if (io_fflush(fptr) < 0)
3092 rb_sys_fail_on_write(fptr);
3093 pos = lseek(fptr->fd, 0, SEEK_CUR);
3094 if (st.st_size >= pos && pos >= 0) {
3095 siz += st.st_size - pos;
3096 if (siz > LONG_MAX) {
3097 rb_raise(rb_eIOError, "file too big for single read");
3098 }
3099 }
3100 }
3101 else {
3102 siz += BUFSIZ;
3103 }
3104 return (long)siz;
3105}
3106
3107static VALUE
3108io_enc_str(VALUE str, rb_io_t *fptr)
3109{
3110 rb_enc_associate(str, io_read_encoding(fptr));
3111 return str;
3112}
3113
3114static rb_encoding *io_read_encoding(rb_io_t *fptr);
3115
3116static void
3117make_readconv(rb_io_t *fptr, int size)
3118{
3119 if (!fptr->readconv) {
3120 int ecflags;
3121 VALUE ecopts;
3122 const char *sname, *dname;
3123 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3124 ecopts = fptr->encs.ecopts;
3125 if (fptr->encs.enc2) {
3126 sname = rb_enc_name(fptr->encs.enc2);
3127 dname = rb_enc_name(io_read_encoding(fptr));
3128 }
3129 else {
3130 sname = dname = "";
3131 }
3132 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3133 if (!fptr->readconv)
3134 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3135 fptr->cbuf.off = 0;
3136 fptr->cbuf.len = 0;
3137 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3138 fptr->cbuf.capa = size;
3139 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3140 }
3141}
3142
3143#define MORE_CHAR_SUSPENDED Qtrue
3144#define MORE_CHAR_FINISHED Qnil
3145static VALUE
3146fill_cbuf(rb_io_t *fptr, int ec_flags)
3147{
3148 const unsigned char *ss, *sp, *se;
3149 unsigned char *ds, *dp, *de;
3150 rb_econv_result_t res;
3151 int putbackable;
3152 int cbuf_len0;
3153 VALUE exc;
3154
3155 ec_flags |= ECONV_PARTIAL_INPUT;
3156
3157 if (fptr->cbuf.len == fptr->cbuf.capa)
3158 return MORE_CHAR_SUSPENDED; /* cbuf full */
3159 if (fptr->cbuf.len == 0)
3160 fptr->cbuf.off = 0;
3161 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3162 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3163 fptr->cbuf.off = 0;
3164 }
3165
3166 cbuf_len0 = fptr->cbuf.len;
3167
3168 while (1) {
3169 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3170 se = sp + fptr->rbuf.len;
3171 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3172 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3173 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3174 fptr->rbuf.off += (int)(sp - ss);
3175 fptr->rbuf.len -= (int)(sp - ss);
3176 fptr->cbuf.len += (int)(dp - ds);
3177
3178 putbackable = rb_econv_putbackable(fptr->readconv);
3179 if (putbackable) {
3180 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3181 fptr->rbuf.off -= putbackable;
3182 fptr->rbuf.len += putbackable;
3183 }
3184
3185 exc = rb_econv_make_exception(fptr->readconv);
3186 if (!NIL_P(exc))
3187 return exc;
3188
3189 if (cbuf_len0 != fptr->cbuf.len)
3190 return MORE_CHAR_SUSPENDED;
3191
3192 if (res == econv_finished) {
3193 return MORE_CHAR_FINISHED;
3194 }
3195
3196 if (res == econv_source_buffer_empty) {
3197 if (fptr->rbuf.len == 0) {
3198 READ_CHECK(fptr);
3199 if (io_fillbuf(fptr) < 0) {
3200 if (!fptr->readconv) {
3201 return MORE_CHAR_FINISHED;
3202 }
3203 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3204 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3205 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3206 fptr->cbuf.len += (int)(dp - ds);
3207 rb_econv_check_error(fptr->readconv);
3208 break;
3209 }
3210 }
3211 }
3212 }
3213 if (cbuf_len0 != fptr->cbuf.len)
3214 return MORE_CHAR_SUSPENDED;
3215
3216 return MORE_CHAR_FINISHED;
3217}
3218
3219static VALUE
3220more_char(rb_io_t *fptr)
3221{
3222 VALUE v;
3223 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3224 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3225 rb_exc_raise(v);
3226 return v;
3227}
3228
3229static VALUE
3230io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3231{
3232 VALUE str = Qnil;
3233 if (strp) {
3234 str = *strp;
3235 if (NIL_P(str)) {
3236 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3237 }
3238 else {
3239 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3240 }
3241 rb_enc_associate(str, fptr->encs.enc);
3242 }
3243 fptr->cbuf.off += len;
3244 fptr->cbuf.len -= len;
3245 /* xxx: set coderange */
3246 if (fptr->cbuf.len == 0)
3247 fptr->cbuf.off = 0;
3248 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3249 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3250 fptr->cbuf.off = 0;
3251 }
3252 return str;
3253}
3254
3255static int
3256io_setstrbuf(VALUE *str, long len)
3257{
3258#ifdef _WIN32
3259 if (len > 0)
3260 len = (len + 1) & ~1L; /* round up for wide char */
3261#endif
3262 if (NIL_P(*str)) {
3263 *str = rb_str_new(0, len);
3264 return TRUE;
3265 }
3266 else {
3267 VALUE s = StringValue(*str);
3268 long clen = RSTRING_LEN(s);
3269 if (clen >= len) {
3270 rb_str_modify(s);
3271 return FALSE;
3272 }
3273 len -= clen;
3274 }
3275 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3276 rb_str_modify_expand(*str, len);
3277 }
3278 return FALSE;
3279}
3280
3281#define MAX_REALLOC_GAP 4096
3282static void
3283io_shrink_read_string(VALUE str, long n)
3284{
3285 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3286 rb_str_resize(str, n);
3287 }
3288}
3289
3290static void
3291io_set_read_length(VALUE str, long n, int shrinkable)
3292{
3293 if (RSTRING_LEN(str) != n) {
3294 rb_str_modify(str);
3295 rb_str_set_len(str, n);
3296 if (shrinkable) io_shrink_read_string(str, n);
3297 }
3298}
3299
3300static VALUE
3301read_all(rb_io_t *fptr, long siz, VALUE str)
3302{
3303 long bytes;
3304 long n;
3305 long pos;
3306 rb_encoding *enc;
3307 int cr;
3308 int shrinkable;
3309
3310 if (NEED_READCONV(fptr)) {
3311 int first = !NIL_P(str);
3312 SET_BINARY_MODE(fptr);
3313 shrinkable = io_setstrbuf(&str,0);
3314 make_readconv(fptr, 0);
3315 while (1) {
3316 VALUE v;
3317 if (fptr->cbuf.len) {
3318 if (first) rb_str_set_len(str, first = 0);
3319 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3320 }
3321 v = fill_cbuf(fptr, 0);
3322 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3323 if (fptr->cbuf.len) {
3324 if (first) rb_str_set_len(str, first = 0);
3325 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3326 }
3327 rb_exc_raise(v);
3328 }
3329 if (v == MORE_CHAR_FINISHED) {
3330 clear_readconv(fptr);
3331 if (first) rb_str_set_len(str, first = 0);
3332 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3333 return io_enc_str(str, fptr);
3334 }
3335 }
3336 }
3337
3338 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3339 bytes = 0;
3340 pos = 0;
3341
3342 enc = io_read_encoding(fptr);
3343 cr = 0;
3344
3345 if (siz == 0) siz = BUFSIZ;
3346 shrinkable = io_setstrbuf(&str, siz);
3347 for (;;) {
3348 READ_CHECK(fptr);
3349 n = io_fread(str, bytes, siz - bytes, fptr);
3350 if (n == 0 && bytes == 0) {
3351 rb_str_set_len(str, 0);
3352 break;
3353 }
3354 bytes += n;
3355 rb_str_set_len(str, bytes);
3356 if (cr != ENC_CODERANGE_BROKEN)
3357 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3358 if (bytes < siz) break;
3359 siz += BUFSIZ;
3360
3361 size_t capa = rb_str_capacity(str);
3362 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3363 if (capa < BUFSIZ) {
3364 capa = BUFSIZ;
3365 }
3366 else if (capa > IO_MAX_BUFFER_GROWTH) {
3367 capa = IO_MAX_BUFFER_GROWTH;
3368 }
3369 rb_str_modify_expand(str, capa);
3370 }
3371 }
3372 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3373 str = io_enc_str(str, fptr);
3374 ENC_CODERANGE_SET(str, cr);
3375 return str;
3376}
3377
3378void
3379rb_io_set_nonblock(rb_io_t *fptr)
3380{
3381 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3382 rb_sys_fail_path(fptr->pathv);
3383 }
3384}
3385
3386static VALUE
3387io_read_memory_call(VALUE arg)
3388{
3389 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3390
3391 VALUE scheduler = rb_fiber_scheduler_current();
3392 if (scheduler != Qnil) {
3393 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3394
3395 if (!UNDEF_P(result)) {
3396 // This is actually returned as a pseudo-VALUE and later cast to a long:
3397 return (VALUE)rb_fiber_scheduler_io_result_apply(result);
3398 }
3399 }
3400
3401 return rb_thread_io_blocking_region(internal_read_func, iis, iis->fptr->fd);
3402}
3403
3404static long
3405io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3406{
3407 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3408}
3409
3410#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3411
3412static VALUE
3413io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3414{
3415 rb_io_t *fptr;
3416 VALUE length, str;
3417 long n, len;
3418 struct io_internal_read_struct iis;
3419 int shrinkable;
3420
3421 rb_scan_args(argc, argv, "11", &length, &str);
3422
3423 if ((len = NUM2LONG(length)) < 0) {
3424 rb_raise(rb_eArgError, "negative length %ld given", len);
3425 }
3426
3427 shrinkable = io_setstrbuf(&str, len);
3428
3429 GetOpenFile(io, fptr);
3430 rb_io_check_byte_readable(fptr);
3431
3432 if (len == 0) {
3433 io_set_read_length(str, 0, shrinkable);
3434 return str;
3435 }
3436
3437 if (!nonblock)
3438 READ_CHECK(fptr);
3439 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3440 if (n <= 0) {
3441 again:
3442 if (nonblock) {
3443 rb_io_set_nonblock(fptr);
3444 }
3445 io_setstrbuf(&str, len);
3446 iis.th = rb_thread_current();
3447 iis.fptr = fptr;
3448 iis.nonblock = nonblock;
3449 iis.fd = fptr->fd;
3450 iis.buf = RSTRING_PTR(str);
3451 iis.capa = len;
3452 iis.timeout = NULL;
3453 n = io_read_memory_locktmp(str, &iis);
3454 if (n < 0) {
3455 int e = errno;
3456 if (!nonblock && fptr_wait_readable(fptr))
3457 goto again;
3458 if (nonblock && (io_again_p(e))) {
3459 if (no_exception)
3460 return sym_wait_readable;
3461 else
3462 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3463 e, "read would block");
3464 }
3465 rb_syserr_fail_path(e, fptr->pathv);
3466 }
3467 }
3468 io_set_read_length(str, n, shrinkable);
3469
3470 if (n == 0)
3471 return Qnil;
3472 else
3473 return str;
3474}
3475
3476/*
3477 * call-seq:
3478 * readpartial(maxlen) -> string
3479 * readpartial(maxlen, out_string) -> out_string
3480 *
3481 * Reads up to +maxlen+ bytes from the stream;
3482 * returns a string (either a new string or the given +out_string+).
3483 * Its encoding is:
3484 *
3485 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3486 * - ASCII-8BIT, otherwise.
3487 *
3488 * - Contains +maxlen+ bytes from the stream, if available.
3489 * - Otherwise contains all available bytes, if any available.
3490 * - Otherwise is an empty string.
3491 *
3492 * With the single non-negative integer argument +maxlen+ given,
3493 * returns a new string:
3494 *
3495 * f = File.new('t.txt')
3496 * f.readpartial(20) # => "First line\nSecond l"
3497 * f.readpartial(20) # => "ine\n\nFourth line\n"
3498 * f.readpartial(20) # => "Fifth line\n"
3499 * f.readpartial(20) # Raises EOFError.
3500 * f.close
3501 *
3502 * With both argument +maxlen+ and string argument +out_string+ given,
3503 * returns modified +out_string+:
3504 *
3505 * f = File.new('t.txt')
3506 * s = 'foo'
3507 * f.readpartial(20, s) # => "First line\nSecond l"
3508 * s = 'bar'
3509 * f.readpartial(0, s) # => ""
3510 * f.close
3511 *
3512 * This method is useful for a stream such as a pipe, a socket, or a tty.
3513 * It blocks only when no data is immediately available.
3514 * This means that it blocks only when _all_ of the following are true:
3515 *
3516 * - The byte buffer in the stream is empty.
3517 * - The content of the stream is empty.
3518 * - The stream is not at EOF.
3519 *
3520 * When blocked, the method waits for either more data or EOF on the stream:
3521 *
3522 * - If more data is read, the method returns the data.
3523 * - If EOF is reached, the method raises EOFError.
3524 *
3525 * When not blocked, the method responds immediately:
3526 *
3527 * - Returns data from the buffer if there is any.
3528 * - Otherwise returns data from the stream if there is any.
3529 * - Otherwise raises EOFError if the stream has reached EOF.
3530 *
3531 * Note that this method is similar to sysread. The differences are:
3532 *
3533 * - If the byte buffer is not empty, read from the byte buffer
3534 * instead of "sysread for buffered IO (IOError)".
3535 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3536 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3537 * readpartial retries the system call.
3538 *
3539 * The latter means that readpartial is non-blocking-flag insensitive.
3540 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3541 * if the fd is blocking mode.
3542 *
3543 * Examples:
3544 *
3545 * # # Returned Buffer Content Pipe Content
3546 * r, w = IO.pipe #
3547 * w << 'abc' # "" "abc".
3548 * r.readpartial(4096) # => "abc" "" ""
3549 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3550 *
3551 * # # Returned Buffer Content Pipe Content
3552 * r, w = IO.pipe #
3553 * w << 'abc' # "" "abc"
3554 * w.close # "" "abc" EOF
3555 * r.readpartial(4096) # => "abc" "" EOF
3556 * r.readpartial(4096) # raises EOFError
3557 *
3558 * # # Returned Buffer Content Pipe Content
3559 * r, w = IO.pipe #
3560 * w << "abc\ndef\n" # "" "abc\ndef\n"
3561 * r.gets # => "abc\n" "def\n" ""
3562 * w << "ghi\n" # "def\n" "ghi\n"
3563 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3564 * r.readpartial(4096) # => "ghi\n" "" ""
3565 *
3566 */
3567
3568static VALUE
3569io_readpartial(int argc, VALUE *argv, VALUE io)
3570{
3571 VALUE ret;
3572
3573 ret = io_getpartial(argc, argv, io, Qnil, 0);
3574 if (NIL_P(ret))
3575 rb_eof_error();
3576 return ret;
3577}
3578
3579static VALUE
3580io_nonblock_eof(int no_exception)
3581{
3582 if (!no_exception) {
3583 rb_eof_error();
3584 }
3585 return Qnil;
3586}
3587
3588/* :nodoc: */
3589static VALUE
3590io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3591{
3592 rb_io_t *fptr;
3593 long n, len;
3594 struct io_internal_read_struct iis;
3595 int shrinkable;
3596
3597 if ((len = NUM2LONG(length)) < 0) {
3598 rb_raise(rb_eArgError, "negative length %ld given", len);
3599 }
3600
3601 shrinkable = io_setstrbuf(&str, len);
3602 rb_bool_expected(ex, "exception", TRUE);
3603
3604 GetOpenFile(io, fptr);
3605 rb_io_check_byte_readable(fptr);
3606
3607 if (len == 0) {
3608 io_set_read_length(str, 0, shrinkable);
3609 return str;
3610 }
3611
3612 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3613 if (n <= 0) {
3614 rb_fd_set_nonblock(fptr->fd);
3615 shrinkable |= io_setstrbuf(&str, len);
3616 iis.fptr = fptr;
3617 iis.nonblock = 1;
3618 iis.fd = fptr->fd;
3619 iis.buf = RSTRING_PTR(str);
3620 iis.capa = len;
3621 iis.timeout = NULL;
3622 n = io_read_memory_locktmp(str, &iis);
3623 if (n < 0) {
3624 int e = errno;
3625 if (io_again_p(e)) {
3626 if (!ex) return sym_wait_readable;
3627 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3628 e, "read would block");
3629 }
3630 rb_syserr_fail_path(e, fptr->pathv);
3631 }
3632 }
3633 io_set_read_length(str, n, shrinkable);
3634
3635 if (n == 0) {
3636 if (!ex) return Qnil;
3637 rb_eof_error();
3638 }
3639
3640 return str;
3641}
3642
3643/* :nodoc: */
3644static VALUE
3645io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3646{
3647 rb_io_t *fptr;
3648 long n;
3649
3650 if (!RB_TYPE_P(str, T_STRING))
3651 str = rb_obj_as_string(str);
3652 rb_bool_expected(ex, "exception", TRUE);
3653
3654 io = GetWriteIO(io);
3655 GetOpenFile(io, fptr);
3656 rb_io_check_writable(fptr);
3657
3658 if (io_fflush(fptr) < 0)
3659 rb_sys_fail_on_write(fptr);
3660
3661 rb_fd_set_nonblock(fptr->fd);
3662 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3663 RB_GC_GUARD(str);
3664
3665 if (n < 0) {
3666 int e = errno;
3667 if (io_again_p(e)) {
3668 if (!ex) {
3669 return sym_wait_writable;
3670 }
3671 else {
3672 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3673 }
3674 }
3675 rb_syserr_fail_path(e, fptr->pathv);
3676 }
3677
3678 return LONG2FIX(n);
3679}
3680
3681/*
3682 * call-seq:
3683 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3684 *
3685 * Reads bytes from the stream; the stream must be opened for reading
3686 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3687 *
3688 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3689 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3690 *
3691 * Returns a string (either a new string or the given +out_string+)
3692 * containing the bytes read.
3693 * The encoding of the string depends on both +maxLen+ and +out_string+:
3694 *
3695 * - +maxlen+ is +nil+: uses internal encoding of +self+
3696 * (regardless of whether +out_string+ was given).
3697 * - +maxlen+ not +nil+:
3698 *
3699 * - +out_string+ given: encoding of +out_string+ not modified.
3700 * - +out_string+ not given: ASCII-8BIT is used.
3701 *
3702 * <b>Without Argument +out_string+</b>
3703 *
3704 * When argument +out_string+ is omitted,
3705 * the returned value is a new string:
3706 *
3707 * f = File.new('t.txt')
3708 * f.read
3709 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3710 * f.rewind
3711 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3712 * f.read(30) # => "rth line\r\nFifth line\r\n"
3713 * f.read(30) # => nil
3714 * f.close
3715 *
3716 * If +maxlen+ is zero, returns an empty string.
3717 *
3718 * <b> With Argument +out_string+</b>
3719 *
3720 * When argument +out_string+ is given,
3721 * the returned value is +out_string+, whose content is replaced:
3722 *
3723 * f = File.new('t.txt')
3724 * s = 'foo' # => "foo"
3725 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3726 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3727 * f.rewind
3728 * s = 'bar'
3729 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3730 * s # => "First line\r\nSecond line\r\n\r\nFou"
3731 * s = 'baz'
3732 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3733 * s # => "rth line\r\nFifth line\r\n"
3734 * s = 'bat'
3735 * f.read(30, s) # => nil
3736 * s # => ""
3737 * f.close
3738 *
3739 * Note that this method behaves like the fread() function in C.
3740 * This means it retries to invoke read(2) system calls to read data
3741 * with the specified maxlen (or until EOF).
3742 *
3743 * This behavior is preserved even if the stream is in non-blocking mode.
3744 * (This method is non-blocking-flag insensitive as other methods.)
3745 *
3746 * If you need the behavior like a single read(2) system call,
3747 * consider #readpartial, #read_nonblock, and #sysread.
3748 *
3749 * Related: IO#write.
3750 */
3751
3752static VALUE
3753io_read(int argc, VALUE *argv, VALUE io)
3754{
3755 rb_io_t *fptr;
3756 long n, len;
3757 VALUE length, str;
3758 int shrinkable;
3759#if RUBY_CRLF_ENVIRONMENT
3760 int previous_mode;
3761#endif
3762
3763 rb_scan_args(argc, argv, "02", &length, &str);
3764
3765 if (NIL_P(length)) {
3766 GetOpenFile(io, fptr);
3767 rb_io_check_char_readable(fptr);
3768 return read_all(fptr, remain_size(fptr), str);
3769 }
3770 len = NUM2LONG(length);
3771 if (len < 0) {
3772 rb_raise(rb_eArgError, "negative length %ld given", len);
3773 }
3774
3775 shrinkable = io_setstrbuf(&str,len);
3776
3777 GetOpenFile(io, fptr);
3778 rb_io_check_byte_readable(fptr);
3779 if (len == 0) {
3780 io_set_read_length(str, 0, shrinkable);
3781 return str;
3782 }
3783
3784 READ_CHECK(fptr);
3785#if RUBY_CRLF_ENVIRONMENT
3786 previous_mode = set_binary_mode_with_seek_cur(fptr);
3787#endif
3788 n = io_fread(str, 0, len, fptr);
3789 io_set_read_length(str, n, shrinkable);
3790#if RUBY_CRLF_ENVIRONMENT
3791 if (previous_mode == O_TEXT) {
3792 setmode(fptr->fd, O_TEXT);
3793 }
3794#endif
3795 if (n == 0) return Qnil;
3796
3797 return str;
3798}
3799
3800static void
3801rscheck(const char *rsptr, long rslen, VALUE rs)
3802{
3803 if (!rs) return;
3804 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3805 rb_raise(rb_eRuntimeError, "rs modified");
3806}
3807
3808static int
3809appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
3810{
3811 VALUE str = *strp;
3812 long limit = *lp;
3813
3814 if (NEED_READCONV(fptr)) {
3815 SET_BINARY_MODE(fptr);
3816 make_readconv(fptr, 0);
3817 do {
3818 const char *p, *e;
3819 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3820 if (searchlen) {
3821 p = READ_CHAR_PENDING_PTR(fptr);
3822 if (0 < limit && limit < searchlen)
3823 searchlen = (int)limit;
3824 e = memchr(p, delim, searchlen);
3825 if (e) {
3826 int len = (int)(e-p+1);
3827 if (NIL_P(str))
3828 *strp = str = rb_str_new(p, len);
3829 else
3830 rb_str_buf_cat(str, p, len);
3831 fptr->cbuf.off += len;
3832 fptr->cbuf.len -= len;
3833 limit -= len;
3834 *lp = limit;
3835 return delim;
3836 }
3837
3838 if (NIL_P(str))
3839 *strp = str = rb_str_new(p, searchlen);
3840 else
3841 rb_str_buf_cat(str, p, searchlen);
3842 fptr->cbuf.off += searchlen;
3843 fptr->cbuf.len -= searchlen;
3844 limit -= searchlen;
3845
3846 if (limit == 0) {
3847 *lp = limit;
3848 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3849 }
3850 }
3851 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3852 clear_readconv(fptr);
3853 *lp = limit;
3854 return EOF;
3855 }
3856
3857 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3858 do {
3859 long pending = READ_DATA_PENDING_COUNT(fptr);
3860 if (pending > 0) {
3861 const char *p = READ_DATA_PENDING_PTR(fptr);
3862 const char *e;
3863 long last;
3864
3865 if (limit > 0 && pending > limit) pending = limit;
3866 e = memchr(p, delim, pending);
3867 if (e) pending = e - p + 1;
3868 if (!NIL_P(str)) {
3869 last = RSTRING_LEN(str);
3870 rb_str_resize(str, last + pending);
3871 }
3872 else {
3873 last = 0;
3874 *strp = str = rb_str_buf_new(pending);
3875 rb_str_set_len(str, pending);
3876 }
3877 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3878 limit -= pending;
3879 *lp = limit;
3880 if (e) return delim;
3881 if (limit == 0)
3882 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3883 }
3884 READ_CHECK(fptr);
3885 } while (io_fillbuf(fptr) >= 0);
3886 *lp = limit;
3887 return EOF;
3888}
3889
3890static inline int
3891swallow(rb_io_t *fptr, int term)
3892{
3893 if (NEED_READCONV(fptr)) {
3894 rb_encoding *enc = io_read_encoding(fptr);
3895 int needconv = rb_enc_mbminlen(enc) != 1;
3896 SET_BINARY_MODE(fptr);
3897 make_readconv(fptr, 0);
3898 do {
3899 size_t cnt;
3900 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3901 const char *p = READ_CHAR_PENDING_PTR(fptr);
3902 int i;
3903 if (!needconv) {
3904 if (*p != term) return TRUE;
3905 i = (int)cnt;
3906 while (--i && *++p == term);
3907 }
3908 else {
3909 const char *e = p + cnt;
3910 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3911 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3912 i = (int)(e - p);
3913 }
3914 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3915 }
3916 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3917 return FALSE;
3918 }
3919
3920 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3921 do {
3922 size_t cnt;
3923 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3924 char buf[1024];
3925 const char *p = READ_DATA_PENDING_PTR(fptr);
3926 int i;
3927 if (cnt > sizeof buf) cnt = sizeof buf;
3928 if (*p != term) return TRUE;
3929 i = (int)cnt;
3930 while (--i && *++p == term);
3931 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
3932 rb_sys_fail_path(fptr->pathv);
3933 }
3934 READ_CHECK(fptr);
3935 } while (io_fillbuf(fptr) == 0);
3936 return FALSE;
3937}
3938
3939static VALUE
3940rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
3941{
3942 VALUE str = Qnil;
3943 int len = 0;
3944 long pos = 0;
3945 int cr = 0;
3946
3947 do {
3948 int pending = READ_DATA_PENDING_COUNT(fptr);
3949
3950 if (pending > 0) {
3951 const char *p = READ_DATA_PENDING_PTR(fptr);
3952 const char *e;
3953 int chomplen = 0;
3954
3955 e = memchr(p, '\n', pending);
3956 if (e) {
3957 pending = (int)(e - p + 1);
3958 if (chomp) {
3959 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
3960 }
3961 }
3962 if (NIL_P(str)) {
3963 str = rb_str_new(p, pending - chomplen);
3964 fptr->rbuf.off += pending;
3965 fptr->rbuf.len -= pending;
3966 }
3967 else {
3968 rb_str_resize(str, len + pending - chomplen);
3969 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
3970 fptr->rbuf.off += chomplen;
3971 fptr->rbuf.len -= chomplen;
3972 if (pending == 1 && chomplen == 1 && len > 0) {
3973 if (RSTRING_PTR(str)[len-1] == '\r') {
3974 rb_str_resize(str, --len);
3975 break;
3976 }
3977 }
3978 }
3979 len += pending - chomplen;
3980 if (cr != ENC_CODERANGE_BROKEN)
3981 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
3982 if (e) break;
3983 }
3984 READ_CHECK(fptr);
3985 } while (io_fillbuf(fptr) >= 0);
3986 if (NIL_P(str)) return Qnil;
3987
3988 str = io_enc_str(str, fptr);
3989 ENC_CODERANGE_SET(str, cr);
3990 fptr->lineno++;
3991
3992 return str;
3993}
3994
3995 struct getline_arg {
3996 VALUE io;
3997 VALUE rs;
3998 long limit;
3999 unsigned int chomp: 1;
4000};
4001
4002static void
4003extract_getline_opts(VALUE opts, struct getline_arg *args)
4004{
4005 int chomp = FALSE;
4006 if (!NIL_P(opts)) {
4007 static ID kwds[1];
4008 VALUE vchomp;
4009 if (!kwds[0]) {
4010 kwds[0] = rb_intern_const("chomp");
4011 }
4012 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4013 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4014 }
4015 args->chomp = chomp;
4016}
4017
4018static void
4019extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4020{
4021 VALUE rs = rb_rs, lim = Qnil;
4022
4023 if (argc == 1) {
4024 VALUE tmp = Qnil;
4025
4026 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4027 rs = tmp;
4028 }
4029 else {
4030 lim = argv[0];
4031 }
4032 }
4033 else if (2 <= argc) {
4034 rs = argv[0], lim = argv[1];
4035 if (!NIL_P(rs))
4036 StringValue(rs);
4037 }
4038 args->rs = rs;
4039 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4040}
4041
4042static void
4043check_getline_args(VALUE *rsp, long *limit, VALUE io)
4044{
4045 rb_io_t *fptr;
4046 VALUE rs = *rsp;
4047
4048 if (!NIL_P(rs)) {
4049 rb_encoding *enc_rs, *enc_io;
4050
4051 GetOpenFile(io, fptr);
4052 enc_rs = rb_enc_get(rs);
4053 enc_io = io_read_encoding(fptr);
4054 if (enc_io != enc_rs &&
4055 (!is_ascii_string(rs) ||
4056 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4057 if (rs == rb_default_rs) {
4058 rs = rb_enc_str_new(0, 0, enc_io);
4059 rb_str_buf_cat_ascii(rs, "\n");
4060 *rsp = rs;
4061 }
4062 else {
4063 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4064 rb_enc_name(enc_io),
4065 rb_enc_name(enc_rs));
4066 }
4067 }
4068 }
4069}
4070
4071static void
4072prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4073{
4074 VALUE opts;
4075 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4076 extract_getline_args(argc, argv, args);
4077 extract_getline_opts(opts, args);
4078 check_getline_args(&args->rs, &args->limit, io);
4079}
4080
4081static VALUE
4082rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4083{
4084 VALUE str = Qnil;
4085 int nolimit = 0;
4086 rb_encoding *enc;
4087
4088 rb_io_check_char_readable(fptr);
4089 if (NIL_P(rs) && limit < 0) {
4090 str = read_all(fptr, 0, Qnil);
4091 if (RSTRING_LEN(str) == 0) return Qnil;
4092 }
4093 else if (limit == 0) {
4094 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4095 }
4096 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4097 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4098 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4099 return rb_io_getline_fast(fptr, enc, chomp);
4100 }
4101 else {
4102 int c, newline = -1;
4103 const char *rsptr = 0;
4104 long rslen = 0;
4105 int rspara = 0;
4106 int extra_limit = 16;
4107 int chomp_cr = chomp;
4108
4109 SET_BINARY_MODE(fptr);
4110 enc = io_read_encoding(fptr);
4111
4112 if (!NIL_P(rs)) {
4113 rslen = RSTRING_LEN(rs);
4114 if (rslen == 0) {
4115 rsptr = "\n\n";
4116 rslen = 2;
4117 rspara = 1;
4118 swallow(fptr, '\n');
4119 rs = 0;
4120 if (!rb_enc_asciicompat(enc)) {
4121 rs = rb_usascii_str_new(rsptr, rslen);
4122 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
4123 OBJ_FREEZE(rs);
4124 rsptr = RSTRING_PTR(rs);
4125 rslen = RSTRING_LEN(rs);
4126 }
4127 }
4128 else {
4129 rsptr = RSTRING_PTR(rs);
4130 }
4131 newline = (unsigned char)rsptr[rslen - 1];
4132 chomp_cr = chomp && rslen == 1 && newline == '\n';
4133 }
4134
4135 /* MS - Optimization */
4136 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
4137 const char *s, *p, *pp, *e;
4138
4139 if (c == newline) {
4140 if (RSTRING_LEN(str) < rslen) continue;
4141 s = RSTRING_PTR(str);
4142 e = RSTRING_END(str);
4143 p = e - rslen;
4144 pp = rb_enc_left_char_head(s, p, e, enc);
4145 if (pp != p) continue;
4146 if (!rspara) rscheck(rsptr, rslen, rs);
4147 if (memcmp(p, rsptr, rslen) == 0) {
4148 if (chomp) {
4149 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4150 rb_str_set_len(str, p - s);
4151 }
4152 break;
4153 }
4154 }
4155 if (limit == 0) {
4156 s = RSTRING_PTR(str);
4157 p = RSTRING_END(str);
4158 pp = rb_enc_left_char_head(s, p-1, p, enc);
4159 if (extra_limit &&
4160 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4161 /* relax the limit while incomplete character.
4162 * extra_limit limits the relax length */
4163 limit = 1;
4164 extra_limit--;
4165 }
4166 else {
4167 nolimit = 1;
4168 break;
4169 }
4170 }
4171 }
4172
4173 if (rspara && c != EOF)
4174 swallow(fptr, '\n');
4175 if (!NIL_P(str))
4176 str = io_enc_str(str, fptr);
4177 }
4178
4179 if (!NIL_P(str) && !nolimit) {
4180 fptr->lineno++;
4181 }
4182
4183 return str;
4184}
4185
4186static VALUE
4187rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4188{
4189 rb_io_t *fptr;
4190 int old_lineno, new_lineno;
4191 VALUE str;
4192
4193 GetOpenFile(io, fptr);
4194 old_lineno = fptr->lineno;
4195 str = rb_io_getline_0(rs, limit, chomp, fptr);
4196 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4197 if (io == ARGF.current_file) {
4198 ARGF.lineno += new_lineno - old_lineno;
4199 ARGF.last_lineno = ARGF.lineno;
4200 }
4201 else {
4202 ARGF.last_lineno = new_lineno;
4203 }
4204 }
4205
4206 return str;
4207}
4208
4209static VALUE
4210rb_io_getline(int argc, VALUE *argv, VALUE io)
4211{
4212 struct getline_arg args;
4213
4214 prepare_getline_args(argc, argv, &args, io);
4215 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4216}
4217
4218 VALUE
4219rb_io_gets(VALUE io)
4220{
4221 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4222}
4223
4224 VALUE
4225rb_io_gets_internal(VALUE io)
4226{
4227 rb_io_t *fptr;
4228 GetOpenFile(io, fptr);
4229 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4230}
4231
4232/*
4233 * call-seq:
4234 * gets(sep = $/, chomp: false) -> string or nil
4235 * gets(limit, chomp: false) -> string or nil
4236 * gets(sep, limit, chomp: false) -> string or nil
4237 *
4238 * Reads and returns a line from the stream;
4239 * assigns the return value to <tt>$_</tt>.
4240 * See {Line IO}[rdoc-ref:IO@Line+IO].
4241 *
4242 * With no arguments given, returns the next line
4243 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4244 *
4245 * f = File.open('t.txt')
4246 * f.gets # => "First line\n"
4247 * $_ # => "First line\n"
4248 * f.gets # => "\n"
4249 * f.gets # => "Fourth line\n"
4250 * f.gets # => "Fifth line\n"
4251 * f.gets # => nil
4252 * f.close
4253 *
4254 * With only string argument +sep+ given,
4255 * returns the next line as determined by line separator +sep+,
4256 * or +nil+ if none;
4257 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4258 *
4259 * f = File.new('t.txt')
4260 * f.gets('l') # => "First l"
4261 * f.gets('li') # => "ine\nSecond li"
4262 * f.gets('lin') # => "ne\n\nFourth lin"
4263 * f.gets # => "e\n"
4264 * f.close
4265 *
4266 * The two special values for +sep+ are honored:
4267 *
4268 * f = File.new('t.txt')
4269 * # Get all.
4270 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4271 * f.rewind
4272 * # Get paragraph (up to two line separators).
4273 * f.gets('') # => "First line\nSecond line\n\n"
4274 * f.close
4275 *
4276 * With only integer argument +limit+ given,
4277 * limits the number of bytes in the line;
4278 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4279 *
4280 * # No more than one line.
4281 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4282 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4283 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4284 *
4285 * With arguments +sep+ and +limit+ given,
4286 * combines the two behaviors:
4287 *
4288 * - Returns the next line as determined by line separator +sep+,
4289 * or +nil+ if none.
4290 * - But returns no more bytes than are allowed by the limit.
4291 *
4292 * Optional keyword argument +chomp+ specifies whether line separators
4293 * are to be omitted:
4294 *
4295 * f = File.open('t.txt')
4296 * # Chomp the lines.
4297 * f.gets(chomp: true) # => "First line"
4298 * f.gets(chomp: true) # => "Second line"
4299 * f.gets(chomp: true) # => ""
4300 * f.gets(chomp: true) # => "Fourth line"
4301 * f.gets(chomp: true) # => "Fifth line"
4302 * f.gets(chomp: true) # => nil
4303 * f.close
4304 *
4305 */
4306
4307static VALUE
4308rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4309{
4310 VALUE str;
4311
4312 str = rb_io_getline(argc, argv, io);
4313 rb_lastline_set(str);
4314
4315 return str;
4316}
4317
4318/*
4319 * call-seq:
4320 * lineno -> integer
4321 *
4322 * Returns the current line number for the stream;
4323 * see {Line Number}[rdoc-ref:IO@Line+Number].
4324 *
4325 */
4326
4327static VALUE
4328rb_io_lineno(VALUE io)
4329{
4330 rb_io_t *fptr;
4331
4332 GetOpenFile(io, fptr);
4333 rb_io_check_char_readable(fptr);
4334 return INT2NUM(fptr->lineno);
4335}
4336
4337/*
4338 * call-seq:
4339 * lineno = integer -> integer
4340 *
4341 * Sets and returns the line number for the stream;
4342 * see {Line Number}[rdoc-ref:IO@Line+Number].
4343 *
4344 */
4345
4346static VALUE
4347rb_io_set_lineno(VALUE io, VALUE lineno)
4348{
4349 rb_io_t *fptr;
4350
4351 GetOpenFile(io, fptr);
4352 rb_io_check_char_readable(fptr);
4353 fptr->lineno = NUM2INT(lineno);
4354 return lineno;
4355}
4356
4357/*
4358 * call-seq:
4359 * readline(sep = $/, chomp: false) -> string
4360 * readline(limit, chomp: false) -> string
4361 * readline(sep, limit, chomp: false) -> string
4362 *
4363 * Reads a line as with IO#gets, but raises EOFError if already at end-of-stream.
4364 *
4365 * Optional keyword argument +chomp+ specifies whether line separators
4366 * are to be omitted.
4367 */
4368
4369static VALUE
4370rb_io_readline(int argc, VALUE *argv, VALUE io)
4371{
4372 VALUE line = rb_io_gets_m(argc, argv, io);
4373
4374 if (NIL_P(line)) {
4375 rb_eof_error();
4376 }
4377 return line;
4378}
4379
4380static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4381
4382/*
4383 * call-seq:
4384 * readlines(sep = $/, chomp: false) -> array
4385 * readlines(limit, chomp: false) -> array
4386 * readlines(sep, limit, chomp: false) -> array
4387 *
4388 * Reads and returns all remaining line from the stream;
4389 * does not modify <tt>$_</tt>.
4390 * See {Line IO}[rdoc-ref:IO@Line+IO].
4391 *
4392 * With no arguments given, returns lines
4393 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4394 *
4395 * f = File.new('t.txt')
4396 * f.readlines
4397 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4398 * f.readlines # => []
4399 * f.close
4400 *
4401 * With only string argument +sep+ given,
4402 * returns lines as determined by line separator +sep+,
4403 * or +nil+ if none;
4404 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4405 *
4406 * f = File.new('t.txt')
4407 * f.readlines('li')
4408 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4409 * f.close
4410 *
4411 * The two special values for +sep+ are honored:
4412 *
4413 * f = File.new('t.txt')
4414 * # Get all into one string.
4415 * f.readlines(nil)
4416 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4417 * # Get paragraphs (up to two line separators).
4418 * f.rewind
4419 * f.readlines('')
4420 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4421 * f.close
4422 *
4423 * With only integer argument +limit+ given,
4424 * limits the number of bytes in each line;
4425 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4426 *
4427 * f = File.new('t.txt')
4428 * f.readlines(8)
4429 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4430 * f.close
4431 *
4432 * With arguments +sep+ and +limit+ given,
4433 * combines the two behaviors:
4434 *
4435 * - Returns lines as determined by line separator +sep+.
4436 * - But returns no more bytes in a line than are allowed by the limit.
4437 *
4438 * Optional keyword argument +chomp+ specifies whether line separators
4439 * are to be omitted:
4440 *
4441 * f = File.new('t.txt')
4442 * f.readlines(chomp: true)
4443 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4444 * f.close
4445 *
4446 */
4447
4448static VALUE
4449rb_io_readlines(int argc, VALUE *argv, VALUE io)
4450{
4451 struct getline_arg args;
4452
4453 prepare_getline_args(argc, argv, &args, io);
4454 return io_readlines(&args, io);
4455}
4456
4457static VALUE
4458io_readlines(const struct getline_arg *arg, VALUE io)
4459{
4460 VALUE line, ary;
4461
4462 if (arg->limit == 0)
4463 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4464 ary = rb_ary_new();
4465 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4466 rb_ary_push(ary, line);
4467 }
4468 return ary;
4469}
4470
4471/*
4472 * call-seq:
4473 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4474 * each_line(limit, chomp: false) {|line| ... } -> self
4475 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4476 * each_line -> enumerator
4477 *
4478 * Calls the block with each remaining line read from the stream;
4479 * returns +self+.
4480 * Does nothing if already at end-of-stream;
4481 * See {Line IO}[rdoc-ref:IO@Line+IO].
4482 *
4483 * With no arguments given, reads lines
4484 * as determined by line separator <tt>$/</tt>:
4485 *
4486 * f = File.new('t.txt')
4487 * f.each_line {|line| p line }
4488 * f.each_line {|line| fail 'Cannot happen' }
4489 * f.close
4490 *
4491 * Output:
4492 *
4493 * "First line\n"
4494 * "Second line\n"
4495 * "\n"
4496 * "Fourth line\n"
4497 * "Fifth line\n"
4498 *
4499 * With only string argument +sep+ given,
4500 * reads lines as determined by line separator +sep+;
4501 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4502 *
4503 * f = File.new('t.txt')
4504 * f.each_line('li') {|line| p line }
4505 * f.close
4506 *
4507 * Output:
4508 *
4509 * "First li"
4510 * "ne\nSecond li"
4511 * "ne\n\nFourth li"
4512 * "ne\nFifth li"
4513 * "ne\n"
4514 *
4515 * The two special values for +sep+ are honored:
4516 *
4517 * f = File.new('t.txt')
4518 * # Get all into one string.
4519 * f.each_line(nil) {|line| p line }
4520 * f.close
4521 *
4522 * Output:
4523 *
4524 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4525 *
4526 * f.rewind
4527 * # Get paragraphs (up to two line separators).
4528 * f.each_line('') {|line| p line }
4529 *
4530 * Output:
4531 *
4532 * "First line\nSecond line\n\n"
4533 * "Fourth line\nFifth line\n"
4534 *
4535 * With only integer argument +limit+ given,
4536 * limits the number of bytes in each line;
4537 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4538 *
4539 * f = File.new('t.txt')
4540 * f.each_line(8) {|line| p line }
4541 * f.close
4542 *
4543 * Output:
4544 *
4545 * "First li"
4546 * "ne\n"
4547 * "Second l"
4548 * "ine\n"
4549 * "\n"
4550 * "Fourth l"
4551 * "ine\n"
4552 * "Fifth li"
4553 * "ne\n"
4554 *
4555 * With arguments +sep+ and +limit+ given,
4556 * combines the two behaviors:
4557 *
4558 * - Calls with the next line as determined by line separator +sep+.
4559 * - But returns no more bytes than are allowed by the limit.
4560 *
4561 * Optional keyword argument +chomp+ specifies whether line separators
4562 * are to be omitted:
4563 *
4564 * f = File.new('t.txt')
4565 * f.each_line(chomp: true) {|line| p line }
4566 * f.close
4567 *
4568 * Output:
4569 *
4570 * "First line"
4571 * "Second line"
4572 * ""
4573 * "Fourth line"
4574 * "Fifth line"
4575 *
4576 * Returns an Enumerator if no block is given.
4577 *
4578 * IO#each is an alias for IO#each_line.
4579 *
4580 */
4581
4582static VALUE
4583rb_io_each_line(int argc, VALUE *argv, VALUE io)
4584{
4585 VALUE str;
4586 struct getline_arg args;
4587
4588 RETURN_ENUMERATOR(io, argc, argv);
4589 prepare_getline_args(argc, argv, &args, io);
4590 if (args.limit == 0)
4591 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4592 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4593 rb_yield(str);
4594 }
4595 return io;
4596}
4597
4598/*
4599 * call-seq:
4600 * each_byte {|byte| ... } -> self
4601 * each_byte -> enumerator
4602 *
4603 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4604 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4605 *
4606 * f = File.new('t.rus')
4607 * a = []
4608 * f.each_byte {|b| a << b }
4609 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4610 * f.close
4611 *
4612 * Returns an Enumerator if no block is given.
4613 *
4614 * Related: IO#each_char, IO#each_codepoint.
4615 *
4616 */
4617
4618static VALUE
4619rb_io_each_byte(VALUE io)
4620{
4621 rb_io_t *fptr;
4622
4623 RETURN_ENUMERATOR(io, 0, 0);
4624 GetOpenFile(io, fptr);
4625
4626 do {
4627 while (fptr->rbuf.len > 0) {
4628 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4629 fptr->rbuf.len--;
4630 rb_yield(INT2FIX(*p & 0xff));
4631 rb_io_check_byte_readable(fptr);
4632 errno = 0;
4633 }
4634 READ_CHECK(fptr);
4635 } while (io_fillbuf(fptr) >= 0);
4636 return io;
4637}
4638
4639static VALUE
4640io_getc(rb_io_t *fptr, rb_encoding *enc)
4641{
4642 int r, n, cr = 0;
4643 VALUE str;
4644
4645 if (NEED_READCONV(fptr)) {
4646 rb_encoding *read_enc = io_read_encoding(fptr);
4647
4648 str = Qnil;
4649 SET_BINARY_MODE(fptr);
4650 make_readconv(fptr, 0);
4651
4652 while (1) {
4653 if (fptr->cbuf.len) {
4654 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4655 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4656 read_enc);
4657 if (!MBCLEN_NEEDMORE_P(r))
4658 break;
4659 if (fptr->cbuf.len == fptr->cbuf.capa) {
4660 rb_raise(rb_eIOError, "too long character");
4661 }
4662 }
4663
4664 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4665 if (fptr->cbuf.len == 0) {
4666 clear_readconv(fptr);
4667 return Qnil;
4668 }
4669 /* return an unit of an incomplete character just before EOF */
4670 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4671 fptr->cbuf.off += 1;
4672 fptr->cbuf.len -= 1;
4673 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4674 ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
4675 return str;
4676 }
4677 }
4678 if (MBCLEN_INVALID_P(r)) {
4679 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4680 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4681 read_enc);
4682 io_shift_cbuf(fptr, r, &str);
4683 cr = ENC_CODERANGE_BROKEN;
4684 }
4685 else {
4686 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4687 cr = ENC_CODERANGE_VALID;
4688 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4689 ISASCII(RSTRING_PTR(str)[0])) {
4690 cr = ENC_CODERANGE_7BIT;
4691 }
4692 }
4693 str = io_enc_str(str, fptr);
4694 ENC_CODERANGE_SET(str, cr);
4695 return str;
4696 }
4697
4698 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4699 if (io_fillbuf(fptr) < 0) {
4700 return Qnil;
4701 }
4702 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4703 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4704 fptr->rbuf.off += 1;
4705 fptr->rbuf.len -= 1;
4706 cr = ENC_CODERANGE_7BIT;
4707 }
4708 else {
4709 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4710 if (MBCLEN_CHARFOUND_P(r) &&
4711 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4712 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4713 fptr->rbuf.off += n;
4714 fptr->rbuf.len -= n;
4715 cr = ENC_CODERANGE_VALID;
4716 }
4717 else if (MBCLEN_NEEDMORE_P(r)) {
4718 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4719 fptr->rbuf.len = 0;
4720 getc_needmore:
4721 if (io_fillbuf(fptr) != -1) {
4722 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4723 fptr->rbuf.off++;
4724 fptr->rbuf.len--;
4725 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4726 if (MBCLEN_NEEDMORE_P(r)) {
4727 goto getc_needmore;
4728 }
4729 else if (MBCLEN_CHARFOUND_P(r)) {
4730 cr = ENC_CODERANGE_VALID;
4731 }
4732 }
4733 }
4734 else {
4735 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4736 fptr->rbuf.off++;
4737 fptr->rbuf.len--;
4738 }
4739 }
4740 if (!cr) cr = ENC_CODERANGE_BROKEN;
4741 str = io_enc_str(str, fptr);
4742 ENC_CODERANGE_SET(str, cr);
4743 return str;
4744}
4745
4746/*
4747 * call-seq:
4748 * each_char {|c| ... } -> self
4749 * each_char -> enumerator
4750 *
4751 * Calls the given block with each character in the stream; returns +self+.
4752 * See {Character IO}[rdoc-ref:IO@Character+IO].
4753 *
4754 * f = File.new('t.rus')
4755 * a = []
4756 * f.each_char {|c| a << c.ord }
4757 * a # => [1090, 1077, 1089, 1090]
4758 * f.close
4759 *
4760 * Returns an Enumerator if no block is given.
4761 *
4762 * Related: IO#each_byte, IO#each_codepoint.
4763 *
4764 */
4765
4766static VALUE
4767rb_io_each_char(VALUE io)
4768{
4769 rb_io_t *fptr;
4770 rb_encoding *enc;
4771 VALUE c;
4772
4773 RETURN_ENUMERATOR(io, 0, 0);
4774 GetOpenFile(io, fptr);
4775 rb_io_check_char_readable(fptr);
4776
4777 enc = io_input_encoding(fptr);
4778 READ_CHECK(fptr);
4779 while (!NIL_P(c = io_getc(fptr, enc))) {
4780 rb_yield(c);
4781 }
4782 return io;
4783}
4784
4785/*
4786 * call-seq:
4787 * each_codepoint {|c| ... } -> self
4788 * each_codepoint -> enumerator
4789 *
4790 * Calls the given block with each codepoint in the stream; returns +self+:
4791 *
4792 * f = File.new('t.rus')
4793 * a = []
4794 * f.each_codepoint {|c| a << c }
4795 * a # => [1090, 1077, 1089, 1090]
4796 * f.close
4797 *
4798 * Returns an Enumerator if no block is given.
4799 *
4800 * Related: IO#each_byte, IO#each_char.
4801 *
4802 */
4803
4804static VALUE
4805rb_io_each_codepoint(VALUE io)
4806{
4807 rb_io_t *fptr;
4808 rb_encoding *enc;
4809 unsigned int c;
4810 int r, n;
4811
4812 RETURN_ENUMERATOR(io, 0, 0);
4813 GetOpenFile(io, fptr);
4814 rb_io_check_char_readable(fptr);
4815
4816 READ_CHECK(fptr);
4817 if (NEED_READCONV(fptr)) {
4818 SET_BINARY_MODE(fptr);
4819 r = 1; /* no invalid char yet */
4820 for (;;) {
4821 make_readconv(fptr, 0);
4822 for (;;) {
4823 if (fptr->cbuf.len) {
4824 if (fptr->encs.enc)
4825 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4826 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4827 fptr->encs.enc);
4828 else
4829 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4830 if (!MBCLEN_NEEDMORE_P(r))
4831 break;
4832 if (fptr->cbuf.len == fptr->cbuf.capa) {
4833 rb_raise(rb_eIOError, "too long character");
4834 }
4835 }
4836 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4837 clear_readconv(fptr);
4838 if (!MBCLEN_CHARFOUND_P(r)) {
4839 enc = fptr->encs.enc;
4840 goto invalid;
4841 }
4842 return io;
4843 }
4844 }
4845 if (MBCLEN_INVALID_P(r)) {
4846 enc = fptr->encs.enc;
4847 goto invalid;
4848 }
4849 n = MBCLEN_CHARFOUND_LEN(r);
4850 if (fptr->encs.enc) {
4851 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4852 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4853 fptr->encs.enc);
4854 }
4855 else {
4856 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4857 }
4858 fptr->cbuf.off += n;
4859 fptr->cbuf.len -= n;
4860 rb_yield(UINT2NUM(c));
4861 rb_io_check_byte_readable(fptr);
4862 }
4863 }
4864 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4865 enc = io_input_encoding(fptr);
4866 while (io_fillbuf(fptr) >= 0) {
4867 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4868 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4869 if (MBCLEN_CHARFOUND_P(r) &&
4870 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4871 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4872 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4873 fptr->rbuf.off += n;
4874 fptr->rbuf.len -= n;
4875 rb_yield(UINT2NUM(c));
4876 }
4877 else if (MBCLEN_INVALID_P(r)) {
4878 goto invalid;
4879 }
4880 else if (MBCLEN_NEEDMORE_P(r)) {
4881 char cbuf[8], *p = cbuf;
4882 int more = MBCLEN_NEEDMORE_LEN(r);
4883 if (more > numberof(cbuf)) goto invalid;
4884 more += n = fptr->rbuf.len;
4885 if (more > numberof(cbuf)) goto invalid;
4886 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4887 (p += n, (more -= n) > 0)) {
4888 if (io_fillbuf(fptr) < 0) goto invalid;
4889 if ((n = fptr->rbuf.len) > more) n = more;
4890 }
4891 r = rb_enc_precise_mbclen(cbuf, p, enc);
4892 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4893 c = rb_enc_codepoint(cbuf, p, enc);
4894 rb_yield(UINT2NUM(c));
4895 }
4896 else {
4897 continue;
4898 }
4899 rb_io_check_byte_readable(fptr);
4900 }
4901 return io;
4902
4903 invalid:
4904 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4905 UNREACHABLE_RETURN(Qundef);
4906}
4907
4908/*
4909 * call-seq:
4910 * getc -> character or nil
4911 *
4912 * Reads and returns the next 1-character string from the stream;
4913 * returns +nil+ if already at end-of-stream.
4914 * See {Character IO}[rdoc-ref:IO@Character+IO].
4915 *
4916 * f = File.open('t.txt')
4917 * f.getc # => "F"
4918 * f.close
4919 * f = File.open('t.rus')
4920 * f.getc.ord # => 1090
4921 * f.close
4922 *
4923 * Related: IO#readchar (may raise EOFError).
4924 *
4925 */
4926
4927static VALUE
4928rb_io_getc(VALUE io)
4929{
4930 rb_io_t *fptr;
4931 rb_encoding *enc;
4932
4933 GetOpenFile(io, fptr);
4934 rb_io_check_char_readable(fptr);
4935
4936 enc = io_input_encoding(fptr);
4937 READ_CHECK(fptr);
4938 return io_getc(fptr, enc);
4939}
4940
4941/*
4942 * call-seq:
4943 * readchar -> string
4944 *
4945 * Reads and returns the next 1-character string from the stream;
4946 * raises EOFError if already at end-of-stream.
4947 * See {Character IO}[rdoc-ref:IO@Character+IO].
4948 *
4949 * f = File.open('t.txt')
4950 * f.readchar # => "F"
4951 * f.close
4952 * f = File.open('t.rus')
4953 * f.readchar.ord # => 1090
4954 * f.close
4955 *
4956 * Related: IO#getc (will not raise EOFError).
4957 *
4958 */
4959
4960static VALUE
4961rb_io_readchar(VALUE io)
4962{
4963 VALUE c = rb_io_getc(io);
4964
4965 if (NIL_P(c)) {
4966 rb_eof_error();
4967 }
4968 return c;
4969}
4970
4971/*
4972 * call-seq:
4973 * getbyte -> integer or nil
4974 *
4975 * Reads and returns the next byte (in range 0..255) from the stream;
4976 * returns +nil+ if already at end-of-stream.
4977 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4978 *
4979 * f = File.open('t.txt')
4980 * f.getbyte # => 70
4981 * f.close
4982 * f = File.open('t.rus')
4983 * f.getbyte # => 209
4984 * f.close
4985 *
4986 * Related: IO#readbyte (may raise EOFError).
4987 */
4988
4989 VALUE
4990rb_io_getbyte(VALUE io)
4991{
4992 rb_io_t *fptr;
4993 int c;
4994
4995 GetOpenFile(io, fptr);
4996 rb_io_check_byte_readable(fptr);
4997 READ_CHECK(fptr);
4998 VALUE r_stdout = rb_ractor_stdout();
4999 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5000 rb_io_t *ofp;
5001 GetOpenFile(r_stdout, ofp);
5002 if (ofp->mode & FMODE_TTY) {
5003 rb_io_flush(r_stdout);
5004 }
5005 }
5006 if (io_fillbuf(fptr) < 0) {
5007 return Qnil;
5008 }
5009 fptr->rbuf.off++;
5010 fptr->rbuf.len--;
5011 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5012 return INT2FIX(c & 0xff);
5013}
5014
5015/*
5016 * call-seq:
5017 * readbyte -> integer
5018 *
5019 * Reads and returns the next byte (in range 0..255) from the stream;
5020 * raises EOFError if already at end-of-stream.
5021 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5022 *
5023 * f = File.open('t.txt')
5024 * f.readbyte # => 70
5025 * f.close
5026 * f = File.open('t.rus')
5027 * f.readbyte # => 209
5028 * f.close
5029 *
5030 * Related: IO#getbyte (will not raise EOFError).
5031 *
5032 */
5033
5034static VALUE
5035rb_io_readbyte(VALUE io)
5036{
5037 VALUE c = rb_io_getbyte(io);
5038
5039 if (NIL_P(c)) {
5040 rb_eof_error();
5041 }
5042 return c;
5043}
5044
5045/*
5046 * call-seq:
5047 * ungetbyte(integer) -> nil
5048 * ungetbyte(string) -> nil
5049 *
5050 * Pushes back ("unshifts") the given data onto the stream's buffer,
5051 * placing the data so that it is next to be read; returns +nil+.
5052 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5053 *
5054 * Note that:
5055 *
5056 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5057 * - Calling #rewind on the stream discards the pushed-back data.
5058 *
5059 * When argument +integer+ is given, uses only its low-order byte:
5060 *
5061 * File.write('t.tmp', '012')
5062 * f = File.open('t.tmp')
5063 * f.ungetbyte(0x41) # => nil
5064 * f.read # => "A012"
5065 * f.rewind
5066 * f.ungetbyte(0x4243) # => nil
5067 * f.read # => "C012"
5068 * f.close
5069 *
5070 * When argument +string+ is given, uses all bytes:
5071 *
5072 * File.write('t.tmp', '012')
5073 * f = File.open('t.tmp')
5074 * f.ungetbyte('A') # => nil
5075 * f.read # => "A012"
5076 * f.rewind
5077 * f.ungetbyte('BCDE') # => nil
5078 * f.read # => "BCDE012"
5079 * f.close
5080 *
5081 */
5082
5083 VALUE
5084rb_io_ungetbyte(VALUE io, VALUE b)
5085{
5086 rb_io_t *fptr;
5087
5088 GetOpenFile(io, fptr);
5089 rb_io_check_byte_readable(fptr);
5090 switch (TYPE(b)) {
5091 case T_NIL:
5092 return Qnil;
5093 case T_FIXNUM:
5094 case T_BIGNUM: ;
5095 VALUE v = rb_int_modulo(b, INT2FIX(256));
5096 unsigned char c = NUM2INT(v) & 0xFF;
5097 b = rb_str_new((const char *)&c, 1);
5098 break;
5099 default:
5100 SafeStringValue(b);
5101 }
5102 io_ungetbyte(b, fptr);
5103 return Qnil;
5104}
5105
5106/*
5107 * call-seq:
5108 * ungetc(integer) -> nil
5109 * ungetc(string) -> nil
5110 *
5111 * Pushes back ("unshifts") the given data onto the stream's buffer,
5112 * placing the data so that it is next to be read; returns +nil+.
5113 * See {Character IO}[rdoc-ref:IO@Character+IO].
5114 *
5115 * Note that:
5116 *
5117 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5118 * - Calling #rewind on the stream discards the pushed-back data.
5119 *
5120 * When argument +integer+ is given, interprets the integer as a character:
5121 *
5122 * File.write('t.tmp', '012')
5123 * f = File.open('t.tmp')
5124 * f.ungetc(0x41) # => nil
5125 * f.read # => "A012"
5126 * f.rewind
5127 * f.ungetc(0x0442) # => nil
5128 * f.getc.ord # => 1090
5129 * f.close
5130 *
5131 * When argument +string+ is given, uses all characters:
5132 *
5133 * File.write('t.tmp', '012')
5134 * f = File.open('t.tmp')
5135 * f.ungetc('A') # => nil
5136 * f.read # => "A012"
5137 * f.rewind
5138 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5139 * f.getc.ord # => 1090
5140 * f.getc.ord # => 1077
5141 * f.getc.ord # => 1089
5142 * f.getc.ord # => 1090
5143 * f.close
5144 *
5145 */
5146
5147 VALUE
5148rb_io_ungetc(VALUE io, VALUE c)
5149{
5150 rb_io_t *fptr;
5151 long len;
5152
5153 GetOpenFile(io, fptr);
5154 rb_io_check_char_readable(fptr);
5155 if (FIXNUM_P(c)) {
5156 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5157 }
5158 else if (RB_BIGNUM_TYPE_P(c)) {
5159 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5160 }
5161 else {
5162 SafeStringValue(c);
5163 }
5164 if (NEED_READCONV(fptr)) {
5165 SET_BINARY_MODE(fptr);
5166 len = RSTRING_LEN(c);
5167#if SIZEOF_LONG > SIZEOF_INT
5168 if (len > INT_MAX)
5169 rb_raise(rb_eIOError, "ungetc failed");
5170#endif
5171 make_readconv(fptr, (int)len);
5172 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5173 rb_raise(rb_eIOError, "ungetc failed");
5174 if (fptr->cbuf.off < len) {
5175 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5176 fptr->cbuf.ptr+fptr->cbuf.off,
5177 char, fptr->cbuf.len);
5178 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5179 }
5180 fptr->cbuf.off -= (int)len;
5181 fptr->cbuf.len += (int)len;
5182 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5183 }
5184 else {
5185 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5186 io_ungetbyte(c, fptr);
5187 }
5188 return Qnil;
5189}
5190
5191/*
5192 * call-seq:
5193 * isatty -> true or false
5194 *
5195 * Returns +true+ if the stream is associated with a terminal device (tty),
5196 * +false+ otherwise:
5197 *
5198 * f = File.new('t.txt').isatty #=> false
5199 * f.close
5200 * f = File.new('/dev/tty').isatty #=> true
5201 * f.close
5202 *
5203 * IO#tty? is an alias for IO#isatty.
5204 *
5205 */
5206
5207static VALUE
5208rb_io_isatty(VALUE io)
5209{
5210 rb_io_t *fptr;
5211
5212 GetOpenFile(io, fptr);
5213 return RBOOL(isatty(fptr->fd) != 0);
5214}
5215
5216#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5217/*
5218 * call-seq:
5219 * close_on_exec? -> true or false
5220 *
5221 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5222 *
5223 * f = File.open('t.txt')
5224 * f.close_on_exec? # => true
5225 * f.close_on_exec = false
5226 * f.close_on_exec? # => false
5227 * f.close
5228 *
5229 */
5230
5231static VALUE
5232rb_io_close_on_exec_p(VALUE io)
5233{
5234 rb_io_t *fptr;
5235 VALUE write_io;
5236 int fd, ret;
5237
5238 write_io = GetWriteIO(io);
5239 if (io != write_io) {
5240 GetOpenFile(write_io, fptr);
5241 if (fptr && 0 <= (fd = fptr->fd)) {
5242 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5243 if (!(ret & FD_CLOEXEC)) return Qfalse;
5244 }
5245 }
5246
5247 GetOpenFile(io, fptr);
5248 if (fptr && 0 <= (fd = fptr->fd)) {
5249 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5250 if (!(ret & FD_CLOEXEC)) return Qfalse;
5251 }
5252 return Qtrue;
5253}
5254#else
5255#define rb_io_close_on_exec_p rb_f_notimplement
5256#endif
5257
5258#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5259/*
5260 * call-seq:
5261 * self.close_on_exec = bool -> true or false
5262 *
5263 * Sets a close-on-exec flag.
5264 *
5265 * f = open("/dev/null")
5266 * f.close_on_exec = true
5267 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5268 * f.closed? #=> false
5269 *
5270 * Ruby sets close-on-exec flags of all file descriptors by default
5271 * since Ruby 2.0.0.
5272 * So you don't need to set by yourself.
5273 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5274 * if another thread use fork() and exec() (via system() method for example).
5275 * If you really needs file descriptor inheritance to child process,
5276 * use spawn()'s argument such as fd=>fd.
5277 */
5278
5279static VALUE
5280rb_io_set_close_on_exec(VALUE io, VALUE arg)
5281{
5282 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5283 rb_io_t *fptr;
5284 VALUE write_io;
5285 int fd, ret;
5286
5287 write_io = GetWriteIO(io);
5288 if (io != write_io) {
5289 GetOpenFile(write_io, fptr);
5290 if (fptr && 0 <= (fd = fptr->fd)) {
5291 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5292 if ((ret & FD_CLOEXEC) != flag) {
5293 ret = (ret & ~FD_CLOEXEC) | flag;
5294 ret = fcntl(fd, F_SETFD, ret);
5295 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5296 }
5297 }
5298
5299 }
5300
5301 GetOpenFile(io, fptr);
5302 if (fptr && 0 <= (fd = fptr->fd)) {
5303 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5304 if ((ret & FD_CLOEXEC) != flag) {
5305 ret = (ret & ~FD_CLOEXEC) | flag;
5306 ret = fcntl(fd, F_SETFD, ret);
5307 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5308 }
5309 }
5310 return Qnil;
5311}
5312#else
5313#define rb_io_set_close_on_exec rb_f_notimplement
5314#endif
5315
5316#define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
5317#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5318
5319static VALUE
5320finish_writeconv(rb_io_t *fptr, int noalloc)
5321{
5322 unsigned char *ds, *dp, *de;
5323 rb_econv_result_t res;
5324
5325 if (!fptr->wbuf.ptr) {
5326 unsigned char buf[1024];
5327
5328 res = econv_destination_buffer_full;
5329 while (res == econv_destination_buffer_full) {
5330 ds = dp = buf;
5331 de = buf + sizeof(buf);
5332 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5333 while (dp-ds) {
5334 size_t remaining = dp-ds;
5335 long result = rb_io_write_memory(fptr, ds, remaining);
5336
5337 if (result > 0) {
5338 ds += result;
5339 if ((size_t)result == remaining) break;
5340 }
5341 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5342 if (fptr->fd < 0)
5343 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5344 }
5345 else {
5346 return noalloc ? Qtrue : INT2NUM(errno);
5347 }
5348 }
5349 if (res == econv_invalid_byte_sequence ||
5350 res == econv_incomplete_input ||
5351 res == econv_undefined_conversion) {
5352 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5353 }
5354 }
5355
5356 return Qnil;
5357 }
5358
5359 res = econv_destination_buffer_full;
5360 while (res == econv_destination_buffer_full) {
5361 if (fptr->wbuf.len == fptr->wbuf.capa) {
5362 if (io_fflush(fptr) < 0) {
5363 return noalloc ? Qtrue : INT2NUM(errno);
5364 }
5365 }
5366
5367 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5368 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5369 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5370 fptr->wbuf.len += (int)(dp - ds);
5371 if (res == econv_invalid_byte_sequence ||
5372 res == econv_incomplete_input ||
5373 res == econv_undefined_conversion) {
5374 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5375 }
5376 }
5377 return Qnil;
5378}
5379
5380 struct finish_writeconv_arg {
5381 rb_io_t *fptr;
5382 int noalloc;
5383};
5384
5385static VALUE
5386finish_writeconv_sync(VALUE arg)
5387{
5388 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5389 return finish_writeconv(p->fptr, p->noalloc);
5390}
5391
5392static void*
5393nogvl_close(void *ptr)
5394{
5395 int *fd = ptr;
5396
5397 return (void*)(intptr_t)close(*fd);
5398}
5399
5400static int
5401maygvl_close(int fd, int keepgvl)
5402{
5403 if (keepgvl)
5404 return close(fd);
5405
5406 /*
5407 * close() may block for certain file types (NFS, SO_LINGER sockets,
5408 * inotify), so let other threads run.
5409 */
5410 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
5411}
5412
5413static void*
5414nogvl_fclose(void *ptr)
5415{
5416 FILE *file = ptr;
5417
5418 return (void*)(intptr_t)fclose(file);
5419}
5420
5421static int
5422maygvl_fclose(FILE *file, int keepgvl)
5423{
5424 if (keepgvl)
5425 return fclose(file);
5426
5427 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
5428}
5429
5430static void free_io_buffer(rb_io_buffer_t *buf);
5431static void clear_codeconv(rb_io_t *fptr);
5432
5433static void
5434fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5435 struct ccan_list_head *busy)
5436{
5437 VALUE error = Qnil;
5438 int fd = fptr->fd;
5439 FILE *stdio_file = fptr->stdio_file;
5440 int mode = fptr->mode;
5441
5442 if (fptr->writeconv) {
5443 if (!NIL_P(fptr->write_lock) && !noraise) {
5444 struct finish_writeconv_arg arg;
5445 arg.fptr = fptr;
5446 arg.noalloc = noraise;
5447 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5448 }
5449 else {
5450 error = finish_writeconv(fptr, noraise);
5451 }
5452 }
5453 if (fptr->wbuf.len) {
5454 if (noraise) {
5455 io_flush_buffer_sync(fptr);
5456 }
5457 else {
5458 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5459 error = INT2NUM(errno);
5460 }
5461 }
5462 }
5463
5464 int done = 0;
5465
5466 if (IS_PREP_STDIO(fptr) || fd <= 2) {
5467 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5468 done = 1;
5469 }
5470
5471 fptr->fd = -1;
5472 fptr->stdio_file = 0;
5473 fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
5474
5475 // Ensure waiting_fd users do not hit EBADF.
5476 if (busy) {
5477 // Wait for them to exit before we call close().
5478 do rb_thread_schedule(); while (!ccan_list_empty(busy));
5479 }
5480
5481 // Disable for now.
5482 // if (!done && fd >= 0) {
5483 // VALUE scheduler = rb_fiber_scheduler_current();
5484 // if (scheduler != Qnil) {
5485 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5486 // if (!UNDEF_P(result)) done = 1;
5487 // }
5488 // }
5489
5490 if (!done && stdio_file) {
5491 // stdio_file is deallocated anyway even if fclose failed.
5492 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5493 if (!noraise) {
5494 error = INT2NUM(errno);
5495 }
5496 }
5497
5498 done = 1;
5499 }
5500
5501 if (!done && fd >= 0) {
5502 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5503 // We assumes it is closed.
5504
5505 keepgvl |= !(mode & FMODE_WRITABLE);
5506 keepgvl |= noraise;
5507 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5508 if (!noraise) {
5509 error = INT2NUM(errno);
5510 }
5511 }
5512
5513 done = 1;
5514 }
5515
5516 if (!NIL_P(error) && !noraise) {
5517 if (RB_INTEGER_TYPE_P(error))
5518 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5519 else
5520 rb_exc_raise(error);
5521 }
5522}
5523
5524static void
5525fptr_finalize(rb_io_t *fptr, int noraise)
5526{
5527 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5528 free_io_buffer(&fptr->rbuf);
5529 free_io_buffer(&fptr->wbuf);
5530 clear_codeconv(fptr);
5531}
5532
5533static void
5534rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5535{
5536 if (fptr->finalize) {
5537 (*fptr->finalize)(fptr, noraise);
5538 }
5539 else {
5540 fptr_finalize(fptr, noraise);
5541 }
5542}
5543
5544static void
5545free_io_buffer(rb_io_buffer_t *buf)
5546{
5547 if (buf->ptr) {
5548 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5549 buf->ptr = NULL;
5550 }
5551}
5552
5553static void
5554clear_readconv(rb_io_t *fptr)
5555{
5556 if (fptr->readconv) {
5557 rb_econv_close(fptr->readconv);
5558 fptr->readconv = NULL;
5559 }
5560 free_io_buffer(&fptr->cbuf);
5561}
5562
5563static void
5564clear_writeconv(rb_io_t *fptr)
5565{
5566 if (fptr->writeconv) {
5567 rb_econv_close(fptr->writeconv);
5568 fptr->writeconv = NULL;
5569 }
5570 fptr->writeconv_initialized = 0;
5571}
5572
5573static void
5574clear_codeconv(rb_io_t *fptr)
5575{
5576 clear_readconv(fptr);
5577 clear_writeconv(fptr);
5578}
5579
5580void
5581rb_io_fptr_finalize_internal(void *ptr)
5582{
5583 rb_io_t *fptr = ptr;
5584
5585 if (!ptr) return;
5586 fptr->pathv = Qnil;
5587 if (0 <= fptr->fd)
5588 rb_io_fptr_cleanup(fptr, TRUE);
5589 fptr->write_lock = Qnil;
5590 free_io_buffer(&fptr->rbuf);
5591 free_io_buffer(&fptr->wbuf);
5592 clear_codeconv(fptr);
5593 free(fptr);
5594}
5595
5596#undef rb_io_fptr_finalize
5597int
5598rb_io_fptr_finalize(rb_io_t *fptr)
5599{
5600 if (!fptr) {
5601 return 0;
5602 }
5603 else {
5604 rb_io_fptr_finalize_internal(fptr);
5605 return 1;
5606 }
5607}
5608#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5609
5610RUBY_FUNC_EXPORTED size_t
5611rb_io_memsize(const rb_io_t *fptr)
5612{
5613 size_t size = sizeof(rb_io_t);
5614 size += fptr->rbuf.capa;
5615 size += fptr->wbuf.capa;
5616 size += fptr->cbuf.capa;
5617 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5618 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5619 return size;
5620}
5621
5622#ifdef _WIN32
5623/* keep GVL while closing to prevent crash on Windows */
5624# define KEEPGVL TRUE
5625#else
5626# define KEEPGVL FALSE
5627#endif
5628
5629int rb_notify_fd_close(int fd, struct ccan_list_head *);
5630static rb_io_t *
5631io_close_fptr(VALUE io)
5632{
5633 rb_io_t *fptr;
5634 VALUE write_io;
5635 rb_io_t *write_fptr;
5636 struct ccan_list_head busy;
5637
5638 ccan_list_head_init(&busy);
5639 write_io = GetWriteIO(io);
5640 if (io != write_io) {
5641 write_fptr = RFILE(write_io)->fptr;
5642 if (write_fptr && 0 <= write_fptr->fd) {
5643 rb_io_fptr_cleanup(write_fptr, TRUE);
5644 }
5645 }
5646
5647 fptr = RFILE(io)->fptr;
5648 if (!fptr) return 0;
5649 if (fptr->fd < 0) return 0;
5650
5651 if (rb_notify_fd_close(fptr->fd, &busy)) {
5652 /* calls close(fptr->fd): */
5653 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5654 }
5655 rb_io_fptr_cleanup(fptr, FALSE);
5656 return fptr;
5657}
5658
5659static void
5660fptr_waitpid(rb_io_t *fptr, int nohang)
5661{
5662 int status;
5663 if (fptr->pid) {
5664 rb_last_status_clear();
5665 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5666 fptr->pid = 0;
5667 }
5668}
5669
5670 VALUE
5671rb_io_close(VALUE io)
5672{
5673 rb_io_t *fptr = io_close_fptr(io);
5674 if (fptr) fptr_waitpid(fptr, 0);
5675 return Qnil;
5676}
5677
5678/*
5679 * call-seq:
5680 * close -> nil
5681 *
5682 * Closes the stream for both reading and writing
5683 * if open for either or both; returns +nil+.
5684 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5685 *
5686 * If the stream is open for writing, flushes any buffered writes
5687 * to the operating system before closing.
5688 *
5689 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5690 * (child exit status).
5691 *
5692 * Example:
5693 *
5694 * IO.popen('ruby', 'r+') do |pipe|
5695 * puts pipe.closed?
5696 * pipe.close
5697 * puts $?
5698 * puts pipe.closed?
5699 * end
5700 *
5701 * Output:
5702 *
5703 * false
5704 * pid 13760 exit 0
5705 * true
5706 *
5707 * Related: IO#close_read, IO#close_write, IO#closed?.
5708 */
5709
5710static VALUE
5711rb_io_close_m(VALUE io)
5712{
5713 rb_io_t *fptr = rb_io_get_fptr(io);
5714 if (fptr->fd < 0) {
5715 return Qnil;
5716 }
5717 rb_io_close(io);
5718 return Qnil;
5719}
5720
5721static VALUE
5722io_call_close(VALUE io)
5723{
5724 rb_check_funcall(io, rb_intern("close"), 0, 0);
5725 return io;
5726}
5727
5728static VALUE
5729ignore_closed_stream(VALUE io, VALUE exc)
5730{
5731 enum {mesg_len = sizeof(closed_stream)-1};
5732 VALUE mesg = rb_attr_get(exc, idMesg);
5733 if (!RB_TYPE_P(mesg, T_STRING) ||
5734 RSTRING_LEN(mesg) != mesg_len ||
5735 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5736 rb_exc_raise(exc);
5737 }
5738 return io;
5739}
5740
5741static VALUE
5742io_close(VALUE io)
5743{
5744 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5745 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5746 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5747 rb_eIOError, (VALUE)0);
5748 return io;
5749}
5750
5751/*
5752 * call-seq:
5753 * closed? -> true or false
5754 *
5755 * Returns +true+ if the stream is closed for both reading and writing,
5756 * +false+ otherwise.
5757 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5758 *
5759 * IO.popen('ruby', 'r+') do |pipe|
5760 * puts pipe.closed?
5761 * pipe.close_read
5762 * puts pipe.closed?
5763 * pipe.close_write
5764 * puts pipe.closed?
5765 * end
5766 *
5767 * Output:
5768 *
5769 * false
5770 * false
5771 * true
5772 *
5773 * Related: IO#close_read, IO#close_write, IO#close.
5774 */
5775
5776
5777static VALUE
5778rb_io_closed(VALUE io)
5779{
5780 rb_io_t *fptr;
5781 VALUE write_io;
5782 rb_io_t *write_fptr;
5783
5784 write_io = GetWriteIO(io);
5785 if (io != write_io) {
5786 write_fptr = RFILE(write_io)->fptr;
5787 if (write_fptr && 0 <= write_fptr->fd) {
5788 return Qfalse;
5789 }
5790 }
5791
5792 fptr = rb_io_get_fptr(io);
5793 return RBOOL(0 > fptr->fd);
5794}
5795
5796/*
5797 * call-seq:
5798 * close_read -> nil
5799 *
5800 * Closes the stream for reading if open for reading;
5801 * returns +nil+.
5802 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5803 *
5804 * If the stream was opened by IO.popen and is also closed for writing,
5805 * sets global variable <tt>$?</tt> (child exit status).
5806 *
5807 * Example:
5808 *
5809 * IO.popen('ruby', 'r+') do |pipe|
5810 * puts pipe.closed?
5811 * pipe.close_write
5812 * puts pipe.closed?
5813 * pipe.close_read
5814 * puts $?
5815 * puts pipe.closed?
5816 * end
5817 *
5818 * Output:
5819 *
5820 * false
5821 * false
5822 * pid 14748 exit 0
5823 * true
5824 *
5825 * Related: IO#close, IO#close_write, IO#closed?.
5826 */
5827
5828static VALUE
5829rb_io_close_read(VALUE io)
5830{
5831 rb_io_t *fptr;
5832 VALUE write_io;
5833
5834 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5835 if (fptr->fd < 0) return Qnil;
5836 if (is_socket(fptr->fd, fptr->pathv)) {
5837#ifndef SHUT_RD
5838# define SHUT_RD 0
5839#endif
5840 if (shutdown(fptr->fd, SHUT_RD) < 0)
5841 rb_sys_fail_path(fptr->pathv);
5842 fptr->mode &= ~FMODE_READABLE;
5843 if (!(fptr->mode & FMODE_WRITABLE))
5844 return rb_io_close(io);
5845 return Qnil;
5846 }
5847
5848 write_io = GetWriteIO(io);
5849 if (io != write_io) {
5850 rb_io_t *wfptr;
5851 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5852 wfptr->pid = fptr->pid;
5853 fptr->pid = 0;
5854 RFILE(io)->fptr = wfptr;
5855 /* bind to write_io temporarily to get rid of memory/fd leak */
5856 fptr->tied_io_for_writing = 0;
5857 RFILE(write_io)->fptr = fptr;
5858 rb_io_fptr_cleanup(fptr, FALSE);
5859 /* should not finalize fptr because another thread may be reading it */
5860 return Qnil;
5861 }
5862
5863 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5864 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5865 }
5866 return rb_io_close(io);
5867}
5868
5869/*
5870 * call-seq:
5871 * close_write -> nil
5872 *
5873 * Closes the stream for writing if open for writing;
5874 * returns +nil+.
5875 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5876 *
5877 * Flushes any buffered writes to the operating system before closing.
5878 *
5879 * If the stream was opened by IO.popen and is also closed for reading,
5880 * sets global variable <tt>$?</tt> (child exit status).
5881 *
5882 * IO.popen('ruby', 'r+') do |pipe|
5883 * puts pipe.closed?
5884 * pipe.close_read
5885 * puts pipe.closed?
5886 * pipe.close_write
5887 * puts $?
5888 * puts pipe.closed?
5889 * end
5890 *
5891 * Output:
5892 *
5893 * false
5894 * false
5895 * pid 15044 exit 0
5896 * true
5897 *
5898 * Related: IO#close, IO#close_read, IO#closed?.
5899 */
5900
5901static VALUE
5902rb_io_close_write(VALUE io)
5903{
5904 rb_io_t *fptr;
5905 VALUE write_io;
5906
5907 write_io = GetWriteIO(io);
5908 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5909 if (fptr->fd < 0) return Qnil;
5910 if (is_socket(fptr->fd, fptr->pathv)) {
5911#ifndef SHUT_WR
5912# define SHUT_WR 1
5913#endif
5914 if (shutdown(fptr->fd, SHUT_WR) < 0)
5915 rb_sys_fail_path(fptr->pathv);
5916 fptr->mode &= ~FMODE_WRITABLE;
5917 if (!(fptr->mode & FMODE_READABLE))
5918 return rb_io_close(write_io);
5919 return Qnil;
5920 }
5921
5922 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
5923 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
5924 }
5925
5926 if (io != write_io) {
5927 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5928 fptr->tied_io_for_writing = 0;
5929 }
5930 rb_io_close(write_io);
5931 return Qnil;
5932}
5933
5934/*
5935 * call-seq:
5936 * sysseek(offset, whence = IO::SEEK_SET) -> integer
5937 *
5938 * Behaves like IO#seek, except that it:
5939 *
5940 * - Uses low-level system functions.
5941 * - Returns the new position.
5942 *
5943 */
5944
5945static VALUE
5946rb_io_sysseek(int argc, VALUE *argv, VALUE io)
5947{
5948 VALUE offset, ptrname;
5949 int whence = SEEK_SET;
5950 rb_io_t *fptr;
5951 rb_off_t pos;
5952
5953 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
5954 whence = interpret_seek_whence(ptrname);
5955 }
5956 pos = NUM2OFFT(offset);
5957 GetOpenFile(io, fptr);
5958 if ((fptr->mode & FMODE_READABLE) &&
5959 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5960 rb_raise(rb_eIOError, "sysseek for buffered IO");
5961 }
5962 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
5963 rb_warn("sysseek for buffered IO");
5964 }
5965 errno = 0;
5966 pos = lseek(fptr->fd, pos, whence);
5967 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
5968
5969 return OFFT2NUM(pos);
5970}
5971
5972/*
5973 * call-seq:
5974 * syswrite(object) -> integer
5975 *
5976 * Writes the given +object+ to self, which must be opened for writing (see Modes);
5977 * returns the number bytes written.
5978 * If +object+ is not a string is converted via method to_s:
5979 *
5980 * f = File.new('t.tmp', 'w')
5981 * f.syswrite('foo') # => 3
5982 * f.syswrite(30) # => 2
5983 * f.syswrite(:foo) # => 3
5984 * f.close
5985 *
5986 * This methods should not be used with other stream-writer methods.
5987 *
5988 */
5989
5990static VALUE
5991rb_io_syswrite(VALUE io, VALUE str)
5992{
5993 VALUE tmp;
5994 rb_io_t *fptr;
5995 long n, len;
5996 const char *ptr;
5997
5998 if (!RB_TYPE_P(str, T_STRING))
5999 str = rb_obj_as_string(str);
6000
6001 io = GetWriteIO(io);
6002 GetOpenFile(io, fptr);
6003 rb_io_check_writable(fptr);
6004
6005 if (fptr->wbuf.len) {
6006 rb_warn("syswrite for buffered IO");
6007 }
6008
6009 tmp = rb_str_tmp_frozen_acquire(str);
6010 RSTRING_GETMEM(tmp, ptr, len);
6011 n = rb_io_write_memory(fptr, ptr, len);
6012 if (n < 0) rb_sys_fail_path(fptr->pathv);
6013 rb_str_tmp_frozen_release(str, tmp);
6014
6015 return LONG2FIX(n);
6016}
6017
6018/*
6019 * call-seq:
6020 * sysread(maxlen) -> string
6021 * sysread(maxlen, out_string) -> string
6022 *
6023 * Behaves like IO#readpartial, except that it uses low-level system functions.
6024 *
6025 * This method should not be used with other stream-reader methods.
6026 *
6027 */
6028
6029static VALUE
6030rb_io_sysread(int argc, VALUE *argv, VALUE io)
6031{
6032 VALUE len, str;
6033 rb_io_t *fptr;
6034 long n, ilen;
6035 struct io_internal_read_struct iis;
6036 int shrinkable;
6037
6038 rb_scan_args(argc, argv, "11", &len, &str);
6039 ilen = NUM2LONG(len);
6040
6041 shrinkable = io_setstrbuf(&str, ilen);
6042 if (ilen == 0) return str;
6043
6044 GetOpenFile(io, fptr);
6045 rb_io_check_byte_readable(fptr);
6046
6047 if (READ_DATA_BUFFERED(fptr)) {
6048 rb_raise(rb_eIOError, "sysread for buffered IO");
6049 }
6050
6051 rb_io_check_closed(fptr);
6052
6053 io_setstrbuf(&str, ilen);
6054 iis.th = rb_thread_current();
6055 iis.fptr = fptr;
6056 iis.nonblock = 0;
6057 iis.fd = fptr->fd;
6058 iis.buf = RSTRING_PTR(str);
6059 iis.capa = ilen;
6060 iis.timeout = NULL;
6061 n = io_read_memory_locktmp(str, &iis);
6062
6063 if (n < 0) {
6064 rb_sys_fail_path(fptr->pathv);
6065 }
6066
6067 io_set_read_length(str, n, shrinkable);
6068
6069 if (n == 0 && ilen > 0) {
6070 rb_eof_error();
6071 }
6072
6073 return str;
6074}
6075
6076#if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
6077struct prdwr_internal_arg {
6078 int fd;
6079 void *buf;
6080 size_t count;
6081 rb_off_t offset;
6082};
6083#endif /* HAVE_PREAD || HAVE_PWRITE */
6084
6085#if defined(HAVE_PREAD)
6086static VALUE
6087internal_pread_func(void *arg)
6088{
6089 struct prdwr_internal_arg *p = arg;
6090 return (VALUE)pread(p->fd, p->buf, p->count, p->offset);
6091}
6092
6093static VALUE
6094pread_internal_call(VALUE arg)
6095{
6096 struct prdwr_internal_arg *p = (struct prdwr_internal_arg *)arg;
6097 return rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
6098}
6099
6100/*
6101 * call-seq:
6102 * pread(maxlen, offset) -> string
6103 * pread(maxlen, offset, out_string) -> string
6104 *
6105 * Behaves like IO#readpartial, except that it:
6106 *
6107 * - Reads at the given +offset+ (in bytes).
6108 * - Disregards, and does not modify, the stream's position
6109 * (see {Position}[rdoc-ref:IO@Position]).
6110 * - Bypasses any user space buffering in the stream.
6111 *
6112 * Because this method does not disturb the stream's state
6113 * (its position, in particular), +pread+ allows multiple threads and processes
6114 * to use the same \IO object for reading at various offsets.
6115 *
6116 * f = File.open('t.txt')
6117 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6118 * f.pos # => 52
6119 * # Read 12 bytes at offset 0.
6120 * f.pread(12, 0) # => "First line\n"
6121 * # Read 9 bytes at offset 8.
6122 * f.pread(9, 8) # => "ne\nSecon"
6123 * f.close
6124 *
6125 * Not available on some platforms.
6126 *
6127 */
6128static VALUE
6129rb_io_pread(int argc, VALUE *argv, VALUE io)
6130{
6131 VALUE len, offset, str;
6132 rb_io_t *fptr;
6133 ssize_t n;
6134 struct prdwr_internal_arg arg;
6135 int shrinkable;
6136
6137 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6138 arg.count = NUM2SIZET(len);
6139 arg.offset = NUM2OFFT(offset);
6140
6141 shrinkable = io_setstrbuf(&str, (long)arg.count);
6142 if (arg.count == 0) return str;
6143 arg.buf = RSTRING_PTR(str);
6144
6145 GetOpenFile(io, fptr);
6146 rb_io_check_byte_readable(fptr);
6147
6148 arg.fd = fptr->fd;
6149 rb_io_check_closed(fptr);
6150
6151 rb_str_locktmp(str);
6152 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6153
6154 if (n < 0) {
6155 rb_sys_fail_path(fptr->pathv);
6156 }
6157 io_set_read_length(str, n, shrinkable);
6158 if (n == 0 && arg.count > 0) {
6159 rb_eof_error();
6160 }
6161
6162 return str;
6163}
6164#else
6165# define rb_io_pread rb_f_notimplement
6166#endif /* HAVE_PREAD */
6167
6168#if defined(HAVE_PWRITE)
6169static VALUE
6170internal_pwrite_func(void *ptr)
6171{
6172 struct prdwr_internal_arg *arg = ptr;
6173
6174 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6175}
6176
6177/*
6178 * call-seq:
6179 * pwrite(object, offset) -> integer
6180 *
6181 * Behaves like IO#write, except that it:
6182 *
6183 * - Writes at the given +offset+ (in bytes).
6184 * - Disregards, and does not modify, the stream's position
6185 * (see {Position}[rdoc-ref:IO@Position]).
6186 * - Bypasses any user space buffering in the stream.
6187 *
6188 * Because this method does not disturb the stream's state
6189 * (its position, in particular), +pwrite+ allows multiple threads and processes
6190 * to use the same \IO object for writing at various offsets.
6191 *
6192 * f = File.open('t.tmp', 'w+')
6193 * # Write 6 bytes at offset 3.
6194 * f.pwrite('ABCDEF', 3) # => 6
6195 * f.rewind
6196 * f.read # => "\u0000\u0000\u0000ABCDEF"
6197 * f.close
6198 *
6199 * Not available on some platforms.
6200 *
6201 */
6202static VALUE
6203rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6204{
6205 rb_io_t *fptr;
6206 ssize_t n;
6207 struct prdwr_internal_arg arg;
6208 VALUE tmp;
6209
6210 if (!RB_TYPE_P(str, T_STRING))
6211 str = rb_obj_as_string(str);
6212
6213 arg.offset = NUM2OFFT(offset);
6214
6215 io = GetWriteIO(io);
6216 GetOpenFile(io, fptr);
6217 rb_io_check_writable(fptr);
6218 arg.fd = fptr->fd;
6219
6220 tmp = rb_str_tmp_frozen_acquire(str);
6221 arg.buf = RSTRING_PTR(tmp);
6222 arg.count = (size_t)RSTRING_LEN(tmp);
6223
6224 n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
6225 if (n < 0) rb_sys_fail_path(fptr->pathv);
6226 rb_str_tmp_frozen_release(str, tmp);
6227
6228 return SSIZET2NUM(n);
6229}
6230#else
6231# define rb_io_pwrite rb_f_notimplement
6232#endif /* HAVE_PWRITE */
6233
6234 VALUE
6235rb_io_binmode(VALUE io)
6236{
6237 rb_io_t *fptr;
6238
6239 GetOpenFile(io, fptr);
6240 if (fptr->readconv)
6241 rb_econv_binmode(fptr->readconv);
6242 if (fptr->writeconv)
6243 rb_econv_binmode(fptr->writeconv);
6244 fptr->mode |= FMODE_BINMODE;
6245 fptr->mode &= ~FMODE_TEXTMODE;
6246 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6247#ifdef O_BINARY
6248 if (!fptr->readconv) {
6249 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6250 }
6251 else {
6252 setmode(fptr->fd, O_BINARY);
6253 }
6254#endif
6255 return io;
6256}
6257
6258static void
6259io_ascii8bit_binmode(rb_io_t *fptr)
6260{
6261 if (fptr->readconv) {
6262 rb_econv_close(fptr->readconv);
6263 fptr->readconv = NULL;
6264 }
6265 if (fptr->writeconv) {
6266 rb_econv_close(fptr->writeconv);
6267 fptr->writeconv = NULL;
6268 }
6269 fptr->mode |= FMODE_BINMODE;
6270 fptr->mode &= ~FMODE_TEXTMODE;
6271 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6272
6273 fptr->encs.enc = rb_ascii8bit_encoding();
6274 fptr->encs.enc2 = NULL;
6275 fptr->encs.ecflags = 0;
6276 fptr->encs.ecopts = Qnil;
6277 clear_codeconv(fptr);
6278}
6279
6280 VALUE
6281rb_io_ascii8bit_binmode(VALUE io)
6282{
6283 rb_io_t *fptr;
6284
6285 GetOpenFile(io, fptr);
6286 io_ascii8bit_binmode(fptr);
6287
6288 return io;
6289}
6290
6291/*
6292 * call-seq:
6293 * binmode -> self
6294 *
6295 * Sets the stream's data mode as binary
6296 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6297 *
6298 * A stream's data mode may not be changed from binary to text.
6299 *
6300 */
6301
6302static VALUE
6303rb_io_binmode_m(VALUE io)
6304{
6305 VALUE write_io;
6306
6307 rb_io_ascii8bit_binmode(io);
6308
6309 write_io = GetWriteIO(io);
6310 if (write_io != io)
6311 rb_io_ascii8bit_binmode(write_io);
6312 return io;
6313}
6314
6315/*
6316 * call-seq:
6317 * binmode? -> true or false
6318 *
6319 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6320 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6321 *
6322 */
6323static VALUE
6324rb_io_binmode_p(VALUE io)
6325{
6326 rb_io_t *fptr;
6327 GetOpenFile(io, fptr);
6328 return RBOOL(fptr->mode & FMODE_BINMODE);
6329}
6330
6331static const char*
6332rb_io_fmode_modestr(int fmode)
6333{
6334 if (fmode & FMODE_APPEND) {
6335 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6336 return MODE_BTMODE("a+", "ab+", "at+");
6337 }
6338 return MODE_BTMODE("a", "ab", "at");
6339 }
6340 switch (fmode & FMODE_READWRITE) {
6341 default:
6342 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6343 case FMODE_READABLE:
6344 return MODE_BTMODE("r", "rb", "rt");
6345 case FMODE_WRITABLE:
6346 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6347 case FMODE_READWRITE:
6348 if (fmode & FMODE_CREATE) {
6349 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6350 }
6351 return MODE_BTMODE("r+", "rb+", "rt+");
6352 }
6353}
6354
6355static const char bom_prefix[] = "bom|";
6356static const char utf_prefix[] = "utf-";
6357enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6358enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6359
6360static int
6361io_encname_bom_p(const char *name, long len)
6362{
6363 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6364}
6365
6366int
6367rb_io_modestr_fmode(const char *modestr)
6368{
6369 int fmode = 0;
6370 const char *m = modestr, *p = NULL;
6371
6372 switch (*m++) {
6373 case 'r':
6374 fmode |= FMODE_READABLE;
6375 break;
6376 case 'w':
6377 fmode |= FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE;
6378 break;
6379 case 'a':
6380 fmode |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
6381 break;
6382 default:
6383 goto error;
6384 }
6385
6386 while (*m) {
6387 switch (*m++) {
6388 case 'b':
6389 fmode |= FMODE_BINMODE;
6390 break;
6391 case 't':
6392 fmode |= FMODE_TEXTMODE;
6393 break;
6394 case '+':
6395 fmode |= FMODE_READWRITE;
6396 break;
6397 case 'x':
6398 if (modestr[0] != 'w')
6399 goto error;
6400 fmode |= FMODE_EXCL;
6401 break;
6402 default:
6403 goto error;
6404 case ':':
6405 p = strchr(m, ':');
6406 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6407 fmode |= FMODE_SETENC_BY_BOM;
6408 goto finished;
6409 }
6410 }
6411
6412 finished:
6413 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6414 goto error;
6415
6416 return fmode;
6417
6418 error:
6419 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6420 UNREACHABLE_RETURN(Qundef);
6421}
6422
6423int
6424rb_io_oflags_fmode(int oflags)
6425{
6426 int fmode = 0;
6427
6428 switch (oflags & O_ACCMODE) {
6429 case O_RDONLY:
6430 fmode = FMODE_READABLE;
6431 break;
6432 case O_WRONLY:
6433 fmode = FMODE_WRITABLE;
6434 break;
6435 case O_RDWR:
6436 fmode = FMODE_READWRITE;
6437 break;
6438 }
6439
6440 if (oflags & O_APPEND) {
6441 fmode |= FMODE_APPEND;
6442 }
6443 if (oflags & O_TRUNC) {
6444 fmode |= FMODE_TRUNC;
6445 }
6446 if (oflags & O_CREAT) {
6447 fmode |= FMODE_CREATE;
6448 }
6449 if (oflags & O_EXCL) {
6450 fmode |= FMODE_EXCL;
6451 }
6452#ifdef O_BINARY
6453 if (oflags & O_BINARY) {
6454 fmode |= FMODE_BINMODE;
6455 }
6456#endif
6457
6458 return fmode;
6459}
6460
6461static int
6462rb_io_fmode_oflags(int fmode)
6463{
6464 int oflags = 0;
6465
6466 switch (fmode & FMODE_READWRITE) {
6467 case FMODE_READABLE:
6468 oflags |= O_RDONLY;
6469 break;
6470 case FMODE_WRITABLE:
6471 oflags |= O_WRONLY;
6472 break;
6473 case FMODE_READWRITE:
6474 oflags |= O_RDWR;
6475 break;
6476 }
6477
6478 if (fmode & FMODE_APPEND) {
6479 oflags |= O_APPEND;
6480 }
6481 if (fmode & FMODE_TRUNC) {
6482 oflags |= O_TRUNC;
6483 }
6484 if (fmode & FMODE_CREATE) {
6485 oflags |= O_CREAT;
6486 }
6487 if (fmode & FMODE_EXCL) {
6488 oflags |= O_EXCL;
6489 }
6490#ifdef O_BINARY
6491 if (fmode & FMODE_BINMODE) {
6492 oflags |= O_BINARY;
6493 }
6494#endif
6495
6496 return oflags;
6497}
6498
6499int
6500rb_io_modestr_oflags(const char *modestr)
6501{
6502 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6503}
6504
6505static const char*
6506rb_io_oflags_modestr(int oflags)
6507{
6508#ifdef O_BINARY
6509# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6510#else
6511# define MODE_BINARY(a,b) (a)
6512#endif
6513 int accmode;
6514 if (oflags & O_EXCL) {
6515 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6516 }
6517 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6518 if (oflags & O_APPEND) {
6519 if (accmode == O_WRONLY) {
6520 return MODE_BINARY("a", "ab");
6521 }
6522 if (accmode == O_RDWR) {
6523 return MODE_BINARY("a+", "ab+");
6524 }
6525 }
6526 switch (accmode) {
6527 default:
6528 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6529 case O_RDONLY:
6530 return MODE_BINARY("r", "rb");
6531 case O_WRONLY:
6532 return MODE_BINARY("w", "wb");
6533 case O_RDWR:
6534 if (oflags & O_TRUNC) {
6535 return MODE_BINARY("w+", "wb+");
6536 }
6537 return MODE_BINARY("r+", "rb+");
6538 }
6539}
6540
6541/*
6542 * Convert external/internal encodings to enc/enc2
6543 * NULL => use default encoding
6544 * Qnil => no encoding specified (internal only)
6545 */
6546static void
6547rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6548{
6549 int default_ext = 0;
6550
6551 if (ext == NULL) {
6552 ext = rb_default_external_encoding();
6553 default_ext = 1;
6554 }
6555 if (rb_is_ascii8bit_enc(ext)) {
6556 /* If external is ASCII-8BIT, no transcoding */
6557 intern = NULL;
6558 }
6559 else if (intern == NULL) {
6560 intern = rb_default_internal_encoding();
6561 }
6562 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6563 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6564 /* No internal encoding => use external + no transcoding */
6565 *enc = (default_ext && intern != ext) ? NULL : ext;
6566 *enc2 = NULL;
6567 }
6568 else {
6569 *enc = intern;
6570 *enc2 = ext;
6571 }
6572}
6573
6574static void
6575unsupported_encoding(const char *name, rb_encoding *enc)
6576{
6577 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6578}
6579
6580static void
6581parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6582 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6583{
6584 const char *p;
6585 char encname[ENCODING_MAXNAMELEN+1];
6586 int idx, idx2;
6587 int fmode = fmode_p ? *fmode_p : 0;
6588 rb_encoding *ext_enc, *int_enc;
6589 long len;
6590
6591 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6592
6593 p = strrchr(estr, ':');
6594 len = p ? (p++ - estr) : (long)strlen(estr);
6595 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6596 estr += bom_prefix_len;
6597 len -= bom_prefix_len;
6598 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6599 fmode |= FMODE_SETENC_BY_BOM;
6600 }
6601 else {
6602 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6603 fmode &= ~FMODE_SETENC_BY_BOM;
6604 }
6605 }
6606 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6607 idx = -1;
6608 }
6609 else {
6610 if (p) {
6611 memcpy(encname, estr, len);
6612 encname[len] = '\0';
6613 estr = encname;
6614 }
6615 idx = rb_enc_find_index(estr);
6616 }
6617 if (fmode_p) *fmode_p = fmode;
6618
6619 if (idx >= 0)
6620 ext_enc = rb_enc_from_index(idx);
6621 else {
6622 if (idx != -2)
6623 unsupported_encoding(estr, estr_enc);
6624 ext_enc = NULL;
6625 }
6626
6627 int_enc = NULL;
6628 if (p) {
6629 if (*p == '-' && *(p+1) == '\0') {
6630 /* Special case - "-" => no transcoding */
6631 int_enc = (rb_encoding *)Qnil;
6632 }
6633 else {
6634 idx2 = rb_enc_find_index(p);
6635 if (idx2 < 0)
6636 unsupported_encoding(p, estr_enc);
6637 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6638 int_enc = (rb_encoding *)Qnil;
6639 }
6640 else
6641 int_enc = rb_enc_from_index(idx2);
6642 }
6643 }
6644
6645 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6646}
6647
6648int
6649rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6650{
6651 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6652 int extracted = 0;
6653 rb_encoding *extencoding = NULL;
6654 rb_encoding *intencoding = NULL;
6655
6656 if (!NIL_P(opt)) {
6657 VALUE v;
6658 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6659 if (v != Qnil) encoding = v;
6660 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6661 if (v != Qnil) extenc = v;
6662 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6663 if (!UNDEF_P(v)) intenc = v;
6664 }
6665 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6666 if (!NIL_P(ruby_verbose)) {
6667 int idx = rb_to_encoding_index(encoding);
6668 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6669 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6670 encoding, UNDEF_P(extenc) ? "internal" : "external");
6671 }
6672 encoding = Qnil;
6673 }
6674 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6675 extencoding = rb_to_encoding(extenc);
6676 }
6677 if (!UNDEF_P(intenc)) {
6678 if (NIL_P(intenc)) {
6679 /* internal_encoding: nil => no transcoding */
6680 intencoding = (rb_encoding *)Qnil;
6681 }
6682 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6683 char *p = StringValueCStr(tmp);
6684
6685 if (*p == '-' && *(p+1) == '\0') {
6686 /* Special case - "-" => no transcoding */
6687 intencoding = (rb_encoding *)Qnil;
6688 }
6689 else {
6690 intencoding = rb_to_encoding(intenc);
6691 }
6692 }
6693 else {
6694 intencoding = rb_to_encoding(intenc);
6695 }
6696 if (extencoding == intencoding) {
6697 intencoding = (rb_encoding *)Qnil;
6698 }
6699 }
6700 if (!NIL_P(encoding)) {
6701 extracted = 1;
6702 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6703 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6704 enc_p, enc2_p, fmode_p);
6705 }
6706 else {
6707 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6708 }
6709 }
6710 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6711 extracted = 1;
6712 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6713 }
6714 return extracted;
6715}
6716
6717typedef struct rb_io_enc_t convconfig_t;
6718
6719static void
6720validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6721{
6722 int fmode = *fmode_p;
6723
6724 if ((fmode & FMODE_READABLE) &&
6725 !enc2 &&
6726 !(fmode & FMODE_BINMODE) &&
6727 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6728 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6729
6730 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6731 rb_raise(rb_eArgError, "newline decorator with binary mode");
6732 }
6733 if (!(fmode & FMODE_BINMODE) &&
6734 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6735 fmode |= FMODE_TEXTMODE;
6736 *fmode_p = fmode;
6737 }
6738#if !DEFAULT_TEXTMODE
6739 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6740 fmode &= ~FMODE_TEXTMODE;
6741 *fmode_p = fmode;
6742 }
6743#endif
6744}
6745
6746static void
6747extract_binmode(VALUE opthash, int *fmode)
6748{
6749 if (!NIL_P(opthash)) {
6750 VALUE v;
6751 v = rb_hash_aref(opthash, sym_textmode);
6752 if (!NIL_P(v)) {
6753 if (*fmode & FMODE_TEXTMODE)
6754 rb_raise(rb_eArgError, "textmode specified twice");
6755 if (*fmode & FMODE_BINMODE)
6756 rb_raise(rb_eArgError, "both textmode and binmode specified");
6757 if (RTEST(v))
6758 *fmode |= FMODE_TEXTMODE;
6759 }
6760 v = rb_hash_aref(opthash, sym_binmode);
6761 if (!NIL_P(v)) {
6762 if (*fmode & FMODE_BINMODE)
6763 rb_raise(rb_eArgError, "binmode specified twice");
6764 if (*fmode & FMODE_TEXTMODE)
6765 rb_raise(rb_eArgError, "both textmode and binmode specified");
6766 if (RTEST(v))
6767 *fmode |= FMODE_BINMODE;
6768 }
6769
6770 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6771 rb_raise(rb_eArgError, "both textmode and binmode specified");
6772 }
6773}
6774
6775void
6776rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6777 int *oflags_p, int *fmode_p, convconfig_t *convconfig_p)
6778{
6779 VALUE vmode;
6780 int oflags, fmode;
6781 rb_encoding *enc, *enc2;
6782 int ecflags;
6783 VALUE ecopts;
6784 int has_enc = 0, has_vmode = 0;
6785 VALUE intmode;
6786
6787 vmode = *vmode_p;
6788
6789 /* Set to defaults */
6790 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6791
6792 vmode_handle:
6793 if (NIL_P(vmode)) {
6794 fmode = FMODE_READABLE;
6795 oflags = O_RDONLY;
6796 }
6797 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6798 vmode = intmode;
6799 oflags = NUM2INT(intmode);
6800 fmode = rb_io_oflags_fmode(oflags);
6801 }
6802 else {
6803 const char *p;
6804
6805 SafeStringValue(vmode);
6806 p = StringValueCStr(vmode);
6807 fmode = rb_io_modestr_fmode(p);
6808 oflags = rb_io_fmode_oflags(fmode);
6809 p = strchr(p, ':');
6810 if (p) {
6811 has_enc = 1;
6812 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6813 }
6814 else {
6815 rb_encoding *e;
6816
6817 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6818 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6819 }
6820 }
6821
6822 if (NIL_P(opthash)) {
6823 ecflags = (fmode & FMODE_READABLE) ?
6824 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6825 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6826#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6827 ecflags |= (fmode & FMODE_WRITABLE) ?
6828 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6829 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6830#endif
6831 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6832 ecopts = Qnil;
6833 if (fmode & FMODE_BINMODE) {
6834#ifdef O_BINARY
6835 oflags |= O_BINARY;
6836#endif
6837 if (!has_enc)
6838 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6839 }
6840#if DEFAULT_TEXTMODE
6841 else if (NIL_P(vmode)) {
6842 fmode |= DEFAULT_TEXTMODE;
6843 }
6844#endif
6845 }
6846 else {
6847 VALUE v;
6848 if (!has_vmode) {
6849 v = rb_hash_aref(opthash, sym_mode);
6850 if (!NIL_P(v)) {
6851 if (!NIL_P(vmode)) {
6852 rb_raise(rb_eArgError, "mode specified twice");
6853 }
6854 has_vmode = 1;
6855 vmode = v;
6856 goto vmode_handle;
6857 }
6858 }
6859 v = rb_hash_aref(opthash, sym_flags);
6860 if (!NIL_P(v)) {
6861 v = rb_to_int(v);
6862 oflags |= NUM2INT(v);
6863 vmode = INT2NUM(oflags);
6864 fmode = rb_io_oflags_fmode(oflags);
6865 }
6866 extract_binmode(opthash, &fmode);
6867 if (fmode & FMODE_BINMODE) {
6868#ifdef O_BINARY
6869 oflags |= O_BINARY;
6870#endif
6871 if (!has_enc)
6872 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6873 }
6874#if DEFAULT_TEXTMODE
6875 else if (NIL_P(vmode)) {
6876 fmode |= DEFAULT_TEXTMODE;
6877 }
6878#endif
6879 v = rb_hash_aref(opthash, sym_perm);
6880 if (!NIL_P(v)) {
6881 if (vperm_p) {
6882 if (!NIL_P(*vperm_p)) {
6883 rb_raise(rb_eArgError, "perm specified twice");
6884 }
6885 *vperm_p = v;
6886 }
6887 else {
6888 /* perm no use, just ignore */
6889 }
6890 }
6891 ecflags = (fmode & FMODE_READABLE) ?
6892 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6893 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6894#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6895 ecflags |= (fmode & FMODE_WRITABLE) ?
6896 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6897 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6898#endif
6899
6900 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6901 if (has_enc) {
6902 rb_raise(rb_eArgError, "encoding specified twice");
6903 }
6904 }
6905 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6906 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
6907 }
6908
6909 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6910
6911 *vmode_p = vmode;
6912
6913 *oflags_p = oflags;
6914 *fmode_p = fmode;
6915 convconfig_p->enc = enc;
6916 convconfig_p->enc2 = enc2;
6917 convconfig_p->ecflags = ecflags;
6918 convconfig_p->ecopts = ecopts;
6919}
6920
6921 struct sysopen_struct {
6922 VALUE fname;
6923 int oflags;
6924 mode_t perm;
6925};
6926
6927static void *
6928sysopen_func(void *ptr)
6929{
6930 const struct sysopen_struct *data = ptr;
6931 const char *fname = RSTRING_PTR(data->fname);
6932 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
6933}
6934
6935static inline int
6936rb_sysopen_internal(struct sysopen_struct *data)
6937{
6938 int fd;
6939 fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
6940 if (0 <= fd)
6941 rb_update_max_fd(fd);
6942 return fd;
6943}
6944
6945static int
6946rb_sysopen(VALUE fname, int oflags, mode_t perm)
6947{
6948 int fd;
6949 struct sysopen_struct data;
6950
6951 data.fname = rb_str_encode_ospath(fname);
6952 StringValueCStr(data.fname);
6953 data.oflags = oflags;
6954 data.perm = perm;
6955
6956 fd = rb_sysopen_internal(&data);
6957 if (fd < 0) {
6958 int e = errno;
6959 if (rb_gc_for_fd(e)) {
6960 fd = rb_sysopen_internal(&data);
6961 }
6962 if (fd < 0) {
6963 rb_syserr_fail_path(e, fname);
6964 }
6965 }
6966 return fd;
6967}
6968
6969 FILE *
6970rb_fdopen(int fd, const char *modestr)
6971{
6972 FILE *file;
6973
6974#if defined(__sun)
6975 errno = 0;
6976#endif
6977 file = fdopen(fd, modestr);
6978 if (!file) {
6979 int e = errno;
6980#if defined(__sun)
6981 if (e == 0) {
6982 rb_gc();
6983 errno = 0;
6984 file = fdopen(fd, modestr);
6985 }
6986 else
6987#endif
6988 if (rb_gc_for_fd(e)) {
6989 file = fdopen(fd, modestr);
6990 }
6991 if (!file) {
6992#ifdef _WIN32
6993 if (e == 0) e = EINVAL;
6994#elif defined(__sun)
6995 if (e == 0) e = EMFILE;
6996#endif
6997 rb_syserr_fail(e, 0);
6998 }
6999 }
7000
7001 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7002#ifdef USE_SETVBUF
7003 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7004 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7005#endif
7006 return file;
7007}
7008
7009static int
7010io_check_tty(rb_io_t *fptr)
7011{
7012 int t = isatty(fptr->fd);
7013 if (t)
7014 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7015 return t;
7016}
7017
7018static VALUE rb_io_internal_encoding(VALUE);
7019static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7020
7021static int
7022io_strip_bom(VALUE io)
7023{
7024 VALUE b1, b2, b3, b4;
7025 rb_io_t *fptr;
7026
7027 GetOpenFile(io, fptr);
7028 if (!(fptr->mode & FMODE_READABLE)) return 0;
7029 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7030 switch (b1) {
7031 case INT2FIX(0xEF):
7032 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7033 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7034 if (b3 == INT2FIX(0xBF)) {
7035 return rb_utf8_encindex();
7036 }
7037 rb_io_ungetbyte(io, b3);
7038 }
7039 rb_io_ungetbyte(io, b2);
7040 break;
7041
7042 case INT2FIX(0xFE):
7043 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7044 if (b2 == INT2FIX(0xFF)) {
7045 return ENCINDEX_UTF_16BE;
7046 }
7047 rb_io_ungetbyte(io, b2);
7048 break;
7049
7050 case INT2FIX(0xFF):
7051 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7052 if (b2 == INT2FIX(0xFE)) {
7053 b3 = rb_io_getbyte(io);
7054 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7055 if (b4 == INT2FIX(0)) {
7056 return ENCINDEX_UTF_32LE;
7057 }
7058 rb_io_ungetbyte(io, b4);
7059 }
7060 rb_io_ungetbyte(io, b3);
7061 return ENCINDEX_UTF_16LE;
7062 }
7063 rb_io_ungetbyte(io, b2);
7064 break;
7065
7066 case INT2FIX(0):
7067 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7068 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7069 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7070 if (b4 == INT2FIX(0xFF)) {
7071 return ENCINDEX_UTF_32BE;
7072 }
7073 rb_io_ungetbyte(io, b4);
7074 }
7075 rb_io_ungetbyte(io, b3);
7076 }
7077 rb_io_ungetbyte(io, b2);
7078 break;
7079 }
7080 rb_io_ungetbyte(io, b1);
7081 return 0;
7082}
7083
7084static rb_encoding *
7085io_set_encoding_by_bom(VALUE io)
7086{
7087 int idx = io_strip_bom(io);
7088 rb_io_t *fptr;
7089 rb_encoding *extenc = NULL;
7090
7091 GetOpenFile(io, fptr);
7092 if (idx) {
7093 extenc = rb_enc_from_index(idx);
7094 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7095 rb_io_internal_encoding(io), Qnil);
7096 }
7097 else {
7098 fptr->encs.enc2 = NULL;
7099 }
7100 return extenc;
7101}
7102
7103static VALUE
7104rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7105 const convconfig_t *convconfig, mode_t perm)
7106{
7107 VALUE pathv;
7108 rb_io_t *fptr;
7109 convconfig_t cc;
7110 if (!convconfig) {
7111 /* Set to default encodings */
7112 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7113 cc.ecflags = 0;
7114 cc.ecopts = Qnil;
7115 convconfig = &cc;
7116 }
7117 validate_enc_binmode(&fmode, convconfig->ecflags,
7118 convconfig->enc, convconfig->enc2);
7119
7120 MakeOpenFile(io, fptr);
7121 fptr->mode = fmode;
7122 fptr->encs = *convconfig;
7123 pathv = rb_str_new_frozen(filename);
7124#ifdef O_TMPFILE
7125 if (!(oflags & O_TMPFILE)) {
7126 fptr->pathv = pathv;
7127 }
7128#else
7129 fptr->pathv = pathv;
7130#endif
7131 fptr->fd = rb_sysopen(pathv, oflags, perm);
7132 io_check_tty(fptr);
7133 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7134
7135 return io;
7136}
7137
7138static VALUE
7139rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7140{
7141 int fmode = rb_io_modestr_fmode(modestr);
7142 const char *p = strchr(modestr, ':');
7143 convconfig_t convconfig;
7144
7145 if (p) {
7146 parse_mode_enc(p+1, rb_usascii_encoding(),
7147 &convconfig.enc, &convconfig.enc2, &fmode);
7148 convconfig.ecflags = 0;
7149 convconfig.ecopts = Qnil;
7150 }
7151 else {
7152 rb_encoding *e;
7153 /* Set to default encodings */
7154
7155 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7156 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7157 convconfig.ecflags = 0;
7158 convconfig.ecopts = Qnil;
7159 }
7160
7161 return rb_file_open_generic(io, filename,
7162 rb_io_fmode_oflags(fmode),
7163 fmode,
7164 &convconfig,
7165 0666);
7166}
7167
7168 VALUE
7169rb_file_open_str(VALUE fname, const char *modestr)
7170{
7171 FilePathValue(fname);
7172 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7173}
7174
7175 VALUE
7176rb_file_open(const char *fname, const char *modestr)
7177{
7178 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7179}
7180
7181#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7182 static struct pipe_list {
7183 rb_io_t *fptr;
7184 struct pipe_list *next;
7185} *pipe_list;
7186
7187static void
7188pipe_add_fptr(rb_io_t *fptr)
7189{
7190 struct pipe_list *list;
7191
7192 list = ALLOC(struct pipe_list);
7193 list->fptr = fptr;
7194 list->next = pipe_list;
7195 pipe_list = list;
7196}
7197
7198static void
7199pipe_del_fptr(rb_io_t *fptr)
7200{
7201 struct pipe_list **prev = &pipe_list;
7202 struct pipe_list *tmp;
7203
7204 while ((tmp = *prev) != 0) {
7205 if (tmp->fptr == fptr) {
7206 *prev = tmp->next;
7207 free(tmp);
7208 return;
7209 }
7210 prev = &tmp->next;
7211 }
7212}
7213
7214#if defined (_WIN32) || defined(__CYGWIN__)
7215static void
7216pipe_atexit(void)
7217{
7218 struct pipe_list *list = pipe_list;
7219 struct pipe_list *tmp;
7220
7221 while (list) {
7222 tmp = list->next;
7223 rb_io_fptr_finalize(list->fptr);
7224 list = tmp;
7225 }
7226}
7227#endif
7228
7229static void
7230pipe_finalize(rb_io_t *fptr, int noraise)
7231{
7232#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7233 int status = 0;
7234 if (fptr->stdio_file) {
7235 status = pclose(fptr->stdio_file);
7236 }
7237 fptr->fd = -1;
7238 fptr->stdio_file = 0;
7239 rb_last_status_set(status, fptr->pid);
7240#else
7241 fptr_finalize(fptr, noraise);
7242#endif
7243 pipe_del_fptr(fptr);
7244}
7245#endif
7246
7247static void
7248fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7249{
7250#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7251 void (*const old_finalize)(struct rb_io_t*,int) = fptr->finalize;
7252
7253 if (old_finalize == orig->finalize) return;
7254#endif
7255
7256 fptr->finalize = orig->finalize;
7257
7258#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7259 if (old_finalize != pipe_finalize) {
7260 struct pipe_list *list;
7261 for (list = pipe_list; list; list = list->next) {
7262 if (list->fptr == fptr) break;
7263 }
7264 if (!list) pipe_add_fptr(fptr);
7265 }
7266 else {
7267 pipe_del_fptr(fptr);
7268 }
7269#endif
7270}
7271
7272void
7273rb_io_synchronized(rb_io_t *fptr)
7274{
7275 rb_io_check_initialized(fptr);
7276 fptr->mode |= FMODE_SYNC;
7277}
7278
7279void
7280rb_io_unbuffered(rb_io_t *fptr)
7281{
7282 rb_io_synchronized(fptr);
7283}
7284
7285int
7286rb_pipe(int *pipes)
7287{
7288 int ret;
7289 ret = rb_cloexec_pipe(pipes);
7290 if (ret < 0) {
7291 if (rb_gc_for_fd(errno)) {
7292 ret = rb_cloexec_pipe(pipes);
7293 }
7294 }
7295 if (ret == 0) {
7296 rb_update_max_fd(pipes[0]);
7297 rb_update_max_fd(pipes[1]);
7298 }
7299 return ret;
7300}
7301
7302#ifdef _WIN32
7303#define HAVE_SPAWNV 1
7304#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7305#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7306#endif
7307
7308#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7309struct popen_arg {
7310 VALUE execarg_obj;
7311 struct rb_execarg *eargp;
7312 int modef;
7313 int pair[2];
7314 int write_pair[2];
7315};
7316#endif
7317
7318#ifdef HAVE_WORKING_FORK
7319# ifndef __EMSCRIPTEN__
7320static void
7321popen_redirect(struct popen_arg *p)
7322{
7323 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7324 close(p->write_pair[1]);
7325 if (p->write_pair[0] != 0) {
7326 dup2(p->write_pair[0], 0);
7327 close(p->write_pair[0]);
7328 }
7329 close(p->pair[0]);
7330 if (p->pair[1] != 1) {
7331 dup2(p->pair[1], 1);
7332 close(p->pair[1]);
7333 }
7334 }
7335 else if (p->modef & FMODE_READABLE) {
7336 close(p->pair[0]);
7337 if (p->pair[1] != 1) {
7338 dup2(p->pair[1], 1);
7339 close(p->pair[1]);
7340 }
7341 }
7342 else {
7343 close(p->pair[1]);
7344 if (p->pair[0] != 0) {
7345 dup2(p->pair[0], 0);
7346 close(p->pair[0]);
7347 }
7348 }
7349}
7350# endif
7351
7352#if defined(__linux__)
7353/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7354 * Since /proc may not be available, linux_get_maxfd is just a hint.
7355 * This function, linux_get_maxfd, must be async-signal-safe.
7356 * I.e. opendir() is not usable.
7357 *
7358 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7359 * However they are easy to re-implement in async-signal-safe manner.
7360 * (Also note that there is missing/memcmp.c.)
7361 */
7362static int
7363linux_get_maxfd(void)
7364{
7365 int fd;
7366 char buf[4096], *p, *np, *e;
7367 ssize_t ss;
7368 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7369 if (fd < 0) return fd;
7370 ss = read(fd, buf, sizeof(buf));
7371 if (ss < 0) goto err;
7372 p = buf;
7373 e = buf + ss;
7374 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7375 (np = memchr(p, '\n', e-p)) != NULL) {
7376 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7377 int fdsize;
7378 p += sizeof("FDSize:")-1;
7379 *np = '\0';
7380 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7381 close(fd);
7382 return fdsize;
7383 }
7384 p = np+1;
7385 }
7386 /* fall through */
7387
7388 err:
7389 close(fd);
7390 return (int)ss;
7391}
7392#endif
7393
7394/* This function should be async-signal-safe. */
7395void
7396 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7397{
7398#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7399 int fd, ret;
7400 int max = (int)max_file_descriptor;
7401# ifdef F_MAXFD
7402 /* F_MAXFD is available since NetBSD 2.0. */
7403 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7404 if (ret != -1)
7405 maxhint = max = ret;
7406# elif defined(__linux__)
7407 ret = linux_get_maxfd();
7408 if (maxhint < ret)
7409 maxhint = ret;
7410 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7411# endif
7412 if (max < maxhint)
7413 max = maxhint;
7414 for (fd = lowfd; fd <= max; fd++) {
7415 if (!NIL_P(noclose_fds) &&
7416 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7417 continue;
7418 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7419 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7420 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7421 }
7422# define CONTIGUOUS_CLOSED_FDS 20
7423 if (ret != -1) {
7424 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7425 max = fd + CONTIGUOUS_CLOSED_FDS;
7426 }
7427 }
7428#endif
7429}
7430
7431# ifndef __EMSCRIPTEN__
7432static int
7433popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7434{
7435 struct popen_arg *p = (struct popen_arg*)pp;
7436
7437 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7438}
7439# endif
7440#endif
7441
7442#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7443static VALUE
7444rb_execarg_fixup_v(VALUE execarg_obj)
7445{
7446 rb_execarg_parent_start(execarg_obj);
7447 return Qnil;
7448}
7449#else
7450char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7451#endif
7452
7453#ifndef __EMSCRIPTEN__
7454static VALUE
7455pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7456 const convconfig_t *convconfig)
7457{
7458 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7459 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7460 rb_pid_t pid = 0;
7461 rb_io_t *fptr;
7462 VALUE port;
7463 rb_io_t *write_fptr;
7464 VALUE write_port;
7465#if defined(HAVE_WORKING_FORK)
7466 int status;
7467 char errmsg[80] = { '\0' };
7468#endif
7469#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7470 int state;
7471 struct popen_arg arg;
7472#endif
7473 int e = 0;
7474#if defined(HAVE_SPAWNV)
7475# if defined(HAVE_SPAWNVE)
7476# define DO_SPAWN(cmd, args, envp) ((args) ? \
7477 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7478 spawne(P_NOWAIT, (cmd), (envp)))
7479# else
7480# define DO_SPAWN(cmd, args, envp) ((args) ? \
7481 spawnv(P_NOWAIT, (cmd), (args)) : \
7482 spawn(P_NOWAIT, (cmd)))
7483# endif
7484# if !defined(HAVE_WORKING_FORK)
7485 char **args = NULL;
7486# if defined(HAVE_SPAWNVE)
7487 char **envp = NULL;
7488# endif
7489# endif
7490#endif
7491#if !defined(HAVE_WORKING_FORK)
7492 struct rb_execarg sarg, *sargp = &sarg;
7493#endif
7494 FILE *fp = 0;
7495 int fd = -1;
7496 int write_fd = -1;
7497#if !defined(HAVE_WORKING_FORK)
7498 const char *cmd = 0;
7499
7500 if (prog)
7501 cmd = StringValueCStr(prog);
7502#endif
7503
7504#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7505 arg.execarg_obj = execarg_obj;
7506 arg.eargp = eargp;
7507 arg.modef = fmode;
7508 arg.pair[0] = arg.pair[1] = -1;
7509 arg.write_pair[0] = arg.write_pair[1] = -1;
7510# if !defined(HAVE_WORKING_FORK)
7511 if (eargp && !eargp->use_shell) {
7512 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7513 }
7514# endif
7515 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7516 case FMODE_READABLE|FMODE_WRITABLE:
7517 if (rb_pipe(arg.write_pair) < 0)
7518 rb_sys_fail_str(prog);
7519 if (rb_pipe(arg.pair) < 0) {
7520 e = errno;
7521 close(arg.write_pair[0]);
7522 close(arg.write_pair[1]);
7523 rb_syserr_fail_str(e, prog);
7524 }
7525 if (eargp) {
7526 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7527 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7528 }
7529 break;
7530 case FMODE_READABLE:
7531 if (rb_pipe(arg.pair) < 0)
7532 rb_sys_fail_str(prog);
7533 if (eargp)
7534 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7535 break;
7536 case FMODE_WRITABLE:
7537 if (rb_pipe(arg.pair) < 0)
7538 rb_sys_fail_str(prog);
7539 if (eargp)
7540 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7541 break;
7542 default:
7543 rb_sys_fail_str(prog);
7544 }
7545 if (!NIL_P(execarg_obj)) {
7546 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7547 if (state) {
7548 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7549 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7550 if (0 <= arg.pair[0]) close(arg.pair[0]);
7551 if (0 <= arg.pair[1]) close(arg.pair[1]);
7552 rb_execarg_parent_end(execarg_obj);
7553 rb_jump_tag(state);
7554 }
7555
7556# if defined(HAVE_WORKING_FORK)
7557 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7558# else
7559 rb_execarg_run_options(eargp, sargp, NULL, 0);
7560# if defined(HAVE_SPAWNVE)
7561 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7562# endif
7563 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7564 /* exec failed */
7565 switch (e = errno) {
7566 case EAGAIN:
7567# if EWOULDBLOCK != EAGAIN
7568 case EWOULDBLOCK:
7569# endif
7570 rb_thread_sleep(1);
7571 continue;
7572 }
7573 break;
7574 }
7575 if (eargp)
7576 rb_execarg_run_options(sargp, NULL, NULL, 0);
7577# endif
7578 rb_execarg_parent_end(execarg_obj);
7579 }
7580 else {
7581# if defined(HAVE_WORKING_FORK)
7582 pid = rb_call_proc__fork();
7583 if (pid == 0) { /* child */
7584 popen_redirect(&arg);
7585 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7586 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7587 return Qnil;
7588 }
7589# else
7590 rb_notimplement();
7591# endif
7592 }
7593
7594 /* parent */
7595 if (pid < 0) {
7596# if defined(HAVE_WORKING_FORK)
7597 e = errno;
7598# endif
7599 close(arg.pair[0]);
7600 close(arg.pair[1]);
7601 if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) {
7602 close(arg.write_pair[0]);
7603 close(arg.write_pair[1]);
7604 }
7605# if defined(HAVE_WORKING_FORK)
7606 if (errmsg[0])
7607 rb_syserr_fail(e, errmsg);
7608# endif
7609 rb_syserr_fail_str(e, prog);
7610 }
7611 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7612 close(arg.pair[1]);
7613 fd = arg.pair[0];
7614 close(arg.write_pair[0]);
7615 write_fd = arg.write_pair[1];
7616 }
7617 else if (fmode & FMODE_READABLE) {
7618 close(arg.pair[1]);
7619 fd = arg.pair[0];
7620 }
7621 else {
7622 close(arg.pair[0]);
7623 fd = arg.pair[1];
7624 }
7625#else
7626 cmd = rb_execarg_commandline(eargp, &prog);
7627 if (!NIL_P(execarg_obj)) {
7628 rb_execarg_parent_start(execarg_obj);
7629 rb_execarg_run_options(eargp, sargp, NULL, 0);
7630 }
7631 fp = popen(cmd, modestr);
7632 e = errno;
7633 if (eargp) {
7634 rb_execarg_parent_end(execarg_obj);
7635 rb_execarg_run_options(sargp, NULL, NULL, 0);
7636 }
7637 if (!fp) rb_syserr_fail_path(e, prog);
7638 fd = fileno(fp);
7639#endif
7640
7641 port = io_alloc(rb_cIO);
7642 MakeOpenFile(port, fptr);
7643 fptr->fd = fd;
7644 fptr->stdio_file = fp;
7645 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7646 if (convconfig) {
7647 fptr->encs = *convconfig;
7648#if RUBY_CRLF_ENVIRONMENT
7649 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
7650 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7651 }
7652#endif
7653 }
7654 else {
7655 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7656 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7657 }
7658#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7659 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7660 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7661 }
7662#endif
7663 }
7664 fptr->pid = pid;
7665
7666 if (0 <= write_fd) {
7667 write_port = io_alloc(rb_cIO);
7668 MakeOpenFile(write_port, write_fptr);
7669 write_fptr->fd = write_fd;
7670 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7671 fptr->mode &= ~FMODE_WRITABLE;
7672 fptr->tied_io_for_writing = write_port;
7673 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7674 }
7675
7676#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7677 fptr->finalize = pipe_finalize;
7678 pipe_add_fptr(fptr);
7679#endif
7680 return port;
7681}
7682#else
7683static VALUE
7684pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7685 const convconfig_t *convconfig)
7686{
7687 rb_raise(rb_eNotImpError, "popen() is not available");
7688}
7689#endif
7690
7691static int
7692is_popen_fork(VALUE prog)
7693{
7694 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7695#if !defined(HAVE_WORKING_FORK)
7696 rb_raise(rb_eNotImpError,
7697 "fork() function is unimplemented on this machine");
7698#else
7699 return TRUE;
7700#endif
7701 }
7702 return FALSE;
7703}
7704
7705static VALUE
7706pipe_open_s(VALUE prog, const char *modestr, int fmode,
7707 const convconfig_t *convconfig)
7708{
7709 int argc = 1;
7710 VALUE *argv = &prog;
7711 VALUE execarg_obj = Qnil;
7712
7713 if (!is_popen_fork(prog))
7714 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7715 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7716}
7717
7718static VALUE
7719pipe_close(VALUE io)
7720{
7721 rb_io_t *fptr = io_close_fptr(io);
7722 if (fptr) {
7723 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7724 }
7725 return Qnil;
7726}
7727
7728static VALUE popen_finish(VALUE port, VALUE klass);
7729
7730/*
7731 * call-seq:
7732 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7733 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7734 *
7735 * Executes the given command +cmd+ as a subprocess
7736 * whose $stdin and $stdout are connected to a new stream +io+.
7737 *
7738 * This method has potential security vulnerabilities if called with untrusted input;
7739 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7740 *
7741 * If no block is given, returns the new stream,
7742 * which depending on given +mode+ may be open for reading, writing, or both.
7743 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7744 *
7745 * If a block is given, the stream is passed to the block
7746 * (again, open for reading, writing, or both);
7747 * when the block exits, the stream is closed,
7748 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7749 *
7750 * Optional argument +mode+ may be any valid \IO mode.
7751 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7752 *
7753 * Required argument +cmd+ determines which of the following occurs:
7754 *
7755 * - The process forks.
7756 * - A specified program runs in a shell.
7757 * - A specified program runs with specified arguments.
7758 * - A specified program runs with specified arguments and a specified +argv0+.
7759 *
7760 * Each of these is detailed below.
7761 *
7762 * The optional hash argument +env+ specifies name/value pairs that are to be added
7763 * to the environment variables for the subprocess:
7764 *
7765 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7766 * pipe.puts 'puts ENV["FOO"]'
7767 * pipe.close_write
7768 * pipe.gets
7769 * end => "bar\n"
7770 *
7771 * Optional keyword arguments +opts+ specify:
7772 *
7773 * - {Open options}[rdoc-ref:IO@Open+Options].
7774 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7775 * - Options for Kernel#spawn.
7776 *
7777 * <b>Forked \Process</b>
7778 *
7779 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7780 * IO.popen('-') do |pipe|
7781 * if pipe
7782 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7783 * else
7784 * $stderr.puts "In child, pid is #{$$}\n"
7785 * end
7786 * end
7787 *
7788 * Output:
7789 *
7790 * In parent, child pid is 26253
7791 * In child, pid is 26253
7792 *
7793 * Note that this is not supported on all platforms.
7794 *
7795 * <b>Shell Subprocess</b>
7796 *
7797 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7798 * the program named +cmd+ is run as a shell command:
7799 *
7800 * IO.popen('uname') do |pipe|
7801 * pipe.readlines
7802 * end
7803 *
7804 * Output:
7805 *
7806 * ["Linux\n"]
7807 *
7808 * Another example:
7809 *
7810 * IO.popen('/bin/sh', 'r+') do |pipe|
7811 * pipe.puts('ls')
7812 * pipe.close_write
7813 * $stderr.puts pipe.readlines.size
7814 * end
7815 *
7816 * Output:
7817 *
7818 * 213
7819 *
7820 * <b>Program Subprocess</b>
7821 *
7822 * When argument +cmd+ is an array of strings,
7823 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7824 *
7825 * IO.popen(['du', '..', '.']) do |pipe|
7826 * $stderr.puts pipe.readlines.size
7827 * end
7828 *
7829 * Output:
7830 *
7831 * 1111
7832 *
7833 * <b>Program Subprocess with <tt>argv0</tt></b>
7834 *
7835 * When argument +cmd+ is an array whose first element is a 2-element string array
7836 * and whose remaining elements (if any) are strings:
7837 *
7838 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7839 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7840 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7841 *
7842 * Example (sets <tt>$0</tt> to 'foo'):
7843 *
7844 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7845 *
7846 * <b>Some Special Examples</b>
7847 *
7848 * # Set IO encoding.
7849 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7850 * euc_jp_string = nkf_io.read
7851 * }
7852 *
7853 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7854 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7855 * ls_result_with_error = io.read
7856 * end
7857 *
7858 * # Use mixture of spawn options and IO options.
7859 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7860 * ls_result_with_error = io.read
7861 * end
7862 *
7863 * f = IO.popen("uname")
7864 * p f.readlines
7865 * f.close
7866 * puts "Parent is #{Process.pid}"
7867 * IO.popen("date") {|f| puts f.gets }
7868 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7869 * p $?
7870 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7871 * f.puts "bar"; f.close_write; puts f.gets
7872 * }
7873 *
7874 * Output (from last section):
7875 *
7876 * ["Linux\n"]
7877 * Parent is 21346
7878 * Thu Jan 15 22:41:19 JST 2009
7879 * 21346 is here, f is #<IO:fd 3>
7880 * 21352 is here, f is nil
7881 * #<Process::Status: pid 21352 exit 0>
7882 * <foo>bar;zot;
7883 *
7884 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7885 *
7886 */
7887
7888static VALUE
7889rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7890{
7891 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7892
7893 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7894 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7895 switch (argc) {
7896 case 2:
7897 pmode = argv[1];
7898 case 1:
7899 pname = argv[0];
7900 break;
7901 default:
7902 {
7903 int ex = !NIL_P(opt);
7904 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7905 }
7906 }
7907 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7908}
7909
7910 VALUE
7911rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7912{
7913 const char *modestr;
7914 VALUE tmp, execarg_obj = Qnil;
7915 int oflags, fmode;
7916 convconfig_t convconfig;
7917
7918 tmp = rb_check_array_type(pname);
7919 if (!NIL_P(tmp)) {
7920 long len = RARRAY_LEN(tmp);
7921#if SIZEOF_LONG > SIZEOF_INT
7922 if (len > INT_MAX) {
7923 rb_raise(rb_eArgError, "too many arguments");
7924 }
7925#endif
7926 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7927 RB_GC_GUARD(tmp);
7928 }
7929 else {
7930 SafeStringValue(pname);
7931 execarg_obj = Qnil;
7932 if (!is_popen_fork(pname))
7933 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7934 }
7935 if (!NIL_P(execarg_obj)) {
7936 if (!NIL_P(opt))
7937 opt = rb_execarg_extract_options(execarg_obj, opt);
7938 if (!NIL_P(env))
7939 rb_execarg_setenv(execarg_obj, env);
7940 }
7941 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
7942 modestr = rb_io_oflags_modestr(oflags);
7943
7944 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7945}
7946
7947static VALUE
7948popen_finish(VALUE port, VALUE klass)
7949{
7950 if (NIL_P(port)) {
7951 /* child */
7952 if (rb_block_given_p()) {
7953 rb_yield(Qnil);
7954 rb_io_flush(rb_ractor_stdout());
7955 rb_io_flush(rb_ractor_stderr());
7956 _exit(0);
7957 }
7958 return Qnil;
7959 }
7960 RBASIC_SET_CLASS(port, klass);
7961 if (rb_block_given_p()) {
7962 return rb_ensure(rb_yield, port, pipe_close, port);
7963 }
7964 return port;
7965}
7966
7967static void
7968rb_scan_open_args(int argc, const VALUE *argv,
7969 VALUE *fname_p, int *oflags_p, int *fmode_p,
7970 convconfig_t *convconfig_p, mode_t *perm_p)
7971{
7972 VALUE opt, fname, vmode, vperm;
7973 int oflags, fmode;
7974 mode_t perm;
7975
7976 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
7977 FilePathValue(fname);
7978
7979 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
7980
7981 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
7982
7983 *fname_p = fname;
7984 *oflags_p = oflags;
7985 *fmode_p = fmode;
7986 *perm_p = perm;
7987}
7988
7989static VALUE
7990rb_open_file(int argc, const VALUE *argv, VALUE io)
7991{
7992 VALUE fname;
7993 int oflags, fmode;
7994 convconfig_t convconfig;
7995 mode_t perm;
7996
7997 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
7998 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
7999
8000 return io;
8001}
8002
8003/*
8004 * Document-method: File::open
8005 *
8006 * call-seq:
8007 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8008 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8009 *
8010 * Creates a new \File object, via File.new with the given arguments.
8011 *
8012 * With no block given, returns the \File object.
8013 *
8014 * With a block given, calls the block with the \File object
8015 * and returns the block's value.
8016 *
8017 */
8018
8019/*
8020 * Document-method: IO::open
8021 *
8022 * call-seq:
8023 * IO.open(fd, mode = 'r', **opts) -> io
8024 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8025 *
8026 * Creates a new \IO object, via IO.new with the given arguments.
8027 *
8028 * With no block given, returns the \IO object.
8029 *
8030 * With a block given, calls the block with the \IO object
8031 * and returns the block's value.
8032 *
8033 */
8034
8035static VALUE
8036rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8037{
8038 VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
8039
8040 if (rb_block_given_p()) {
8041 return rb_ensure(rb_yield, io, io_close, io);
8042 }
8043
8044 return io;
8045}
8046
8047/*
8048 * call-seq:
8049 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8050 *
8051 * Opens the file at the given path with the given mode and permissions;
8052 * returns the integer file descriptor.
8053 *
8054 * If the file is to be readable, it must exist;
8055 * if the file is to be writable and does not exist,
8056 * it is created with the given permissions:
8057 *
8058 * File.write('t.tmp', '') # => 0
8059 * IO.sysopen('t.tmp') # => 8
8060 * IO.sysopen('t.tmp', 'w') # => 9
8061 *
8062 *
8063 */
8064
8065static VALUE
8066rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8067{
8068 VALUE fname, vmode, vperm;
8069 VALUE intmode;
8070 int oflags, fd;
8071 mode_t perm;
8072
8073 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8074 FilePathValue(fname);
8075
8076 if (NIL_P(vmode))
8077 oflags = O_RDONLY;
8078 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8079 oflags = NUM2INT(intmode);
8080 else {
8081 SafeStringValue(vmode);
8082 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8083 }
8084 if (NIL_P(vperm)) perm = 0666;
8085 else perm = NUM2MODET(vperm);
8086
8087 RB_GC_GUARD(fname) = rb_str_new4(fname);
8088 fd = rb_sysopen(fname, oflags, perm);
8089 return INT2NUM(fd);
8090}
8091
8092static VALUE
8093check_pipe_command(VALUE filename_or_command)
8094{
8095 char *s = RSTRING_PTR(filename_or_command);
8096 long l = RSTRING_LEN(filename_or_command);
8097 char *e = s + l;
8098 int chlen;
8099
8100 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8101 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8102 return cmd;
8103 }
8104 return Qnil;
8105}
8106
8107/*
8108 * call-seq:
8109 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8110 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8111 *
8112 * Creates an IO object connected to the given stream, file, or subprocess.
8113 *
8114 * Required string argument +path+ determines which of the following occurs:
8115 *
8116 * - The file at the specified +path+ is opened.
8117 * - The process forks.
8118 * - A subprocess is created.
8119 *
8120 * Each of these is detailed below.
8121 *
8122 * <b>File Opened</b>
8123
8124 * If +path+ does _not_ start with a pipe character (<tt>'|'</tt>),
8125 * a file stream is opened with <tt>File.open(path, mode, perm, **opts)</tt>.
8126 *
8127 * With no block given, file stream is returned:
8128 *
8129 * open('t.txt') # => #<File:t.txt>
8130 *
8131 * With a block given, calls the block with the open file stream,
8132 * then closes the stream:
8133 *
8134 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8135 *
8136 * Output:
8137 *
8138 * #<File:t.txt>
8139 *
8140 * See File.open for details.
8141 *
8142 * <b>Process Forked</b>
8143 *
8144 * If +path+ is the 2-character string <tt>'|-'</tt>, the process forks
8145 * and the child process is connected to the parent.
8146 *
8147 * With no block given:
8148 *
8149 * io = open('|-')
8150 * if io
8151 * $stderr.puts "In parent, child pid is #{io.pid}."
8152 * else
8153 * $stderr.puts "In child, pid is #{$$}."
8154 * end
8155 *
8156 * Output:
8157 *
8158 * In parent, child pid is 27903.
8159 * In child, pid is 27903.
8160 *
8161 * With a block given:
8162 *
8163 * open('|-') do |io|
8164 * if io
8165 * $stderr.puts "In parent, child pid is #{io.pid}."
8166 * else
8167 * $stderr.puts "In child, pid is #{$$}."
8168 * end
8169 * end
8170 *
8171 * Output:
8172 *
8173 * In parent, child pid is 28427.
8174 * In child, pid is 28427.
8175 *
8176 * <b>Subprocess Created</b>
8177 *
8178 * If +path+ is <tt>'|command'</tt> (<tt>'command' != '-'</tt>),
8179 * a new subprocess runs the command; its open stream is returned.
8180 * Note that the command may be processed by shell if it contains
8181 * shell metacharacters.
8182 *
8183 * With no block given:
8184 *
8185 * io = open('|echo "Hi!"') # => #<IO:fd 12>
8186 * print io.gets
8187 * io.close
8188 *
8189 * Output:
8190 *
8191 * "Hi!"
8192 *
8193 * With a block given, calls the block with the stream, then closes the stream:
8194 *
8195 * open('|echo "Hi!"') do |io|
8196 * print io.gets
8197 * end
8198 *
8199 * Output:
8200 *
8201 * "Hi!"
8202 *
8203 */
8204
8205static VALUE
8206rb_f_open(int argc, VALUE *argv, VALUE _)
8207{
8208 ID to_open = 0;
8209 int redirect = FALSE;
8210
8211 if (argc >= 1) {
8212 CONST_ID(to_open, "to_open");
8213 if (rb_respond_to(argv[0], to_open)) {
8214 redirect = TRUE;
8215 }
8216 else {
8217 VALUE tmp = argv[0];
8218 FilePathValue(tmp);
8219 if (NIL_P(tmp)) {
8220 redirect = TRUE;
8221 }
8222 else {
8223 VALUE cmd = check_pipe_command(tmp);
8224 if (!NIL_P(cmd)) {
8225 argv[0] = cmd;
8226 return rb_io_s_popen(argc, argv, rb_cIO);
8227 }
8228 }
8229 }
8230 }
8231 if (redirect) {
8232 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8233
8234 if (rb_block_given_p()) {
8235 return rb_ensure(rb_yield, io, io_close, io);
8236 }
8237 return io;
8238 }
8239 return rb_io_s_open(argc, argv, rb_cFile);
8240}
8241
8242static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const convconfig_t *, mode_t);
8243
8244static VALUE
8245rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8246{
8247 int oflags, fmode;
8248 convconfig_t convconfig;
8249 mode_t perm;
8250
8251 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8252 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8253 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8254}
8255
8256static VALUE
8257rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8258 const convconfig_t *convconfig, mode_t perm)
8259{
8260 VALUE cmd;
8261 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8262 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8263 }
8264 else {
8265 return rb_file_open_generic(io_alloc(klass), filename,
8266 oflags, fmode, convconfig, perm);
8267 }
8268}
8269
8270static VALUE
8271io_reopen(VALUE io, VALUE nfile)
8272{
8273 rb_io_t *fptr, *orig;
8274 int fd, fd2;
8275 rb_off_t pos = 0;
8276
8277 nfile = rb_io_get_io(nfile);
8278 GetOpenFile(io, fptr);
8279 GetOpenFile(nfile, orig);
8280
8281 if (fptr == orig) return io;
8282 if (IS_PREP_STDIO(fptr)) {
8283 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8284 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8285 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8286 rb_raise(rb_eArgError,
8287 "%s can't change access mode from \"%s\" to \"%s\"",
8288 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8289 rb_io_fmode_modestr(orig->mode));
8290 }
8291 }
8292 if (fptr->mode & FMODE_WRITABLE) {
8293 if (io_fflush(fptr) < 0)
8294 rb_sys_fail_on_write(fptr);
8295 }
8296 else {
8297 flush_before_seek(fptr);
8298 }
8299 if (orig->mode & FMODE_READABLE) {
8300 pos = io_tell(orig);
8301 }
8302 if (orig->mode & FMODE_WRITABLE) {
8303 if (io_fflush(orig) < 0)
8304 rb_sys_fail_on_write(fptr);
8305 }
8306
8307 /* copy rb_io_t structure */
8308 fptr->mode = orig->mode | (fptr->mode & FMODE_PREP);
8309 fptr->pid = orig->pid;
8310 fptr->lineno = orig->lineno;
8311 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8312 else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
8313 fptr_copy_finalizer(fptr, orig);
8314
8315 fd = fptr->fd;
8316 fd2 = orig->fd;
8317 if (fd != fd2) {
8318 if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->stdio_file) {
8319 /* need to keep FILE objects of stdin, stdout and stderr */
8320 if (rb_cloexec_dup2(fd2, fd) < 0)
8321 rb_sys_fail_path(orig->pathv);
8322 rb_update_max_fd(fd);
8323 }
8324 else {
8325 fclose(fptr->stdio_file);
8326 fptr->stdio_file = 0;
8327 fptr->fd = -1;
8328 if (rb_cloexec_dup2(fd2, fd) < 0)
8329 rb_sys_fail_path(orig->pathv);
8330 rb_update_max_fd(fd);
8331 fptr->fd = fd;
8332 }
8333 rb_thread_fd_close(fd);
8334 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8335 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8336 rb_sys_fail_path(fptr->pathv);
8337 }
8338 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8339 rb_sys_fail_path(orig->pathv);
8340 }
8341 }
8342 }
8343
8344 if (fptr->mode & FMODE_BINMODE) {
8345 rb_io_binmode(io);
8346 }
8347
8348 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8349 return io;
8350}
8351
8352#ifdef _WIN32
8353int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8354#else
8355static int
8356rb_freopen(VALUE fname, const char *mode, FILE *fp)
8357{
8358 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8359 RB_GC_GUARD(fname);
8360 return errno;
8361 }
8362 return 0;
8363}
8364#endif
8365
8366/*
8367 * call-seq:
8368 * reopen(other_io) -> self
8369 * reopen(path, mode = 'r', **opts) -> self
8370 *
8371 * Reassociates the stream with another stream,
8372 * which may be of a different class.
8373 * This method may be used to redirect an existing stream
8374 * to a new destination.
8375 *
8376 * With argument +other_io+ given, reassociates with that stream:
8377 *
8378 * # Redirect $stdin from a file.
8379 * f = File.open('t.txt')
8380 * $stdin.reopen(f)
8381 * f.close
8382 *
8383 * # Redirect $stdout to a file.
8384 * f = File.open('t.tmp', 'w')
8385 * $stdout.reopen(f)
8386 * f.close
8387 *
8388 * With argument +path+ given, reassociates with a new stream to that file path:
8389 *
8390 * $stdin.reopen('t.txt')
8391 * $stdout.reopen('t.tmp', 'w')
8392 *
8393 * Optional keyword arguments +opts+ specify:
8394 *
8395 * - {Open Options}[rdoc-ref:IO@Open+Options].
8396 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8397 *
8398 */
8399
8400static VALUE
8401rb_io_reopen(int argc, VALUE *argv, VALUE file)
8402{
8403 VALUE fname, nmode, opt;
8404 int oflags;
8405 rb_io_t *fptr;
8406
8407 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8408 VALUE tmp = rb_io_check_io(fname);
8409 if (!NIL_P(tmp)) {
8410 return io_reopen(file, tmp);
8411 }
8412 }
8413
8414 FilePathValue(fname);
8415 rb_io_taint_check(file);
8416 fptr = RFILE(file)->fptr;
8417 if (!fptr) {
8418 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8419 }
8420
8421 if (!NIL_P(nmode) || !NIL_P(opt)) {
8422 int fmode;
8423 convconfig_t convconfig;
8424
8425 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8426 if (IS_PREP_STDIO(fptr) &&
8427 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8428 (fptr->mode & FMODE_READWRITE)) {
8429 rb_raise(rb_eArgError,
8430 "%s can't change access mode from \"%s\" to \"%s\"",
8431 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8432 rb_io_fmode_modestr(fmode));
8433 }
8434 fptr->mode = fmode;
8435 fptr->encs = convconfig;
8436 }
8437 else {
8438 oflags = rb_io_fmode_oflags(fptr->mode);
8439 }
8440
8441 fptr->pathv = fname;
8442 if (fptr->fd < 0) {
8443 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8444 fptr->stdio_file = 0;
8445 return file;
8446 }
8447
8448 if (fptr->mode & FMODE_WRITABLE) {
8449 if (io_fflush(fptr) < 0)
8450 rb_sys_fail_on_write(fptr);
8451 }
8452 fptr->rbuf.off = fptr->rbuf.len = 0;
8453
8454 if (fptr->stdio_file) {
8455 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8456 rb_io_oflags_modestr(oflags),
8457 fptr->stdio_file);
8458 if (e) rb_syserr_fail_path(e, fptr->pathv);
8459 fptr->fd = fileno(fptr->stdio_file);
8460 rb_fd_fix_cloexec(fptr->fd);
8461#ifdef USE_SETVBUF
8462 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8463 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8464#endif
8465 if (fptr->stdio_file == stderr) {
8466 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8467 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8468 }
8469 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8470 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8471 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8472 }
8473 }
8474 else {
8475 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8476 int err = 0;
8477 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8478 err = errno;
8479 (void)close(tmpfd);
8480 if (err) {
8481 rb_syserr_fail_path(err, fptr->pathv);
8482 }
8483 }
8484
8485 return file;
8486}
8487
8488/* :nodoc: */
8489static VALUE
8490rb_io_init_copy(VALUE dest, VALUE io)
8491{
8492 rb_io_t *fptr, *orig;
8493 int fd;
8494 VALUE write_io;
8495 rb_off_t pos;
8496
8497 io = rb_io_get_io(io);
8498 if (!OBJ_INIT_COPY(dest, io)) return dest;
8499 GetOpenFile(io, orig);
8500 MakeOpenFile(dest, fptr);
8501
8502 rb_io_flush(io);
8503
8504 /* copy rb_io_t structure */
8505 fptr->mode = orig->mode & ~FMODE_PREP;
8506 fptr->encs = orig->encs;
8507 fptr->pid = orig->pid;
8508 fptr->lineno = orig->lineno;
8509 fptr->timeout = orig->timeout;
8510 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8511 fptr_copy_finalizer(fptr, orig);
8512
8513 fd = ruby_dup(orig->fd);
8514 fptr->fd = fd;
8515 pos = io_tell(orig);
8516 if (0 <= pos)
8517 io_seek(fptr, pos, SEEK_SET);
8518 if (fptr->mode & FMODE_BINMODE) {
8519 rb_io_binmode(dest);
8520 }
8521
8522 write_io = GetWriteIO(io);
8523 if (io != write_io) {
8524 write_io = rb_obj_dup(write_io);
8525 fptr->tied_io_for_writing = write_io;
8526 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8527 }
8528
8529 return dest;
8530}
8531
8532/*
8533 * call-seq:
8534 * printf(format_string, *objects) -> nil
8535 *
8536 * Formats and writes +objects+ to the stream.
8537 *
8538 * For details on +format_string+, see
8539 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8540 *
8541 */
8542
8543 VALUE
8544rb_io_printf(int argc, const VALUE *argv, VALUE out)
8545{
8546 rb_io_write(out, rb_f_sprintf(argc, argv));
8547 return Qnil;
8548}
8549
8550/*
8551 * call-seq:
8552 * printf(format_string, *objects) -> nil
8553 * printf(io, format_string, *objects) -> nil
8554 *
8555 * Equivalent to:
8556 *
8557 * io.write(sprintf(format_string, *objects))
8558 *
8559 * For details on +format_string+, see
8560 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8561 *
8562 * With the single argument +format_string+, formats +objects+ into the string,
8563 * then writes the formatted string to $stdout:
8564 *
8565 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8566 *
8567 * Output (on $stdout):
8568 *
8569 * 0024 24 24.00#
8570 *
8571 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8572 * then writes the formatted string to +io+:
8573 *
8574 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8575 *
8576 * Output (on $stderr):
8577 *
8578 * 0024 24 24.00# => nil
8579 *
8580 * With no arguments, does nothing.
8581 *
8582 */
8583
8584static VALUE
8585rb_f_printf(int argc, VALUE *argv, VALUE _)
8586{
8587 VALUE out;
8588
8589 if (argc == 0) return Qnil;
8590 if (RB_TYPE_P(argv[0], T_STRING)) {
8591 out = rb_ractor_stdout();
8592 }
8593 else {
8594 out = argv[0];
8595 argv++;
8596 argc--;
8597 }
8598 rb_io_write(out, rb_f_sprintf(argc, argv));
8599
8600 return Qnil;
8601}
8602
8603static void
8604deprecated_str_setter(VALUE val, ID id, VALUE *var)
8605{
8606 rb_str_setter(val, id, &val);
8607 if (!NIL_P(val)) {
8608 rb_warn_deprecated("`%s'", NULL, rb_id2name(id));
8609 }
8610 *var = val;
8611}
8612
8613/*
8614 * call-seq:
8615 * print(*objects) -> nil
8616 *
8617 * Writes the given objects to the stream; returns +nil+.
8618 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8619 * (<tt>$\</tt>), if it is not +nil+.
8620 * See {Line IO}[rdoc-ref:IO@Line+IO].
8621 *
8622 * With argument +objects+ given, for each object:
8623 *
8624 * - Converts via its method +to_s+ if not a string.
8625 * - Writes to the stream.
8626 * - If not the last object, writes the output field separator
8627 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8628 *
8629 * With default separators:
8630 *
8631 * f = File.open('t.tmp', 'w+')
8632 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8633 * p $OUTPUT_RECORD_SEPARATOR
8634 * p $OUTPUT_FIELD_SEPARATOR
8635 * f.print(*objects)
8636 * f.rewind
8637 * p f.read
8638 * f.close
8639 *
8640 * Output:
8641 *
8642 * nil
8643 * nil
8644 * "00.00/10+0izerozero"
8645 *
8646 * With specified separators:
8647 *
8648 * $\ = "\n"
8649 * $, = ','
8650 * f.rewind
8651 * f.print(*objects)
8652 * f.rewind
8653 * p f.read
8654 *
8655 * Output:
8656 *
8657 * "0,0.0,0/1,0+0i,zero,zero\n"
8658 *
8659 * With no argument given, writes the content of <tt>$_</tt>
8660 * (which is usually the most recent user input):
8661 *
8662 * f = File.open('t.tmp', 'w+')
8663 * gets # Sets $_ to the most recent user input.
8664 * f.print
8665 * f.close
8666 *
8667 */
8668
8669 VALUE
8670rb_io_print(int argc, const VALUE *argv, VALUE out)
8671{
8672 int i;
8673 VALUE line;
8674
8675 /* if no argument given, print `$_' */
8676 if (argc == 0) {
8677 argc = 1;
8678 line = rb_lastline_get();
8679 argv = &line;
8680 }
8681 if (argc > 1 && !NIL_P(rb_output_fs)) {
8682 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8683 }
8684 for (i=0; i<argc; i++) {
8685 if (!NIL_P(rb_output_fs) && i>0) {
8686 rb_io_write(out, rb_output_fs);
8687 }
8688 rb_io_write(out, argv[i]);
8689 }
8690 if (argc > 0 && !NIL_P(rb_output_rs)) {
8691 rb_io_write(out, rb_output_rs);
8692 }
8693
8694 return Qnil;
8695}
8696
8697/*
8698 * call-seq:
8699 * print(*objects) -> nil
8700 *
8701 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8702 * this method is the straightforward way to write to <tt>$stdout</tt>.
8703 *
8704 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8705 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8706 * <tt>$\</tt>), if it is not +nil+.
8707 *
8708 * With argument +objects+ given, for each object:
8709 *
8710 * - Converts via its method +to_s+ if not a string.
8711 * - Writes to <tt>stdout</tt>.
8712 * - If not the last object, writes the output field separator
8713 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8714 *
8715 * With default separators:
8716 *
8717 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8718 * $OUTPUT_RECORD_SEPARATOR
8719 * $OUTPUT_FIELD_SEPARATOR
8720 * print(*objects)
8721 *
8722 * Output:
8723 *
8724 * nil
8725 * nil
8726 * 00.00/10+0izerozero
8727 *
8728 * With specified separators:
8729 *
8730 * $OUTPUT_RECORD_SEPARATOR = "\n"
8731 * $OUTPUT_FIELD_SEPARATOR = ','
8732 * print(*objects)
8733 *
8734 * Output:
8735 *
8736 * 0,0.0,0/1,0+0i,zero,zero
8737 *
8738 * With no argument given, writes the content of <tt>$_</tt>
8739 * (which is usually the most recent user input):
8740 *
8741 * gets # Sets $_ to the most recent user input.
8742 * print # Prints $_.
8743 *
8744 */
8745
8746static VALUE
8747rb_f_print(int argc, const VALUE *argv, VALUE _)
8748{
8749 rb_io_print(argc, argv, rb_ractor_stdout());
8750 return Qnil;
8751}
8752
8753/*
8754 * call-seq:
8755 * putc(object) -> object
8756 *
8757 * Writes a character to the stream.
8758 * See {Character IO}[rdoc-ref:IO@Character+IO].
8759 *
8760 * If +object+ is numeric, converts to integer if necessary,
8761 * then writes the character whose code is the
8762 * least significant byte;
8763 * if +object+ is a string, writes the first character:
8764 *
8765 * $stdout.putc "A"
8766 * $stdout.putc 65
8767 *
8768 * Output:
8769 *
8770 * AA
8771 *
8772 */
8773
8774static VALUE
8775rb_io_putc(VALUE io, VALUE ch)
8776{
8777 VALUE str;
8778 if (RB_TYPE_P(ch, T_STRING)) {
8779 str = rb_str_substr(ch, 0, 1);
8780 }
8781 else {
8782 char c = NUM2CHR(ch);
8783 str = rb_str_new(&c, 1);
8784 }
8785 rb_io_write(io, str);
8786 return ch;
8787}
8788
8789#define forward(obj, id, argc, argv) \
8790 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8791#define forward_public(obj, id, argc, argv) \
8792 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8793#define forward_current(id, argc, argv) \
8794 forward_public(ARGF.current_file, id, argc, argv)
8795
8796/*
8797 * call-seq:
8798 * putc(int) -> int
8799 *
8800 * Equivalent to:
8801 *
8802 * $stdout.putc(int)
8803 *
8804 * See IO#putc for important information regarding multi-byte characters.
8805 *
8806 */
8807
8808static VALUE
8809rb_f_putc(VALUE recv, VALUE ch)
8810{
8811 VALUE r_stdout = rb_ractor_stdout();
8812 if (recv == r_stdout) {
8813 return rb_io_putc(recv, ch);
8814 }
8815 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8816}
8817
8818
8819int
8820rb_str_end_with_asciichar(VALUE str, int c)
8821{
8822 long len = RSTRING_LEN(str);
8823 const char *ptr = RSTRING_PTR(str);
8824 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8825 int n;
8826
8827 if (len == 0) return 0;
8828 if ((n = rb_enc_mbminlen(enc)) == 1) {
8829 return ptr[len - 1] == c;
8830 }
8831 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8832}
8833
8834static VALUE
8835io_puts_ary(VALUE ary, VALUE out, int recur)
8836{
8837 VALUE tmp;
8838 long i;
8839
8840 if (recur) {
8841 tmp = rb_str_new2("[...]");
8842 rb_io_puts(1, &tmp, out);
8843 return Qtrue;
8844 }
8845 ary = rb_check_array_type(ary);
8846 if (NIL_P(ary)) return Qfalse;
8847 for (i=0; i<RARRAY_LEN(ary); i++) {
8848 tmp = RARRAY_AREF(ary, i);
8849 rb_io_puts(1, &tmp, out);
8850 }
8851 return Qtrue;
8852}
8853
8854/*
8855 * call-seq:
8856 * puts(*objects) -> nil
8857 *
8858 * Writes the given +objects+ to the stream, which must be open for writing;
8859 * returns +nil+.\
8860 * Writes a newline after each that does not already end with a newline sequence.
8861 * If called without arguments, writes a newline.
8862 * See {Line IO}[rdoc-ref:IO@Line+IO].
8863 *
8864 * Note that each added newline is the character <tt>"\n"<//tt>,
8865 * not the output record separator (<tt>$\</tt>).
8866 *
8867 * Treatment for each object:
8868 *
8869 * - \String: writes the string.
8870 * - Neither string nor array: writes <tt>object.to_s</tt>.
8871 * - \Array: writes each element of the array; arrays may be nested.
8872 *
8873 * To keep these examples brief, we define this helper method:
8874 *
8875 * def show(*objects)
8876 * # Puts objects to file.
8877 * f = File.new('t.tmp', 'w+')
8878 * f.puts(objects)
8879 * # Return file content.
8880 * f.rewind
8881 * p f.read
8882 * f.close
8883 * end
8884 *
8885 * # Strings without newlines.
8886 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8887 * # Strings, some with newlines.
8888 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8889 *
8890 * # Neither strings nor arrays:
8891 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8892 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8893 *
8894 * # Array of strings.
8895 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8896 * # Nested arrays.
8897 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8898 *
8899 */
8900
8901 VALUE
8902rb_io_puts(int argc, const VALUE *argv, VALUE out)
8903{
8904 VALUE line, args[2];
8905
8906 /* if no argument given, print newline. */
8907 if (argc == 0) {
8908 rb_io_write(out, rb_default_rs);
8909 return Qnil;
8910 }
8911 for (int i = 0; i < argc; i++) {
8912 // Convert the argument to a string:
8913 if (RB_TYPE_P(argv[i], T_STRING)) {
8914 line = argv[i];
8915 }
8916 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8917 continue;
8918 }
8919 else {
8920 line = rb_obj_as_string(argv[i]);
8921 }
8922
8923 // Write the line:
8924 int n = 0;
8925 if (RSTRING_LEN(line) == 0) {
8926 args[n++] = rb_default_rs;
8927 }
8928 else {
8929 args[n++] = line;
8930 if (!rb_str_end_with_asciichar(line, '\n')) {
8931 args[n++] = rb_default_rs;
8932 }
8933 }
8934
8935 rb_io_writev(out, n, args);
8936 }
8937
8938 return Qnil;
8939}
8940
8941/*
8942 * call-seq:
8943 * puts(*objects) -> nil
8944 *
8945 * Equivalent to
8946 *
8947 * $stdout.puts(objects)
8948 */
8949
8950static VALUE
8951rb_f_puts(int argc, VALUE *argv, VALUE recv)
8952{
8953 VALUE r_stdout = rb_ractor_stdout();
8954 if (recv == r_stdout) {
8955 return rb_io_puts(argc, argv, recv);
8956 }
8957 return forward(r_stdout, rb_intern("puts"), argc, argv);
8958}
8959
8960static VALUE
8961rb_p_write(VALUE str)
8962{
8963 VALUE args[2];
8964 args[0] = str;
8965 args[1] = rb_default_rs;
8966 VALUE r_stdout = rb_ractor_stdout();
8967 if (RB_TYPE_P(r_stdout, T_FILE) &&
8968 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
8969 io_writev(2, args, r_stdout);
8970 }
8971 else {
8972 rb_io_writev(r_stdout, 2, args);
8973 }
8974 return Qnil;
8975}
8976
8977void
8978rb_p(VALUE obj) /* for debug print within C code */
8979{
8980 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
8981}
8982
8983static VALUE
8984rb_p_result(int argc, const VALUE *argv)
8985{
8986 VALUE ret = Qnil;
8987
8988 if (argc == 1) {
8989 ret = argv[0];
8990 }
8991 else if (argc > 1) {
8992 ret = rb_ary_new4(argc, argv);
8993 }
8994 VALUE r_stdout = rb_ractor_stdout();
8995 if (RB_TYPE_P(r_stdout, T_FILE)) {
8996 rb_uninterruptible(rb_io_flush, r_stdout);
8997 }
8998 return ret;
8999}
9000
9001/*
9002 * call-seq:
9003 * p(object) -> obj
9004 * p(*objects) -> array of objects
9005 * p -> nil
9006 *
9007 * For each object +obj+, executes:
9008 *
9009 * $stdout.write(obj.inspect, "\n")
9010 *
9011 * With one object given, returns the object;
9012 * with multiple objects given, returns an array containing the objects;
9013 * with no object given, returns +nil+.
9014 *
9015 * Examples:
9016 *
9017 * r = Range.new(0, 4)
9018 * p r # => 0..4
9019 * p [r, r, r] # => [0..4, 0..4, 0..4]
9020 * p # => nil
9021 *
9022 * Output:
9023 *
9024 * 0..4
9025 * [0..4, 0..4, 0..4]
9026 *
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
9180prep_io(int fd, int fmode, VALUE klass, const char *path)
9181{
9182 rb_io_t *fp;
9183 VALUE io = io_alloc(klass);
9184
9185 MakeOpenFile(io, fp);
9186 fp->self = io;
9187 fp->fd = fd;
9188 fp->mode = fmode;
9189 fp->timeout = Qnil;
9190 if (!io_check_tty(fp)) {
9191#ifdef __CYGWIN__
9192 fp->mode |= FMODE_BINMODE;
9193 setmode(fd, O_BINARY);
9194#endif
9195 }
9196 if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
9197 rb_update_max_fd(fd);
9198
9199 return io;
9200}
9201
9202 VALUE
9203rb_io_fdopen(int fd, int oflags, const char *path)
9204{
9205 VALUE klass = rb_cIO;
9206
9207 if (path && strcmp(path, "-")) klass = rb_cFile;
9208 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9209}
9210
9211static VALUE
9212prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9213{
9214 rb_io_t *fptr;
9215 VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
9216
9217 GetOpenFile(io, fptr);
9218 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
9219#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9220 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9221 if (fmode & FMODE_READABLE) {
9222 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
9223 }
9224#endif
9225 fptr->stdio_file = f;
9226
9227 return io;
9228}
9229
9230 VALUE
9231rb_io_prep_stdin(void)
9232{
9233 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9234}
9235
9236 VALUE
9237rb_io_prep_stdout(void)
9238{
9239 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9240}
9241
9242 VALUE
9243rb_io_prep_stderr(void)
9244{
9245 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9246}
9247
9248 FILE *
9249rb_io_stdio_file(rb_io_t *fptr)
9250{
9251 if (!fptr->stdio_file) {
9252 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9253 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9254 }
9255 return fptr->stdio_file;
9256}
9257
9258static inline void
9259rb_io_buffer_init(rb_io_buffer_t *buf)
9260{
9261 buf->ptr = NULL;
9262 buf->off = 0;
9263 buf->len = 0;
9264 buf->capa = 0;
9265}
9266
9267static inline rb_io_t *
9268rb_io_fptr_new(void)
9269{
9270 rb_io_t *fp = ALLOC(rb_io_t);
9271 fp->self = Qnil;
9272 fp->fd = -1;
9273 fp->stdio_file = NULL;
9274 fp->mode = 0;
9275 fp->pid = 0;
9276 fp->lineno = 0;
9277 fp->pathv = Qnil;
9278 fp->finalize = 0;
9279 rb_io_buffer_init(&fp->wbuf);
9280 rb_io_buffer_init(&fp->rbuf);
9281 rb_io_buffer_init(&fp->cbuf);
9282 fp->readconv = NULL;
9283 fp->writeconv = NULL;
9284 fp->writeconv_asciicompat = Qnil;
9285 fp->writeconv_pre_ecflags = 0;
9286 fp->writeconv_pre_ecopts = Qnil;
9287 fp->writeconv_initialized = 0;
9288 fp->tied_io_for_writing = 0;
9289 fp->encs.enc = NULL;
9290 fp->encs.enc2 = NULL;
9291 fp->encs.ecflags = 0;
9292 fp->encs.ecopts = Qnil;
9293 fp->write_lock = Qnil;
9294 fp->timeout = Qnil;
9295 return fp;
9296}
9297
9298 rb_io_t *
9299rb_io_make_open_file(VALUE obj)
9300{
9301 rb_io_t *fp = 0;
9302
9303 Check_Type(obj, T_FILE);
9304 if (RFILE(obj)->fptr) {
9305 rb_io_close(obj);
9306 rb_io_fptr_finalize(RFILE(obj)->fptr);
9307 RFILE(obj)->fptr = 0;
9308 }
9309 fp = rb_io_fptr_new();
9310 fp->self = obj;
9311 RFILE(obj)->fptr = fp;
9312 return fp;
9313}
9314
9315/*
9316 * call-seq:
9317 * IO.new(fd, mode = 'r', **opts) -> io
9318 *
9319 * Creates and returns a new \IO object (file stream) from a file descriptor.
9320 *
9321 * \IO.new may be useful for interaction with low-level libraries.
9322 * For higher-level interactions, it may be simpler to create
9323 * the file stream using File.open.
9324 *
9325 * Argument +fd+ must be a valid file descriptor (integer):
9326 *
9327 * path = 't.tmp'
9328 * fd = IO.sysopen(path) # => 3
9329 * IO.new(fd) # => #<IO:fd 3>
9330 *
9331 * The new \IO object does not inherit encoding
9332 * (because the integer file descriptor does not have an encoding):
9333 *
9334 * fd = IO.sysopen('t.rus', 'rb')
9335 * io = IO.new(fd)
9336 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9337 *
9338 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9339 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9340 *
9341 * IO.new(fd, 'w') # => #<IO:fd 3>
9342 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9343 *
9344 * Optional keyword arguments +opts+ specify:
9345 *
9346 * - {Open Options}[rdoc-ref:IO@Open+Options].
9347 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9348 *
9349 * Examples:
9350 *
9351 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9352 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9353 *
9354 */
9355
9356static VALUE
9357rb_io_initialize(int argc, VALUE *argv, VALUE io)
9358{
9359 VALUE fnum, vmode;
9360 rb_io_t *fp;
9361 int fd, fmode, oflags = O_RDONLY;
9362 convconfig_t convconfig;
9363 VALUE opt;
9364#if defined(HAVE_FCNTL) && defined(F_GETFL)
9365 int ofmode;
9366#else
9367 struct stat st;
9368#endif
9369
9370
9371 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9372 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9373
9374 fd = NUM2INT(fnum);
9375 if (rb_reserved_fd_p(fd)) {
9376 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9377 }
9378#if defined(HAVE_FCNTL) && defined(F_GETFL)
9379 oflags = fcntl(fd, F_GETFL);
9380 if (oflags == -1) rb_sys_fail(0);
9381#else
9382 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9383#endif
9384 rb_update_max_fd(fd);
9385#if defined(HAVE_FCNTL) && defined(F_GETFL)
9386 ofmode = rb_io_oflags_fmode(oflags);
9387 if (NIL_P(vmode)) {
9388 fmode = ofmode;
9389 }
9390 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9391 VALUE error = INT2FIX(EINVAL);
9392 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
9393 }
9394#endif
9395 VALUE path = Qnil;
9396
9397 if (!NIL_P(opt)) {
9398 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9399 fmode |= FMODE_PREP;
9400 }
9401
9402 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9403 if (!NIL_P(path)) {
9404 StringValue(path);
9405 path = rb_str_new_frozen(path);
9406 }
9407 }
9408
9409 MakeOpenFile(io, fp);
9410 fp->self = io;
9411 fp->fd = fd;
9412 fp->mode = fmode;
9413 fp->encs = convconfig;
9414 fp->pathv = path;
9415 fp->timeout = Qnil;
9416 clear_codeconv(fp);
9417 io_check_tty(fp);
9418 if (fileno(stdin) == fd)
9419 fp->stdio_file = stdin;
9420 else if (fileno(stdout) == fd)
9421 fp->stdio_file = stdout;
9422 else if (fileno(stderr) == fd)
9423 fp->stdio_file = stderr;
9424
9425 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9426 return io;
9427}
9428
9429/*
9430 * call-seq:
9431 * set_encoding_by_bom -> encoding or nil
9432 *
9433 * If the stream begins with a BOM
9434 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9435 * consumes the BOM and sets the external encoding accordingly;
9436 * returns the result encoding if found, or +nil+ otherwise:
9437 *
9438 * File.write('t.tmp', "\u{FEFF}abc")
9439 * io = File.open('t.tmp', 'rb')
9440 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9441 * io.close
9442 *
9443 * File.write('t.tmp', 'abc')
9444 * io = File.open('t.tmp', 'rb')
9445 * io.set_encoding_by_bom # => nil
9446 * io.close
9447 *
9448 * Raises an exception if the stream is not binmode
9449 * or its encoding has already been set.
9450 *
9451 */
9452
9453static VALUE
9454rb_io_set_encoding_by_bom(VALUE io)
9455{
9456 rb_io_t *fptr;
9457
9458 GetOpenFile(io, fptr);
9459 if (!(fptr->mode & FMODE_BINMODE)) {
9460 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9461 }
9462 if (fptr->encs.enc2) {
9463 rb_raise(rb_eArgError, "encoding conversion is set");
9464 }
9465 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9466 rb_raise(rb_eArgError, "encoding is set to %s already",
9467 rb_enc_name(fptr->encs.enc));
9468 }
9469 if (!io_set_encoding_by_bom(io)) return Qnil;
9470 return rb_enc_from_encoding(fptr->encs.enc);
9471}
9472
9473/*
9474 * call-seq:
9475 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9476 *
9477 * Opens the file at the given +path+ according to the given +mode+;
9478 * creates and returns a new \File object for that file.
9479 *
9480 * The new \File object is buffered mode (or non-sync mode), unless
9481 * +filename+ is a tty.
9482 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9483 *
9484 * Argument +path+ must be a valid file path:
9485 *
9486 * f = File.new('/etc/fstab')
9487 * f.close
9488 * f = File.new('t.txt')
9489 * f.close
9490 *
9491 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9492 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9493 *
9494 * f = File.new('t.tmp', 'w')
9495 * f.close
9496 * f = File.new('t.tmp', File::RDONLY)
9497 * f.close
9498 *
9499 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9500 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9501 *
9502 * f = File.new('t.tmp', File::CREAT, 0644)
9503 * f.close
9504 * f = File.new('t.tmp', File::CREAT, 0444)
9505 * f.close
9506 *
9507 * Optional keyword arguments +opts+ specify:
9508 *
9509 * - {Open Options}[rdoc-ref:IO@Open+Options].
9510 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9511 *
9512 */
9513
9514static VALUE
9515rb_file_initialize(int argc, VALUE *argv, VALUE io)
9516{
9517 if (RFILE(io)->fptr) {
9518 rb_raise(rb_eRuntimeError, "reinitializing File");
9519 }
9520 if (0 < argc && argc < 3) {
9521 VALUE fd = rb_check_to_int(argv[0]);
9522
9523 if (!NIL_P(fd)) {
9524 argv[0] = fd;
9525 return rb_io_initialize(argc, argv, io);
9526 }
9527 }
9528 rb_open_file(argc, argv, io);
9529
9530 return io;
9531}
9532
9533/* :nodoc: */
9534static VALUE
9535rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9536{
9537 if (rb_block_given_p()) {
9538 VALUE cname = rb_obj_as_string(klass);
9539
9540 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9541 cname, cname);
9542 }
9543 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9544}
9545
9546
9547/*
9548 * call-seq:
9549 * IO.for_fd(fd, mode = 'r', **opts) -> io
9550 *
9551 * Synonym for IO.new.
9552 *
9553 */
9554
9555static VALUE
9556rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9557{
9558 VALUE io = rb_obj_alloc(klass);
9559 rb_io_initialize(argc, argv, io);
9560 return io;
9561}
9562
9563/*
9564 * call-seq:
9565 * ios.autoclose? -> true or false
9566 *
9567 * Returns +true+ if the underlying file descriptor of _ios_ will be
9568 * closed automatically at its finalization, otherwise +false+.
9569 */
9570
9571static VALUE
9572rb_io_autoclose_p(VALUE io)
9573{
9574 rb_io_t *fptr = RFILE(io)->fptr;
9575 rb_io_check_closed(fptr);
9576 return RBOOL(!(fptr->mode & FMODE_PREP));
9577}
9578
9579/*
9580 * call-seq:
9581 * io.autoclose = bool -> true or false
9582 *
9583 * Sets auto-close flag.
9584 *
9585 * f = open("/dev/null")
9586 * IO.for_fd(f.fileno)
9587 * # ...
9588 * f.gets # may cause Errno::EBADF
9589 *
9590 * f = open("/dev/null")
9591 * IO.for_fd(f.fileno).autoclose = false
9592 * # ...
9593 * f.gets # won't cause Errno::EBADF
9594 */
9595
9596static VALUE
9597rb_io_set_autoclose(VALUE io, VALUE autoclose)
9598{
9599 rb_io_t *fptr;
9600 GetOpenFile(io, fptr);
9601 if (!RTEST(autoclose))
9602 fptr->mode |= FMODE_PREP;
9603 else
9604 fptr->mode &= ~FMODE_PREP;
9605 return autoclose;
9606}
9607
9608static VALUE
9609io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9610{
9611 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9612
9613 if (!RB_TEST(result)) {
9614 return Qnil;
9615 }
9616
9617 int mask = RB_NUM2INT(result);
9618
9619 if (mask & event) {
9620 if (return_io)
9621 return io;
9622 else
9623 return result;
9624 }
9625 else {
9626 return Qfalse;
9627 }
9628}
9629
9630/*
9631 * call-seq:
9632 * io.wait_readable -> truthy or falsy
9633 * io.wait_readable(timeout) -> truthy or falsy
9634 *
9635 * Waits until IO is readable and returns a truthy value, or a falsy
9636 * value when times out. Returns a truthy value immediately when
9637 * buffered data is available.
9638 */
9639
9640static VALUE
9641io_wait_readable(int argc, VALUE *argv, VALUE io)
9642{
9643 rb_io_t *fptr;
9644
9645 RB_IO_POINTER(io, fptr);
9646 rb_io_check_readable(fptr);
9647
9648 if (rb_io_read_pending(fptr)) return Qtrue;
9649
9650 rb_check_arity(argc, 0, 1);
9651 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9652
9653 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9654}
9655
9656/*
9657 * call-seq:
9658 * io.wait_writable -> truthy or falsy
9659 * io.wait_writable(timeout) -> truthy or falsy
9660 *
9661 * Waits until IO is writable and returns a truthy value or a falsy
9662 * value when times out.
9663 */
9664static VALUE
9665io_wait_writable(int argc, VALUE *argv, VALUE io)
9666{
9667 rb_io_t *fptr;
9668
9669 RB_IO_POINTER(io, fptr);
9670 rb_io_check_writable(fptr);
9671
9672 rb_check_arity(argc, 0, 1);
9673 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9674
9675 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9676}
9677
9678/*
9679 * call-seq:
9680 * io.wait_priority -> truthy or falsy
9681 * io.wait_priority(timeout) -> truthy or falsy
9682 *
9683 * Waits until IO is priority and returns a truthy value or a falsy
9684 * value when times out. Priority data is sent and received using
9685 * the Socket::MSG_OOB flag and is typically limited to streams.
9686 */
9687static VALUE
9688io_wait_priority(int argc, VALUE *argv, VALUE io)
9689{
9690 rb_io_t *fptr = NULL;
9691
9692 RB_IO_POINTER(io, fptr);
9693 rb_io_check_readable(fptr);
9694
9695 if (rb_io_read_pending(fptr)) return Qtrue;
9696
9697 rb_check_arity(argc, 0, 1);
9698 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9699
9700 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9701}
9702
9703static int
9704wait_mode_sym(VALUE mode)
9705{
9706 if (mode == ID2SYM(rb_intern("r"))) {
9707 return RB_WAITFD_IN;
9708 }
9709 if (mode == ID2SYM(rb_intern("read"))) {
9710 return RB_WAITFD_IN;
9711 }
9712 if (mode == ID2SYM(rb_intern("readable"))) {
9713 return RB_WAITFD_IN;
9714 }
9715 if (mode == ID2SYM(rb_intern("w"))) {
9716 return RB_WAITFD_OUT;
9717 }
9718 if (mode == ID2SYM(rb_intern("write"))) {
9719 return RB_WAITFD_OUT;
9720 }
9721 if (mode == ID2SYM(rb_intern("writable"))) {
9722 return RB_WAITFD_OUT;
9723 }
9724 if (mode == ID2SYM(rb_intern("rw"))) {
9725 return RB_WAITFD_IN|RB_WAITFD_OUT;
9726 }
9727 if (mode == ID2SYM(rb_intern("read_write"))) {
9728 return RB_WAITFD_IN|RB_WAITFD_OUT;
9729 }
9730 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9731 return RB_WAITFD_IN|RB_WAITFD_OUT;
9732 }
9733
9734 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9735}
9736
9737static inline rb_io_event_t
9738io_event_from_value(VALUE value)
9739{
9740 int events = RB_NUM2INT(value);
9741
9742 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9743
9744 return events;
9745}
9746
9747/*
9748 * call-seq:
9749 * io.wait(events, timeout) -> event mask, false or nil
9750 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9751 *
9752 * Waits until the IO becomes ready for the specified events and returns the
9753 * subset of events that become ready, or a falsy value when times out.
9754 *
9755 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9756 * +IO::PRIORITY+.
9757 *
9758 * Returns an event mask (truthy value) immediately when buffered data is available.
9759 *
9760 * Optional parameter +mode+ is one of +:read+, +:write+, or
9761 * +:read_write+.
9762 */
9763
9764static VALUE
9765io_wait(int argc, VALUE *argv, VALUE io)
9766{
9767 VALUE timeout = Qundef;
9768 rb_io_event_t events = 0;
9769 int return_io = 0;
9770
9771 // The documented signature for this method is actually incorrect.
9772 // A single timeout is allowed in any position, and multiple symbols can be given.
9773 // Whether this is intentional or not, I don't know, and as such I consider this to
9774 // be a legacy/slow path.
9775 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9776 // We'd prefer to return the actual mask, but this form would return the io itself:
9777 return_io = 1;
9778
9779 // Slow/messy path:
9780 for (int i = 0; i < argc; i += 1) {
9781 if (RB_SYMBOL_P(argv[i])) {
9782 events |= wait_mode_sym(argv[i]);
9783 }
9784 else if (UNDEF_P(timeout)) {
9785 rb_time_interval(timeout = argv[i]);
9786 }
9787 else {
9788 rb_raise(rb_eArgError, "timeout given more than once");
9789 }
9790 }
9791
9792 if (UNDEF_P(timeout)) timeout = Qnil;
9793
9794 if (events == 0) {
9795 events = RUBY_IO_READABLE;
9796 }
9797 }
9798 else /* argc == 2 and neither are symbols */ {
9799 // This is the fast path:
9800 events = io_event_from_value(argv[0]);
9801 timeout = argv[1];
9802 }
9803
9804 if (events & RUBY_IO_READABLE) {
9805 rb_io_t *fptr = NULL;
9806 RB_IO_POINTER(io, fptr);
9807
9808 if (rb_io_read_pending(fptr)) {
9809 // This was the original behaviour:
9810 if (return_io) return Qtrue;
9811 // New behaviour always returns an event mask:
9812 else return RB_INT2NUM(RUBY_IO_READABLE);
9813 }
9814 }
9815
9816 return io_wait_event(io, events, timeout, return_io);
9817}
9818
9819static void
9820argf_mark(void *ptr)
9821{
9822 struct argf *p = ptr;
9823 rb_gc_mark(p->filename);
9824 rb_gc_mark(p->current_file);
9825 rb_gc_mark(p->argv);
9826 rb_gc_mark(p->inplace);
9827 rb_gc_mark(p->encs.ecopts);
9828}
9829
9830static size_t
9831argf_memsize(const void *ptr)
9832{
9833 const struct argf *p = ptr;
9834 size_t size = sizeof(*p);
9835 return size;
9836}
9837
9838static const rb_data_type_t argf_type = {
9839 "ARGF",
9840 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9841 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9842};
9843
9844static inline void
9845argf_init(struct argf *p, VALUE v)
9846{
9847 p->filename = Qnil;
9848 p->current_file = Qnil;
9849 p->lineno = 0;
9850 p->argv = v;
9851}
9852
9853static VALUE
9854argf_alloc(VALUE klass)
9855{
9856 struct argf *p;
9857 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9858
9859 argf_init(p, Qnil);
9860 return argf;
9861}
9862
9863#undef rb_argv
9864
9865/* :nodoc: */
9866static VALUE
9867argf_initialize(VALUE argf, VALUE argv)
9868{
9869 memset(&ARGF, 0, sizeof(ARGF));
9870 argf_init(&ARGF, argv);
9871
9872 return argf;
9873}
9874
9875/* :nodoc: */
9876static VALUE
9877argf_initialize_copy(VALUE argf, VALUE orig)
9878{
9879 if (!OBJ_INIT_COPY(argf, orig)) return argf;
9880 ARGF = argf_of(orig);
9881 ARGF.argv = rb_obj_dup(ARGF.argv);
9882 return argf;
9883}
9884
9885/*
9886 * call-seq:
9887 * ARGF.lineno = integer -> integer
9888 *
9889 * Sets the line number of ARGF as a whole to the given Integer.
9890 *
9891 * ARGF sets the line number automatically as you read data, so normally
9892 * you will not need to set it explicitly. To access the current line number
9893 * use ARGF.lineno.
9894 *
9895 * For example:
9896 *
9897 * ARGF.lineno #=> 0
9898 * ARGF.readline #=> "This is line 1\n"
9899 * ARGF.lineno #=> 1
9900 * ARGF.lineno = 0 #=> 0
9901 * ARGF.lineno #=> 0
9902 */
9903static VALUE
9904argf_set_lineno(VALUE argf, VALUE val)
9905{
9906 ARGF.lineno = NUM2INT(val);
9907 ARGF.last_lineno = ARGF.lineno;
9908 return val;
9909}
9910
9911/*
9912 * call-seq:
9913 * ARGF.lineno -> integer
9914 *
9915 * Returns the current line number of ARGF as a whole. This value
9916 * can be set manually with ARGF.lineno=.
9917 *
9918 * For example:
9919 *
9920 * ARGF.lineno #=> 0
9921 * ARGF.readline #=> "This is line 1\n"
9922 * ARGF.lineno #=> 1
9923 */
9924static VALUE
9925argf_lineno(VALUE argf)
9926{
9927 return INT2FIX(ARGF.lineno);
9928}
9929
9930static VALUE
9931argf_forward(int argc, VALUE *argv, VALUE argf)
9932{
9933 return forward_current(rb_frame_this_func(), argc, argv);
9934}
9935
9936#define next_argv() argf_next_argv(argf)
9937#define ARGF_GENERIC_INPUT_P() \
9938 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
9939#define ARGF_FORWARD(argc, argv) do {\
9940 if (ARGF_GENERIC_INPUT_P())\
9941 return argf_forward((argc), (argv), argf);\
9942} while (0)
9943#define NEXT_ARGF_FORWARD(argc, argv) do {\
9944 if (!next_argv()) return Qnil;\
9945 ARGF_FORWARD((argc), (argv));\
9946} while (0)
9947
9948static void
9949argf_close(VALUE argf)
9950{
9951 VALUE file = ARGF.current_file;
9952 if (file == rb_stdin) return;
9953 if (RB_TYPE_P(file, T_FILE)) {
9954 rb_io_set_write_io(file, Qnil);
9955 }
9956 io_close(file);
9957 ARGF.init_p = -1;
9958}
9959
9960static int
9961argf_next_argv(VALUE argf)
9962{
9963 char *fn;
9964 rb_io_t *fptr;
9965 int stdout_binmode = 0;
9966 int fmode;
9967
9968 VALUE r_stdout = rb_ractor_stdout();
9969
9970 if (RB_TYPE_P(r_stdout, T_FILE)) {
9971 GetOpenFile(r_stdout, fptr);
9972 if (fptr->mode & FMODE_BINMODE)
9973 stdout_binmode = 1;
9974 }
9975
9976 if (ARGF.init_p == 0) {
9977 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
9978 ARGF.next_p = 1;
9979 }
9980 else {
9981 ARGF.next_p = -1;
9982 }
9983 ARGF.init_p = 1;
9984 }
9985 else {
9986 if (NIL_P(ARGF.argv)) {
9987 ARGF.next_p = -1;
9988 }
9989 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
9990 ARGF.next_p = 1;
9991 }
9992 }
9993
9994 if (ARGF.next_p == 1) {
9995 if (ARGF.init_p == 1) argf_close(argf);
9996 retry:
9997 if (RARRAY_LEN(ARGF.argv) > 0) {
9998 VALUE filename = rb_ary_shift(ARGF.argv);
9999 FilePathValue(filename);
10000 ARGF.filename = filename;
10001 filename = rb_str_encode_ospath(filename);
10002 fn = StringValueCStr(filename);
10003 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10004 ARGF.current_file = rb_stdin;
10005 if (ARGF.inplace) {
10006 rb_warn("Can't do inplace edit for stdio; skipping");
10007 goto retry;
10008 }
10009 }
10010 else {
10011 VALUE write_io = Qnil;
10012 int fr = rb_sysopen(filename, O_RDONLY, 0);
10013
10014 if (ARGF.inplace) {
10015 struct stat st;
10016#ifndef NO_SAFE_RENAME
10017 struct stat st2;
10018#endif
10019 VALUE str;
10020 int fw;
10021
10022 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10023 rb_io_close(r_stdout);
10024 }
10025 fstat(fr, &st);
10026 str = filename;
10027 if (!NIL_P(ARGF.inplace)) {
10028 VALUE suffix = ARGF.inplace;
10029 str = rb_str_dup(str);
10030 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10031 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10032 rb_enc_get(suffix), 0, Qnil))) {
10033 rb_str_append(str, suffix);
10034 }
10035#ifdef NO_SAFE_RENAME
10036 (void)close(fr);
10037 (void)unlink(RSTRING_PTR(str));
10038 if (rename(fn, RSTRING_PTR(str)) < 0) {
10039 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10040 filename, str, strerror(errno));
10041 goto retry;
10042 }
10043 fr = rb_sysopen(str, O_RDONLY, 0);
10044#else
10045 if (rename(fn, RSTRING_PTR(str)) < 0) {
10046 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10047 filename, str, strerror(errno));
10048 close(fr);
10049 goto retry;
10050 }
10051#endif
10052 }
10053 else {
10054#ifdef NO_SAFE_RENAME
10055 rb_fatal("Can't do inplace edit without backup");
10056#else
10057 if (unlink(fn) < 0) {
10058 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10059 filename, strerror(errno));
10060 close(fr);
10061 goto retry;
10062 }
10063#endif
10064 }
10065 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10066#ifndef NO_SAFE_RENAME
10067 fstat(fw, &st2);
10068#ifdef HAVE_FCHMOD
10069 fchmod(fw, st.st_mode);
10070#else
10071 chmod(fn, st.st_mode);
10072#endif
10073 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10074 int err;
10075#ifdef HAVE_FCHOWN
10076 err = fchown(fw, st.st_uid, st.st_gid);
10077#else
10078 err = chown(fn, st.st_uid, st.st_gid);
10079#endif
10080 if (err && getuid() == 0 && st2.st_uid == 0) {
10081 const char *wkfn = RSTRING_PTR(filename);
10082 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10083 filename, str, strerror(errno));
10084 (void)close(fr);
10085 (void)close(fw);
10086 (void)unlink(wkfn);
10087 goto retry;
10088 }
10089 }
10090#endif
10091 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10092 rb_ractor_stdout_set(write_io);
10093 if (stdout_binmode) rb_io_binmode(rb_stdout);
10094 }
10095 fmode = FMODE_READABLE;
10096 if (!ARGF.binmode) {
10097 fmode |= DEFAULT_TEXTMODE;
10098 }
10099 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10100 if (!NIL_P(write_io)) {
10101 rb_io_set_write_io(ARGF.current_file, write_io);
10102 }
10103 RB_GC_GUARD(filename);
10104 }
10105 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10106 GetOpenFile(ARGF.current_file, fptr);
10107 if (ARGF.encs.enc) {
10108 fptr->encs = ARGF.encs;
10109 clear_codeconv(fptr);
10110 }
10111 else {
10112 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10113 if (!ARGF.binmode) {
10114 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
10115#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10116 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10117#endif
10118 }
10119 }
10120 ARGF.next_p = 0;
10121 }
10122 else {
10123 ARGF.next_p = 1;
10124 return FALSE;
10125 }
10126 }
10127 else if (ARGF.next_p == -1) {
10128 ARGF.current_file = rb_stdin;
10129 ARGF.filename = rb_str_new2("-");
10130 if (ARGF.inplace) {
10131 rb_warn("Can't do inplace edit for stdio");
10132 rb_ractor_stdout_set(orig_stdout);
10133 }
10134 }
10135 if (ARGF.init_p == -1) ARGF.init_p = 1;
10136 return TRUE;
10137}
10138
10139static VALUE
10140argf_getline(int argc, VALUE *argv, VALUE argf)
10141{
10142 VALUE line;
10143 long lineno = ARGF.lineno;
10144
10145 retry:
10146 if (!next_argv()) return Qnil;
10147 if (ARGF_GENERIC_INPUT_P()) {
10148 line = forward_current(idGets, argc, argv);
10149 }
10150 else {
10151 if (argc == 0 && rb_rs == rb_default_rs) {
10152 line = rb_io_gets(ARGF.current_file);
10153 }
10154 else {
10155 line = rb_io_getline(argc, argv, ARGF.current_file);
10156 }
10157 if (NIL_P(line) && ARGF.next_p != -1) {
10158 argf_close(argf);
10159 ARGF.next_p = 1;
10160 goto retry;
10161 }
10162 }
10163 if (!NIL_P(line)) {
10164 ARGF.lineno = ++lineno;
10165 ARGF.last_lineno = ARGF.lineno;
10166 }
10167 return line;
10168}
10169
10170static VALUE
10171argf_lineno_getter(ID id, VALUE *var)
10172{
10173 VALUE argf = *var;
10174 return INT2FIX(ARGF.last_lineno);
10175}
10176
10177static void
10178argf_lineno_setter(VALUE val, ID id, VALUE *var)
10179{
10180 VALUE argf = *var;
10181 int n = NUM2INT(val);
10182 ARGF.last_lineno = ARGF.lineno = n;
10183}
10184
10185void
10186rb_reset_argf_lineno(long n)
10187{
10188 ARGF.last_lineno = ARGF.lineno = n;
10189}
10190
10191static VALUE argf_gets(int, VALUE *, VALUE);
10192
10193/*
10194 * call-seq:
10195 * gets(sep=$/ [, getline_args]) -> string or nil
10196 * gets(limit [, getline_args]) -> string or nil
10197 * gets(sep, limit [, getline_args]) -> string or nil
10198 *
10199 * Returns (and assigns to <code>$_</code>) the next line from the list
10200 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10201 * no files are present on the command line. Returns +nil+ at end of
10202 * file. The optional argument specifies the record separator. The
10203 * separator is included with the contents of each record. A separator
10204 * of +nil+ reads the entire contents, and a zero-length separator
10205 * reads the input one paragraph at a time, where paragraphs are
10206 * divided by two consecutive newlines. If the first argument is an
10207 * integer, or optional second argument is given, the returning string
10208 * would not be longer than the given value in bytes. If multiple
10209 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10210 * the contents one file at a time.
10211 *
10212 * ARGV << "testfile"
10213 * print while gets
10214 *
10215 * <em>produces:</em>
10216 *
10217 * This is line one
10218 * This is line two
10219 * This is line three
10220 * And so on...
10221 *
10222 * The style of programming using <code>$_</code> as an implicit
10223 * parameter is gradually losing favor in the Ruby community.
10224 */
10225
10226static VALUE
10227rb_f_gets(int argc, VALUE *argv, VALUE recv)
10228{
10229 if (recv == argf) {
10230 return argf_gets(argc, argv, argf);
10231 }
10232 return forward(argf, idGets, argc, argv);
10233}
10234
10235/*
10236 * call-seq:
10237 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10238 * ARGF.gets(limit [, getline_args]) -> string or nil
10239 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10240 *
10241 * Returns the next line from the current file in ARGF.
10242 *
10243 * By default lines are assumed to be separated by <code>$/</code>;
10244 * to use a different character as a separator, supply it as a String
10245 * for the _sep_ argument.
10246 *
10247 * The optional _limit_ argument specifies how many characters of each line
10248 * to return. By default all characters are returned.
10249 *
10250 * See IO.readlines for details about getline_args.
10251 *
10252 */
10253static VALUE
10254argf_gets(int argc, VALUE *argv, VALUE argf)
10255{
10256 VALUE line;
10257
10258 line = argf_getline(argc, argv, argf);
10259 rb_lastline_set(line);
10260
10261 return line;
10262}
10263
10264 VALUE
10265rb_gets(void)
10266{
10267 VALUE line;
10268
10269 if (rb_rs != rb_default_rs) {
10270 return rb_f_gets(0, 0, argf);
10271 }
10272
10273 retry:
10274 if (!next_argv()) return Qnil;
10275 line = rb_io_gets(ARGF.current_file);
10276 if (NIL_P(line) && ARGF.next_p != -1) {
10277 rb_io_close(ARGF.current_file);
10278 ARGF.next_p = 1;
10279 goto retry;
10280 }
10281 rb_lastline_set(line);
10282 if (!NIL_P(line)) {
10283 ARGF.lineno++;
10284 ARGF.last_lineno = ARGF.lineno;
10285 }
10286
10287 return line;
10288}
10289
10290static VALUE argf_readline(int, VALUE *, VALUE);
10291
10292/*
10293 * call-seq:
10294 * readline(sep = $/, chomp: false) -> string
10295 * readline(limit, chomp: false) -> string
10296 * readline(sep, limit, chomp: false) -> string
10297 *
10298 * Equivalent to method Kernel#gets, except that it raises an exception
10299 * if called at end-of-stream:
10300 *
10301 * $ cat t.txt | ruby -e "p readlines; readline"
10302 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10303 * in `readline': end of file reached (EOFError)
10304 *
10305 * Optional keyword argument +chomp+ specifies whether line separators
10306 * are to be omitted.
10307 */
10308
10309static VALUE
10310rb_f_readline(int argc, VALUE *argv, VALUE recv)
10311{
10312 if (recv == argf) {
10313 return argf_readline(argc, argv, argf);
10314 }
10315 return forward(argf, rb_intern("readline"), argc, argv);
10316}
10317
10318
10319/*
10320 * call-seq:
10321 * ARGF.readline(sep=$/) -> string
10322 * ARGF.readline(limit) -> string
10323 * ARGF.readline(sep, limit) -> string
10324 *
10325 * Returns the next line from the current file in ARGF.
10326 *
10327 * By default lines are assumed to be separated by <code>$/</code>;
10328 * to use a different character as a separator, supply it as a String
10329 * for the _sep_ argument.
10330 *
10331 * The optional _limit_ argument specifies how many characters of each line
10332 * to return. By default all characters are returned.
10333 *
10334 * An EOFError is raised at the end of the file.
10335 */
10336static VALUE
10337argf_readline(int argc, VALUE *argv, VALUE argf)
10338{
10339 VALUE line;
10340
10341 if (!next_argv()) rb_eof_error();
10342 ARGF_FORWARD(argc, argv);
10343 line = argf_gets(argc, argv, argf);
10344 if (NIL_P(line)) {
10345 rb_eof_error();
10346 }
10347
10348 return line;
10349}
10350
10351static VALUE argf_readlines(int, VALUE *, VALUE);
10352
10353/*
10354 * call-seq:
10355 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10356 * readlines(limit, chomp: false, **enc_opts) -> array
10357 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10358 *
10359 * Returns an array containing the lines returned by calling
10360 * Kernel#gets until the end-of-stream is reached;
10361 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10362 *
10363 * With only string argument +sep+ given,
10364 * returns the remaining lines as determined by line separator +sep+,
10365 * or +nil+ if none;
10366 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10367 *
10368 * # Default separator.
10369 * $ cat t.txt | ruby -e "p readlines"
10370 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10371 *
10372 * # Specified separator.
10373 * $ cat t.txt | ruby -e "p readlines 'li'"
10374 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10375 *
10376 * # Get-all separator.
10377 * $ cat t.txt | ruby -e "p readlines nil"
10378 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10379 *
10380 * # Get-paragraph separator.
10381 * $ cat t.txt | ruby -e "p readlines ''"
10382 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10383 *
10384 * With only integer argument +limit+ given,
10385 * limits the number of bytes in the line;
10386 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10387 *
10388 * $cat t.txt | ruby -e "p readlines 10"
10389 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10390 *
10391 * $cat t.txt | ruby -e "p readlines 11"
10392 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10393 *
10394 * $cat t.txt | ruby -e "p readlines 12"
10395 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10396 *
10397 * With arguments +sep+ and +limit+ given, combines the two behaviors;
10398 * see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit].
10399 *
10400 * Optional keyword argument +chomp+ specifies whether line separators
10401 * are to be omitted:
10402 *
10403 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10404 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10405 *
10406 * Optional keyword arguments +enc_opts+ specify encoding options;
10407 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10408 *
10409 */
10410
10411static VALUE
10412rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10413{
10414 if (recv == argf) {
10415 return argf_readlines(argc, argv, argf);
10416 }
10417 return forward(argf, rb_intern("readlines"), argc, argv);
10418}
10419
10420/*
10421 * call-seq:
10422 * ARGF.readlines(sep = $/) -> array
10423 * ARGF.readlines(limit) -> array
10424 * ARGF.readlines(sep, limit) -> array
10425 *
10426 * ARGF.to_a(sep = $/) -> array
10427 * ARGF.to_a(limit) -> array
10428 * ARGF.to_a(sep, limit) -> array
10429 *
10430 * Reads each file in ARGF in its entirety, returning an Array containing
10431 * lines from the files. Lines are assumed to be separated by _sep_.
10432 *
10433 * lines = ARGF.readlines
10434 * lines[0] #=> "This is line one\n"
10435 */
10436static VALUE
10437argf_readlines(int argc, VALUE *argv, VALUE argf)
10438{
10439 long lineno = ARGF.lineno;
10440 VALUE lines, ary;
10441
10442 ary = rb_ary_new();
10443 while (next_argv()) {
10444 if (ARGF_GENERIC_INPUT_P()) {
10445 lines = forward_current(rb_intern("readlines"), argc, argv);
10446 }
10447 else {
10448 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10449 argf_close(argf);
10450 }
10451 ARGF.next_p = 1;
10452 rb_ary_concat(ary, lines);
10453 ARGF.lineno = lineno + RARRAY_LEN(ary);
10454 ARGF.last_lineno = ARGF.lineno;
10455 }
10456 ARGF.init_p = 0;
10457 return ary;
10458}
10459
10460/*
10461 * call-seq:
10462 * `command` -> string
10463 *
10464 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10465 * sets global variable <tt>$?</tt> to the process status.
10466 *
10467 * This method has potential security vulnerabilities if called with untrusted input;
10468 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10469 *
10470 * Examples:
10471 *
10472 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10473 * $ `echo oops && exit 99` # => "oops\n"
10474 * $ $? # => #<Process::Status: pid 17088 exit 99>
10475 * $ $?.status # => 99>
10476 *
10477 * The built-in syntax <tt>%x{...}</tt> uses this method.
10478 *
10479 */
10480
10481static VALUE
10482rb_f_backquote(VALUE obj, VALUE str)
10483{
10484 VALUE port;
10485 VALUE result;
10486 rb_io_t *fptr;
10487
10488 SafeStringValue(str);
10489 rb_last_status_clear();
10490 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10491 if (NIL_P(port)) return rb_str_new(0,0);
10492
10493 GetOpenFile(port, fptr);
10494 result = read_all(fptr, remain_size(fptr), Qnil);
10495 rb_io_close(port);
10496 RFILE(port)->fptr = NULL;
10497 rb_io_fptr_finalize(fptr);
10498 RB_GC_GUARD(port);
10499
10500 return result;
10501}
10502
10503#ifdef HAVE_SYS_SELECT_H
10504#include <sys/select.h>
10505#endif
10506
10507static VALUE
10508select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10509{
10510 VALUE res, list;
10511 rb_fdset_t *rp, *wp, *ep;
10512 rb_io_t *fptr;
10513 long i;
10514 int max = 0, n;
10515 int pending = 0;
10516 struct timeval timerec;
10517
10518 if (!NIL_P(read)) {
10519 Check_Type(read, T_ARRAY);
10520 for (i=0; i<RARRAY_LEN(read); i++) {
10521 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10522 rb_fd_set(fptr->fd, &fds[0]);
10523 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10524 pending++;
10525 rb_fd_set(fptr->fd, &fds[3]);
10526 }
10527 if (max < fptr->fd) max = fptr->fd;
10528 }
10529 if (pending) { /* no blocking if there's buffered data */
10530 timerec.tv_sec = timerec.tv_usec = 0;
10531 tp = &timerec;
10532 }
10533 rp = &fds[0];
10534 }
10535 else
10536 rp = 0;
10537
10538 if (!NIL_P(write)) {
10539 Check_Type(write, T_ARRAY);
10540 for (i=0; i<RARRAY_LEN(write); i++) {
10541 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10542 GetOpenFile(write_io, fptr);
10543 rb_fd_set(fptr->fd, &fds[1]);
10544 if (max < fptr->fd) max = fptr->fd;
10545 }
10546 wp = &fds[1];
10547 }
10548 else
10549 wp = 0;
10550
10551 if (!NIL_P(except)) {
10552 Check_Type(except, T_ARRAY);
10553 for (i=0; i<RARRAY_LEN(except); i++) {
10554 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10555 VALUE write_io = GetWriteIO(io);
10556 GetOpenFile(io, fptr);
10557 rb_fd_set(fptr->fd, &fds[2]);
10558 if (max < fptr->fd) max = fptr->fd;
10559 if (io != write_io) {
10560 GetOpenFile(write_io, fptr);
10561 rb_fd_set(fptr->fd, &fds[2]);
10562 if (max < fptr->fd) max = fptr->fd;
10563 }
10564 }
10565 ep = &fds[2];
10566 }
10567 else {
10568 ep = 0;
10569 }
10570
10571 max++;
10572
10573 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10574 if (n < 0) {
10575 rb_sys_fail(0);
10576 }
10577 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10578
10579 res = rb_ary_new2(3);
10580 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10581 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10582 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10583
10584 if (rp) {
10585 list = RARRAY_AREF(res, 0);
10586 for (i=0; i< RARRAY_LEN(read); i++) {
10587 VALUE obj = rb_ary_entry(read, i);
10588 VALUE io = rb_io_get_io(obj);
10589 GetOpenFile(io, fptr);
10590 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10591 rb_fd_isset(fptr->fd, &fds[3])) {
10592 rb_ary_push(list, obj);
10593 }
10594 }
10595 }
10596
10597 if (wp) {
10598 list = RARRAY_AREF(res, 1);
10599 for (i=0; i< RARRAY_LEN(write); i++) {
10600 VALUE obj = rb_ary_entry(write, i);
10601 VALUE io = rb_io_get_io(obj);
10602 VALUE write_io = GetWriteIO(io);
10603 GetOpenFile(write_io, fptr);
10604 if (rb_fd_isset(fptr->fd, &fds[1])) {
10605 rb_ary_push(list, obj);
10606 }
10607 }
10608 }
10609
10610 if (ep) {
10611 list = RARRAY_AREF(res, 2);
10612 for (i=0; i< RARRAY_LEN(except); i++) {
10613 VALUE obj = rb_ary_entry(except, i);
10614 VALUE io = rb_io_get_io(obj);
10615 VALUE write_io = GetWriteIO(io);
10616 GetOpenFile(io, fptr);
10617 if (rb_fd_isset(fptr->fd, &fds[2])) {
10618 rb_ary_push(list, obj);
10619 }
10620 else if (io != write_io) {
10621 GetOpenFile(write_io, fptr);
10622 if (rb_fd_isset(fptr->fd, &fds[2])) {
10623 rb_ary_push(list, obj);
10624 }
10625 }
10626 }
10627 }
10628
10629 return res; /* returns an empty array on interrupt */
10630}
10631
10632 struct select_args {
10633 VALUE read, write, except;
10634 struct timeval *timeout;
10635 rb_fdset_t fdsets[4];
10636};
10637
10638static VALUE
10639select_call(VALUE arg)
10640{
10641 struct select_args *p = (struct select_args *)arg;
10642
10643 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10644}
10645
10646static VALUE
10647select_end(VALUE arg)
10648{
10649 struct select_args *p = (struct select_args *)arg;
10650 int i;
10651
10652 for (i = 0; i < numberof(p->fdsets); ++i)
10653 rb_fd_term(&p->fdsets[i]);
10654 return Qnil;
10655}
10656
10657static VALUE sym_normal, sym_sequential, sym_random,
10658 sym_willneed, sym_dontneed, sym_noreuse;
10659
10660#ifdef HAVE_POSIX_FADVISE
10661struct io_advise_struct {
10662 int fd;
10663 int advice;
10664 rb_off_t offset;
10665 rb_off_t len;
10666};
10667
10668static VALUE
10669io_advise_internal(void *arg)
10670{
10671 struct io_advise_struct *ptr = arg;
10672 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10673}
10674
10675static VALUE
10676io_advise_sym_to_const(VALUE sym)
10677{
10678#ifdef POSIX_FADV_NORMAL
10679 if (sym == sym_normal)
10680 return INT2NUM(POSIX_FADV_NORMAL);
10681#endif
10682
10683#ifdef POSIX_FADV_RANDOM
10684 if (sym == sym_random)
10685 return INT2NUM(POSIX_FADV_RANDOM);
10686#endif
10687
10688#ifdef POSIX_FADV_SEQUENTIAL
10689 if (sym == sym_sequential)
10690 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10691#endif
10692
10693#ifdef POSIX_FADV_WILLNEED
10694 if (sym == sym_willneed)
10695 return INT2NUM(POSIX_FADV_WILLNEED);
10696#endif
10697
10698#ifdef POSIX_FADV_DONTNEED
10699 if (sym == sym_dontneed)
10700 return INT2NUM(POSIX_FADV_DONTNEED);
10701#endif
10702
10703#ifdef POSIX_FADV_NOREUSE
10704 if (sym == sym_noreuse)
10705 return INT2NUM(POSIX_FADV_NOREUSE);
10706#endif
10707
10708 return Qnil;
10709}
10710
10711static VALUE
10712do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10713{
10714 int rv;
10715 struct io_advise_struct ias;
10716 VALUE num_adv;
10717
10718 num_adv = io_advise_sym_to_const(advice);
10719
10720 /*
10721 * The platform doesn't support this hint. We don't raise exception, instead
10722 * silently ignore it. Because IO::advise is only hint.
10723 */
10724 if (NIL_P(num_adv))
10725 return Qnil;
10726
10727 ias.fd = fptr->fd;
10728 ias.advice = NUM2INT(num_adv);
10729 ias.offset = offset;
10730 ias.len = len;
10731
10732 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
10733 if (rv && rv != ENOSYS) {
10734 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10735 it returns the error code. */
10736 VALUE message = rb_sprintf("%"PRIsVALUE" "
10737 "(%"PRI_OFFT_PREFIX"d, "
10738 "%"PRI_OFFT_PREFIX"d, "
10739 "%"PRIsVALUE")",
10740 fptr->pathv, offset, len, advice);
10741 rb_syserr_fail_str(rv, message);
10742 }
10743
10744 return Qnil;
10745}
10746
10747#endif /* HAVE_POSIX_FADVISE */
10748
10749static void
10750advice_arg_check(VALUE advice)
10751{
10752 if (!SYMBOL_P(advice))
10753 rb_raise(rb_eTypeError, "advice must be a Symbol");
10754
10755 if (advice != sym_normal &&
10756 advice != sym_sequential &&
10757 advice != sym_random &&
10758 advice != sym_willneed &&
10759 advice != sym_dontneed &&
10760 advice != sym_noreuse) {
10761 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10762 }
10763}
10764
10765/*
10766 * call-seq:
10767 * advise(advice, offset = 0, len = 0) -> nil
10768 *
10769 * Invokes Posix system call
10770 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10771 * which announces an intention to access data from the current file
10772 * in a particular manner.
10773 *
10774 * The arguments and results are platform-dependent.
10775 *
10776 * The relevant data is specified by:
10777 *
10778 * - +offset+: The offset of the first byte of data.
10779 * - +len+: The number of bytes to be accessed;
10780 * if +len+ is zero, or is larger than the number of bytes remaining,
10781 * all remaining bytes will be accessed.
10782 *
10783 * Argument +advice+ is one of the following symbols:
10784 *
10785 * - +:normal+: The application has no advice to give
10786 * about its access pattern for the specified data.
10787 * If no advice is given for an open file, this is the default assumption.
10788 * - +:sequential+: The application expects to access the specified data sequentially
10789 * (with lower offsets read before higher ones).
10790 * - +:random+: The specified data will be accessed in random order.
10791 * - +:noreuse+: The specified data will be accessed only once.
10792 * - +:willneed+: The specified data will be accessed in the near future.
10793 * - +:dontneed+: The specified data will not be accessed in the near future.
10794 *
10795 * Not implemented on all platforms.
10796 *
10797 */
10798static VALUE
10799rb_io_advise(int argc, VALUE *argv, VALUE io)
10800{
10801 VALUE advice, offset, len;
10802 rb_off_t off, l;
10803 rb_io_t *fptr;
10804
10805 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10806 advice_arg_check(advice);
10807
10808 io = GetWriteIO(io);
10809 GetOpenFile(io, fptr);
10810
10811 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10812 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10813
10814#ifdef HAVE_POSIX_FADVISE
10815 return do_io_advise(fptr, advice, off, l);
10816#else
10817 ((void)off, (void)l); /* Ignore all hint */
10818 return Qnil;
10819#endif
10820}
10821
10822/*
10823 * call-seq:
10824 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10825 *
10826 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10827 * which monitors multiple file descriptors,
10828 * waiting until one or more of the file descriptors
10829 * becomes ready for some class of I/O operation.
10830 *
10831 * Not implemented on all platforms.
10832 *
10833 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10834 * is an array of IO objects.
10835 *
10836 * Argument +timeout+ is an integer timeout interval in seconds.
10837 *
10838 * The method monitors the \IO objects given in all three arrays,
10839 * waiting for some to be ready;
10840 * returns a 3-element array whose elements are:
10841 *
10842 * - An array of the objects in +read_ios+ that are ready for reading.
10843 * - An array of the objects in +write_ios+ that are ready for writing.
10844 * - An array of the objects in +error_ios+ have pending exceptions.
10845 *
10846 * If no object becomes ready within the given +timeout+, +nil+ is returned.
10847 *
10848 * \IO.select peeks the buffer of \IO objects for testing readability.
10849 * If the \IO buffer is not empty, \IO.select immediately notifies
10850 * readability. This "peek" only happens for \IO objects. It does not
10851 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10852 *
10853 * The best way to use \IO.select is invoking it after non-blocking
10854 * methods such as #read_nonblock, #write_nonblock, etc. The methods
10855 * raise an exception which is extended by IO::WaitReadable or
10856 * IO::WaitWritable. The modules notify how the caller should wait
10857 * with \IO.select. If IO::WaitReadable is raised, the caller should
10858 * wait for reading. If IO::WaitWritable is raised, the caller should
10859 * wait for writing.
10860 *
10861 * So, blocking read (#readpartial) can be emulated using
10862 * #read_nonblock and \IO.select as follows:
10863 *
10864 * begin
10865 * result = io_like.read_nonblock(maxlen)
10866 * rescue IO::WaitReadable
10867 * IO.select([io_like])
10868 * retry
10869 * rescue IO::WaitWritable
10870 * IO.select(nil, [io_like])
10871 * retry
10872 * end
10873 *
10874 * Especially, the combination of non-blocking methods and \IO.select is
10875 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
10876 * has #to_io method to return underlying IO object. IO.select calls
10877 * #to_io to obtain the file descriptor to wait.
10878 *
10879 * This means that readability notified by \IO.select doesn't mean
10880 * readability from OpenSSL::SSL::SSLSocket object.
10881 *
10882 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
10883 * some data. \IO.select doesn't see the buffer. So \IO.select can
10884 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
10885 *
10886 * However, several more complicated situations exist.
10887 *
10888 * SSL is a protocol which is sequence of records.
10889 * The record consists of multiple bytes.
10890 * So, the remote side of SSL sends a partial record, IO.select
10891 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
10892 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
10893 *
10894 * Also, the remote side can request SSL renegotiation which forces
10895 * the local SSL engine to write some data.
10896 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
10897 * system call and it can block.
10898 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
10899 * IO::WaitWritable instead of blocking.
10900 * So, the caller should wait for ready for writability as above
10901 * example.
10902 *
10903 * The combination of non-blocking methods and \IO.select is also useful
10904 * for streams such as tty, pipe socket socket when multiple processes
10905 * read from a stream.
10906 *
10907 * Finally, Linux kernel developers don't guarantee that
10908 * readability of select(2) means readability of following read(2) even
10909 * for a single process;
10910 * see {select(2)}[https://linux.die.net/man/2/select]
10911 *
10912 * Invoking \IO.select before IO#readpartial works well as usual.
10913 * However it is not the best way to use \IO.select.
10914 *
10915 * The writability notified by select(2) doesn't show
10916 * how many bytes are writable.
10917 * IO#write method blocks until given whole string is written.
10918 * So, <tt>IO#write(two or more bytes)</tt> can block after
10919 * writability is notified by \IO.select. IO#write_nonblock is required
10920 * to avoid the blocking.
10921 *
10922 * Blocking write (#write) can be emulated using #write_nonblock and
10923 * IO.select as follows: IO::WaitReadable should also be rescued for
10924 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
10925 *
10926 * while 0 < string.bytesize
10927 * begin
10928 * written = io_like.write_nonblock(string)
10929 * rescue IO::WaitReadable
10930 * IO.select([io_like])
10931 * retry
10932 * rescue IO::WaitWritable
10933 * IO.select(nil, [io_like])
10934 * retry
10935 * end
10936 * string = string.byteslice(written..-1)
10937 * end
10938 *
10939 * Example:
10940 *
10941 * rp, wp = IO.pipe
10942 * mesg = "ping "
10943 * 100.times {
10944 * # IO.select follows IO#read. Not the best way to use IO.select.
10945 * rs, ws, = IO.select([rp], [wp])
10946 * if r = rs[0]
10947 * ret = r.read(5)
10948 * print ret
10949 * case ret
10950 * when /ping/
10951 * mesg = "pong\n"
10952 * when /pong/
10953 * mesg = "ping "
10954 * end
10955 * end
10956 * if w = ws[0]
10957 * w.write(mesg)
10958 * end
10959 * }
10960 *
10961 * Output:
10962 *
10963 * ping pong
10964 * ping pong
10965 * ping pong
10966 * (snipped)
10967 * ping
10968 *
10969 */
10970
10971static VALUE
10972rb_f_select(int argc, VALUE *argv, VALUE obj)
10973{
10974 VALUE scheduler = rb_fiber_scheduler_current();
10975 if (scheduler != Qnil) {
10976 // It's optionally supported.
10977 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
10978 if (!UNDEF_P(result)) return result;
10979 }
10980
10981 VALUE timeout;
10982 struct select_args args;
10983 struct timeval timerec;
10984 int i;
10985
10986 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
10987 if (NIL_P(timeout)) {
10988 args.timeout = 0;
10989 }
10990 else {
10991 timerec = rb_time_interval(timeout);
10992 args.timeout = &timerec;
10993 }
10994
10995 for (i = 0; i < numberof(args.fdsets); ++i)
10996 rb_fd_init(&args.fdsets[i]);
10997
10998 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
10999}
11000
11001#ifdef IOCTL_REQ_TYPE
11002 typedef IOCTL_REQ_TYPE ioctl_req_t;
11003#else
11004 typedef int ioctl_req_t;
11005# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11006#endif
11007
11008#ifdef HAVE_IOCTL
11009struct ioctl_arg {
11010 int fd;
11011 ioctl_req_t cmd;
11012 long narg;
11013};
11014
11015static VALUE
11016nogvl_ioctl(void *ptr)
11017{
11018 struct ioctl_arg *arg = ptr;
11019
11020 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11021}
11022
11023static int
11024do_ioctl(int fd, ioctl_req_t cmd, long narg)
11025{
11026 int retval;
11027 struct ioctl_arg arg;
11028
11029 arg.fd = fd;
11030 arg.cmd = cmd;
11031 arg.narg = narg;
11032
11033 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
11034
11035 return retval;
11036}
11037#endif
11038
11039#define DEFAULT_IOCTL_NARG_LEN (256)
11040
11041#if defined(__linux__) && defined(_IOC_SIZE)
11042static long
11043linux_iocparm_len(ioctl_req_t cmd)
11044{
11045 long len;
11046
11047 if ((cmd & 0xFFFF0000) == 0) {
11048 /* legacy and unstructured ioctl number. */
11049 return DEFAULT_IOCTL_NARG_LEN;
11050 }
11051
11052 len = _IOC_SIZE(cmd);
11053
11054 /* paranoia check for silly drivers which don't keep ioctl convention */
11055 if (len < DEFAULT_IOCTL_NARG_LEN)
11056 len = DEFAULT_IOCTL_NARG_LEN;
11057
11058 return len;
11059}
11060#endif
11061
11062#ifdef HAVE_IOCTL
11063static long
11064ioctl_narg_len(ioctl_req_t cmd)
11065{
11066 long len;
11067
11068#ifdef IOCPARM_MASK
11069#ifndef IOCPARM_LEN
11070#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11071#endif
11072#endif
11073#ifdef IOCPARM_LEN
11074 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11075#elif defined(__linux__) && defined(_IOC_SIZE)
11076 len = linux_iocparm_len(cmd);
11077#else
11078 /* otherwise guess at what's safe */
11079 len = DEFAULT_IOCTL_NARG_LEN;
11080#endif
11081
11082 return len;
11083}
11084#endif
11085
11086#ifdef HAVE_FCNTL
11087#ifdef __linux__
11088typedef long fcntl_arg_t;
11089#else
11090/* posix */
11091typedef int fcntl_arg_t;
11092#endif
11093
11094static long
11095fcntl_narg_len(ioctl_req_t cmd)
11096{
11097 long len;
11098
11099 switch (cmd) {
11100#ifdef F_DUPFD
11101 case F_DUPFD:
11102 len = sizeof(fcntl_arg_t);
11103 break;
11104#endif
11105#ifdef F_DUP2FD /* bsd specific */
11106 case F_DUP2FD:
11107 len = sizeof(int);
11108 break;
11109#endif
11110#ifdef F_DUPFD_CLOEXEC /* linux specific */
11111 case F_DUPFD_CLOEXEC:
11112 len = sizeof(fcntl_arg_t);
11113 break;
11114#endif
11115#ifdef F_GETFD
11116 case F_GETFD:
11117 len = 1;
11118 break;
11119#endif
11120#ifdef F_SETFD
11121 case F_SETFD:
11122 len = sizeof(fcntl_arg_t);
11123 break;
11124#endif
11125#ifdef F_GETFL
11126 case F_GETFL:
11127 len = 1;
11128 break;
11129#endif
11130#ifdef F_SETFL
11131 case F_SETFL:
11132 len = sizeof(fcntl_arg_t);
11133 break;
11134#endif
11135#ifdef F_GETOWN
11136 case F_GETOWN:
11137 len = 1;
11138 break;
11139#endif
11140#ifdef F_SETOWN
11141 case F_SETOWN:
11142 len = sizeof(fcntl_arg_t);
11143 break;
11144#endif
11145#ifdef F_GETOWN_EX /* linux specific */
11146 case F_GETOWN_EX:
11147 len = sizeof(struct f_owner_ex);
11148 break;
11149#endif
11150#ifdef F_SETOWN_EX /* linux specific */
11151 case F_SETOWN_EX:
11152 len = sizeof(struct f_owner_ex);
11153 break;
11154#endif
11155#ifdef F_GETLK
11156 case F_GETLK:
11157 len = sizeof(struct flock);
11158 break;
11159#endif
11160#ifdef F_SETLK
11161 case F_SETLK:
11162 len = sizeof(struct flock);
11163 break;
11164#endif
11165#ifdef F_SETLKW
11166 case F_SETLKW:
11167 len = sizeof(struct flock);
11168 break;
11169#endif
11170#ifdef F_READAHEAD /* bsd specific */
11171 case F_READAHEAD:
11172 len = sizeof(int);
11173 break;
11174#endif
11175#ifdef F_RDAHEAD /* Darwin specific */
11176 case F_RDAHEAD:
11177 len = sizeof(int);
11178 break;
11179#endif
11180#ifdef F_GETSIG /* linux specific */
11181 case F_GETSIG:
11182 len = 1;
11183 break;
11184#endif
11185#ifdef F_SETSIG /* linux specific */
11186 case F_SETSIG:
11187 len = sizeof(fcntl_arg_t);
11188 break;
11189#endif
11190#ifdef F_GETLEASE /* linux specific */
11191 case F_GETLEASE:
11192 len = 1;
11193 break;
11194#endif
11195#ifdef F_SETLEASE /* linux specific */
11196 case F_SETLEASE:
11197 len = sizeof(fcntl_arg_t);
11198 break;
11199#endif
11200#ifdef F_NOTIFY /* linux specific */
11201 case F_NOTIFY:
11202 len = sizeof(fcntl_arg_t);
11203 break;
11204#endif
11205
11206 default:
11207 len = 256;
11208 break;
11209 }
11210
11211 return len;
11212}
11213#else /* HAVE_FCNTL */
11214static long
11215fcntl_narg_len(ioctl_req_t cmd)
11216{
11217 return 0;
11218}
11219#endif /* HAVE_FCNTL */
11220
11221#define NARG_SENTINEL 17
11222
11223static long
11224setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11225{
11226 long narg = 0;
11227 VALUE arg = *argp;
11228
11229 if (!RTEST(arg)) {
11230 narg = 0;
11231 }
11232 else if (FIXNUM_P(arg)) {
11233 narg = FIX2LONG(arg);
11234 }
11235 else if (arg == Qtrue) {
11236 narg = 1;
11237 }
11238 else {
11239 VALUE tmp = rb_check_string_type(arg);
11240
11241 if (NIL_P(tmp)) {
11242 narg = NUM2LONG(arg);
11243 }
11244 else {
11245 char *ptr;
11246 long len, slen;
11247
11248 *argp = arg = tmp;
11249 len = narg_len(cmd);
11250 rb_str_modify(arg);
11251
11252 slen = RSTRING_LEN(arg);
11253 /* expand for data + sentinel. */
11254 if (slen < len+1) {
11255 rb_str_resize(arg, len+1);
11256 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11257 slen = len+1;
11258 }
11259 /* a little sanity check here */
11260 ptr = RSTRING_PTR(arg);
11261 ptr[slen - 1] = NARG_SENTINEL;
11262 narg = (long)(SIGNED_VALUE)ptr;
11263 }
11264 }
11265
11266 return narg;
11267}
11268
11269static VALUE
11270finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11271{
11272 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11273 if (RB_TYPE_P(arg, T_STRING)) {
11274 char *ptr;
11275 long slen;
11276 RSTRING_GETMEM(arg, ptr, slen);
11277 if (ptr[slen-1] != NARG_SENTINEL)
11278 rb_raise(rb_eArgError, "return value overflowed string");
11279 ptr[slen-1] = '\0';
11280 }
11281
11282 return INT2NUM(retval);
11283}
11284
11285#ifdef HAVE_IOCTL
11286static VALUE
11287rb_ioctl(VALUE io, VALUE req, VALUE arg)
11288{
11289 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11290 rb_io_t *fptr;
11291 long narg;
11292 int retval;
11293
11294 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11295 GetOpenFile(io, fptr);
11296 retval = do_ioctl(fptr->fd, cmd, narg);
11297 return finish_narg(retval, arg, fptr);
11298}
11299
11300/*
11301 * call-seq:
11302 * ioctl(integer_cmd, argument) -> integer
11303 *
11304 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11305 * which issues a low-level command to an I/O device.
11306 *
11307 * Issues a low-level command to an I/O device.
11308 * The arguments and returned value are platform-dependent.
11309 * The effect of the call is platform-dependent.
11310 *
11311 * If argument +argument+ is an integer, it is passed directly;
11312 * if it is a string, it is interpreted as a binary sequence of bytes.
11313 *
11314 * Not implemented on all platforms.
11315 *
11316 */
11317
11318static VALUE
11319rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11320{
11321 VALUE req, arg;
11322
11323 rb_scan_args(argc, argv, "11", &req, &arg);
11324 return rb_ioctl(io, req, arg);
11325}
11326#else
11327#define rb_io_ioctl rb_f_notimplement
11328#endif
11329
11330#ifdef HAVE_FCNTL
11331struct fcntl_arg {
11332 int fd;
11333 int cmd;
11334 long narg;
11335};
11336
11337static VALUE
11338nogvl_fcntl(void *ptr)
11339{
11340 struct fcntl_arg *arg = ptr;
11341
11342#if defined(F_DUPFD)
11343 if (arg->cmd == F_DUPFD)
11344 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11345#endif
11346 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11347}
11348
11349static int
11350do_fcntl(int fd, int cmd, long narg)
11351{
11352 int retval;
11353 struct fcntl_arg arg;
11354
11355 arg.fd = fd;
11356 arg.cmd = cmd;
11357 arg.narg = narg;
11358
11359 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
11360 if (retval != -1) {
11361 switch (cmd) {
11362#if defined(F_DUPFD)
11363 case F_DUPFD:
11364#endif
11365#if defined(F_DUPFD_CLOEXEC)
11366 case F_DUPFD_CLOEXEC:
11367#endif
11368 rb_update_max_fd(retval);
11369 }
11370 }
11371
11372 return retval;
11373}
11374
11375static VALUE
11376rb_fcntl(VALUE io, VALUE req, VALUE arg)
11377{
11378 int cmd = NUM2INT(req);
11379 rb_io_t *fptr;
11380 long narg;
11381 int retval;
11382
11383 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11384 GetOpenFile(io, fptr);
11385 retval = do_fcntl(fptr->fd, cmd, narg);
11386 return finish_narg(retval, arg, fptr);
11387}
11388
11389/*
11390 * call-seq:
11391 * fcntl(integer_cmd, argument) -> integer
11392 *
11393 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11394 * which provides a mechanism for issuing low-level commands to control or query
11395 * a file-oriented I/O stream. Arguments and results are platform
11396 * dependent.
11397 *
11398 * If +argument is a number, its value is passed directly;
11399 * if it is a string, it is interpreted as a binary sequence of bytes.
11400 * (Array#pack might be a useful way to build this string.)
11401 *
11402 * Not implemented on all platforms.
11403 *
11404 */
11405
11406static VALUE
11407rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11408{
11409 VALUE req, arg;
11410
11411 rb_scan_args(argc, argv, "11", &req, &arg);
11412 return rb_fcntl(io, req, arg);
11413}
11414#else
11415#define rb_io_fcntl rb_f_notimplement
11416#endif
11417
11418#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11419/*
11420 * call-seq:
11421 * syscall(integer_callno, *arguments) -> integer
11422 *
11423 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11424 * which calls a specified function.
11425 *
11426 * Calls the operating system function identified by +integer_callno+;
11427 * returns the result of the function or raises SystemCallError if it failed.
11428 * The effect of the call is platform-dependent.
11429 * The arguments and returned value are platform-dependent.
11430 *
11431 * For each of +arguments+: if it is an integer, it is passed directly;
11432 * if it is a string, it is interpreted as a binary sequence of bytes.
11433 * There may be as many as nine such arguments.
11434 *
11435 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11436 * are platform-dependent.
11437 *
11438 * Note: Method +syscall+ is essentially unsafe and unportable.
11439 * The DL (Fiddle) library is preferred for safer and a bit
11440 * more portable programming.
11441 *
11442 * Not implemented on all platforms.
11443 *
11444 */
11445
11446static VALUE
11447rb_f_syscall(int argc, VALUE *argv, VALUE _)
11448{
11449 VALUE arg[8];
11450#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11451# define SYSCALL __syscall
11452# define NUM2SYSCALLID(x) NUM2LONG(x)
11453# define RETVAL2NUM(x) LONG2NUM(x)
11454# if SIZEOF_LONG == 8
11455 long num, retval = -1;
11456# elif SIZEOF_LONG_LONG == 8
11457 long long num, retval = -1;
11458# else
11459# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11460# endif
11461#elif defined(__linux__)
11462# define SYSCALL syscall
11463# define NUM2SYSCALLID(x) NUM2LONG(x)
11464# define RETVAL2NUM(x) LONG2NUM(x)
11465 /*
11466 * Linux man page says, syscall(2) function prototype is below.
11467 *
11468 * int syscall(int number, ...);
11469 *
11470 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11471 */
11472 long num, retval = -1;
11473#else
11474# define SYSCALL syscall
11475# define NUM2SYSCALLID(x) NUM2INT(x)
11476# define RETVAL2NUM(x) INT2NUM(x)
11477 int num, retval = -1;
11478#endif
11479 int i;
11480
11481 if (RTEST(ruby_verbose)) {
11482 rb_category_warning(RB_WARN_CATEGORY_DEPRECATED,
11483 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11484 }
11485
11486 if (argc == 0)
11487 rb_raise(rb_eArgError, "too few arguments for syscall");
11488 if (argc > numberof(arg))
11489 rb_raise(rb_eArgError, "too many arguments for syscall");
11490 num = NUM2SYSCALLID(argv[0]); ++argv;
11491 for (i = argc - 1; i--; ) {
11492 VALUE v = rb_check_string_type(argv[i]);
11493
11494 if (!NIL_P(v)) {
11495 SafeStringValue(v);
11496 rb_str_modify(v);
11497 arg[i] = (VALUE)StringValueCStr(v);
11498 }
11499 else {
11500 arg[i] = (VALUE)NUM2LONG(argv[i]);
11501 }
11502 }
11503
11504 switch (argc) {
11505 case 1:
11506 retval = SYSCALL(num);
11507 break;
11508 case 2:
11509 retval = SYSCALL(num, arg[0]);
11510 break;
11511 case 3:
11512 retval = SYSCALL(num, arg[0],arg[1]);
11513 break;
11514 case 4:
11515 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11516 break;
11517 case 5:
11518 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11519 break;
11520 case 6:
11521 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11522 break;
11523 case 7:
11524 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11525 break;
11526 case 8:
11527 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11528 break;
11529 }
11530
11531 if (retval == -1)
11532 rb_sys_fail(0);
11533 return RETVAL2NUM(retval);
11534#undef SYSCALL
11535#undef NUM2SYSCALLID
11536#undef RETVAL2NUM
11537}
11538#else
11539#define rb_f_syscall rb_f_notimplement
11540#endif
11541
11542static VALUE
11543io_new_instance(VALUE args)
11544{
11545 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11546}
11547
11548static rb_encoding *
11549find_encoding(VALUE v)
11550{
11551 rb_encoding *enc = rb_find_encoding(v);
11552 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11553 return enc;
11554}
11555
11556static void
11557io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11558{
11559 rb_encoding *enc, *enc2;
11560 int ecflags = fptr->encs.ecflags;
11561 VALUE ecopts, tmp;
11562
11563 if (!NIL_P(v2)) {
11564 enc2 = find_encoding(v1);
11565 tmp = rb_check_string_type(v2);
11566 if (!NIL_P(tmp)) {
11567 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11568 /* Special case - "-" => no transcoding */
11569 enc = enc2;
11570 enc2 = NULL;
11571 }
11572 else
11573 enc = find_encoding(v2);
11574 if (enc == enc2) {
11575 /* Special case - "-" => no transcoding */
11576 enc2 = NULL;
11577 }
11578 }
11579 else {
11580 enc = find_encoding(v2);
11581 if (enc == enc2) {
11582 /* Special case - "-" => no transcoding */
11583 enc2 = NULL;
11584 }
11585 }
11586 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11587 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11588 }
11589 else {
11590 if (NIL_P(v1)) {
11591 /* Set to default encodings */
11592 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11593 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11594 ecopts = Qnil;
11595 }
11596 else {
11597 tmp = rb_check_string_type(v1);
11598 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11599 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11600 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11601 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11602 }
11603 else {
11604 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11605 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11606 ecopts = Qnil;
11607 }
11608 }
11609 }
11610 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11611 fptr->encs.enc = enc;
11612 fptr->encs.enc2 = enc2;
11613 fptr->encs.ecflags = ecflags;
11614 fptr->encs.ecopts = ecopts;
11615 clear_codeconv(fptr);
11616
11617}
11618
11619 struct io_encoding_set_args {
11620 rb_io_t *fptr;
11621 VALUE v1;
11622 VALUE v2;
11623 VALUE opt;
11624};
11625
11626static VALUE
11627io_encoding_set_v(VALUE v)
11628{
11629 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11630 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11631 return Qnil;
11632}
11633
11634static VALUE
11635pipe_pair_close(VALUE rw)
11636{
11637 VALUE *rwp = (VALUE *)rw;
11638 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11639}
11640
11641/*
11642 * call-seq:
11643 * IO.pipe(**opts) -> [read_io, write_io]
11644 * IO.pipe(enc, **opts) -> [read_io, write_io]
11645 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11646 * IO.pipe(**opts) {|read_io, write_io] ...} -> object
11647 * IO.pipe(enc, **opts) {|read_io, write_io] ...} -> object
11648 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io] ...} -> object
11649 *
11650 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11651 * connected to each other.
11652 *
11653 * If argument +enc_string+ is given, it must be a string containing one of:
11654 *
11655 * - The name of the encoding to be used as the external encoding.
11656 * - The colon-separated names of two encodings to be used as the external
11657 * and internal encodings.
11658 *
11659 * If argument +int_enc+ is given, it must be an Encoding object
11660 * or encoding name string that specifies the internal encoding to be used;
11661 * if argument +ext_enc+ is also given, it must be an Encoding object
11662 * or encoding name string that specifies the external encoding to be used.
11663 *
11664 * The string read from +read_io+ is tagged with the external encoding;
11665 * if an internal encoding is also specified, the string is converted
11666 * to, and tagged with, that encoding.
11667 *
11668 * If any encoding is specified,
11669 * optional hash arguments specify the conversion option.
11670 *
11671 * Optional keyword arguments +opts+ specify:
11672 *
11673 * - {Open Options}[rdoc-ref:IO@Open+Options].
11674 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11675 *
11676 * With no block given, returns the two endpoints in an array:
11677 *
11678 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11679 *
11680 * With a block given, calls the block with the two endpoints;
11681 * closes both endpoints and returns the value of the block:
11682 *
11683 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11684 *
11685 * Output:
11686 *
11687 * #<IO:fd 6>
11688 * #<IO:fd 7>
11689 *
11690 * Not available on all platforms.
11691 *
11692 * In the example below, the two processes close the ends of the pipe
11693 * that they are not using. This is not just a cosmetic nicety. The
11694 * read end of a pipe will not generate an end of file condition if
11695 * there are any writers with the pipe still open. In the case of the
11696 * parent process, the <tt>rd.read</tt> will never return if it
11697 * does not first issue a <tt>wr.close</tt>:
11698 *
11699 * rd, wr = IO.pipe
11700 *
11701 * if fork
11702 * wr.close
11703 * puts "Parent got: <#{rd.read}>"
11704 * rd.close
11705 * Process.wait
11706 * else
11707 * rd.close
11708 * puts 'Sending message to parent'
11709 * wr.write "Hi Dad"
11710 * wr.close
11711 * end
11712 *
11713 * <em>produces:</em>
11714 *
11715 * Sending message to parent
11716 * Parent got: <Hi Dad>
11717 *
11718 */
11719
11720static VALUE
11721rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11722{
11723 int pipes[2], state;
11724 VALUE r, w, args[3], v1, v2;
11725 VALUE opt;
11726 rb_io_t *fptr, *fptr2;
11727 struct io_encoding_set_args ies_args;
11728 int fmode = 0;
11729 VALUE ret;
11730
11731 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11732 if (rb_pipe(pipes) < 0)
11733 rb_sys_fail(0);
11734
11735 args[0] = klass;
11736 args[1] = INT2NUM(pipes[0]);
11737 args[2] = INT2FIX(O_RDONLY);
11738 r = rb_protect(io_new_instance, (VALUE)args, &state);
11739 if (state) {
11740 close(pipes[0]);
11741 close(pipes[1]);
11742 rb_jump_tag(state);
11743 }
11744 GetOpenFile(r, fptr);
11745
11746 ies_args.fptr = fptr;
11747 ies_args.v1 = v1;
11748 ies_args.v2 = v2;
11749 ies_args.opt = opt;
11750 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11751 if (state) {
11752 close(pipes[1]);
11753 io_close(r);
11754 rb_jump_tag(state);
11755 }
11756
11757 args[1] = INT2NUM(pipes[1]);
11758 args[2] = INT2FIX(O_WRONLY);
11759 w = rb_protect(io_new_instance, (VALUE)args, &state);
11760 if (state) {
11761 close(pipes[1]);
11762 if (!NIL_P(r)) rb_io_close(r);
11763 rb_jump_tag(state);
11764 }
11765 GetOpenFile(w, fptr2);
11766 rb_io_synchronized(fptr2);
11767
11768 extract_binmode(opt, &fmode);
11769
11770 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11771 rb_io_ascii8bit_binmode(r);
11772 rb_io_ascii8bit_binmode(w);
11773 }
11774
11775#if DEFAULT_TEXTMODE
11776 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11777 fptr->mode &= ~FMODE_TEXTMODE;
11778 setmode(fptr->fd, O_BINARY);
11779 }
11780#if RUBY_CRLF_ENVIRONMENT
11781 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
11782 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
11783 }
11784#endif
11785#endif
11786 fptr->mode |= fmode;
11787#if DEFAULT_TEXTMODE
11788 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11789 fptr2->mode &= ~FMODE_TEXTMODE;
11790 setmode(fptr2->fd, O_BINARY);
11791 }
11792#endif
11793 fptr2->mode |= fmode;
11794
11795 ret = rb_assoc_new(r, w);
11796 if (rb_block_given_p()) {
11797 VALUE rw[2];
11798 rw[0] = r;
11799 rw[1] = w;
11800 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11801 }
11802 return ret;
11803}
11804
11805 struct foreach_arg {
11806 int argc;
11807 VALUE *argv;
11808 VALUE io;
11809};
11810
11811static void
11812open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11813{
11814 VALUE path, v;
11815 VALUE vmode = Qnil, vperm = Qnil;
11816
11817 path = *argv++;
11818 argc--;
11819 FilePathValue(path);
11820 arg->io = 0;
11821 arg->argc = argc;
11822 arg->argv = argv;
11823 if (NIL_P(opt)) {
11824 vmode = INT2NUM(O_RDONLY);
11825 vperm = INT2FIX(0666);
11826 }
11827 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11828 int n;
11829
11830 v = rb_to_array_type(v);
11831 n = RARRAY_LENINT(v);
11832 rb_check_arity(n, 0, 3); /* rb_io_open */
11833 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11834 }
11835 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11836}
11837
11838static VALUE
11839io_s_foreach(VALUE v)
11840{
11841 struct getline_arg *arg = (void *)v;
11842 VALUE str;
11843
11844 if (arg->limit == 0)
11845 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
11846 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11847 rb_lastline_set(str);
11848 rb_yield(str);
11849 }
11850 rb_lastline_set(Qnil);
11851 return Qnil;
11852}
11853
11854/*
11855 * call-seq:
11856 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
11857 * IO.foreach(path, limit, **opts) {|line| block } -> nil
11858 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
11859 * IO.foreach(command, sep = $/, **opts) {|line| block } -> nil
11860 * IO.foreach(command, limit, **opts) {|line| block } -> nil
11861 * IO.foreach(command, sep, limit, **opts) {|line| block } -> nil
11862 * IO.foreach(...) -> an_enumerator
11863 *
11864 * Calls the block with each successive line read from the stream.
11865 *
11866 * When called from class \IO (but not subclasses of \IO),
11867 * this method has potential security vulnerabilities if called with untrusted input;
11868 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11869 *
11870 * The first argument must be a string that is one of the following:
11871 *
11872 * - Path: if +self+ is a subclass of \IO (\File, for example),
11873 * or if the string _does_ _not_ start with the pipe character (<tt>'|'</tt>),
11874 * the string is the path to a file.
11875 * - Command: if +self+ is the class \IO,
11876 * and if the string starts with the pipe character,
11877 * the rest of the string is a command to be executed as a subprocess.
11878 * This usage has potential security vulnerabilities if called with untrusted input;
11879 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11880 *
11881 * With only argument +path+ given, parses lines from the file at the given +path+,
11882 * as determined by the default line separator,
11883 * and calls the block with each successive line:
11884 *
11885 * File.foreach('t.txt') {|line| p line }
11886 *
11887 * Output: the same as above.
11888 *
11889 * For both forms, command and path, the remaining arguments are the same.
11890 *
11891 * With argument +sep+ given, parses lines as determined by that line separator
11892 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
11893 *
11894 * File.foreach('t.txt', 'li') {|line| p line }
11895 *
11896 * Output:
11897 *
11898 * "First li"
11899 * "ne\nSecond li"
11900 * "ne\n\nThird li"
11901 * "ne\nFourth li"
11902 * "ne\n"
11903 *
11904 * Each paragraph:
11905 *
11906 * File.foreach('t.txt', '') {|paragraph| p paragraph }
11907 *
11908 * Output:
11909 *
11910 * "First line\nSecond line\n\n"
11911 * "Third line\nFourth line\n"
11912 *
11913 * With argument +limit+ given, parses lines as determined by the default
11914 * line separator and the given line-length limit
11915 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
11916 *
11917 * File.foreach('t.txt', 7) {|line| p line }
11918 *
11919 * Output:
11920 *
11921 * "First l"
11922 * "ine\n"
11923 * "Second "
11924 * "line\n"
11925 * "\n"
11926 * "Third l"
11927 * "ine\n"
11928 * "Fourth l"
11929 * "line\n"
11930 *
11931 * With arguments +sep+ and +limit+ given,
11932 * parses lines as determined by the given
11933 * line separator and the given line-length limit
11934 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
11935 *
11936 * Optional keyword arguments +opts+ specify:
11937 *
11938 * - {Open Options}[rdoc-ref:IO@Open+Options].
11939 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11940 * - {Line Options}[rdoc-ref:IO@Line+Options].
11941 *
11942 * Returns an Enumerator if no block is given.
11943 *
11944 */
11945
11946static VALUE
11947rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
11948{
11949 VALUE opt;
11950 int orig_argc = argc;
11951 struct foreach_arg arg;
11952 struct getline_arg garg;
11953
11954 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
11955 RETURN_ENUMERATOR(self, orig_argc, argv);
11956 extract_getline_args(argc-1, argv+1, &garg);
11957 open_key_args(self, argc, argv, opt, &arg);
11958 if (NIL_P(arg.io)) return Qnil;
11959 extract_getline_opts(opt, &garg);
11960 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
11961 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
11962}
11963
11964static VALUE
11965io_s_readlines(VALUE v)
11966{
11967 struct getline_arg *arg = (void *)v;
11968 return io_readlines(arg, arg->io);
11969}
11970
11971/*
11972 * call-seq:
11973 * IO.readlines(command, sep = $/, **opts) -> array
11974 * IO.readlines(command, limit, **opts) -> array
11975 * IO.readlines(command, sep, limit, **opts) -> array
11976 * IO.readlines(path, sep = $/, **opts) -> array
11977 * IO.readlines(path, limit, **opts) -> array
11978 * IO.readlines(path, sep, limit, **opts) -> array
11979 *
11980 * Returns an array of all lines read from the stream.
11981 *
11982 * When called from class \IO (but not subclasses of \IO),
11983 * this method has potential security vulnerabilities if called with untrusted input;
11984 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11985 *
11986 * The first argument must be a string;
11987 * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
11988 *
11989 * - If so (and if +self+ is \IO),
11990 * the rest of the string is a command to be executed as a subprocess.
11991 * - Otherwise, the string is the path to a file.
11992 *
11993 * With only argument +command+ given, executes the command in a shell,
11994 * parses its $stdout into lines, as determined by the default line separator,
11995 * and returns those lines in an array:
11996 *
11997 * IO.readlines('| cat t.txt')
11998 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
11999 *
12000 * With only argument +path+ given, parses lines from the file at the given +path+,
12001 * as determined by the default line separator,
12002 * and returns those lines in an array:
12003 *
12004 * IO.readlines('t.txt')
12005 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12006 *
12007 * For both forms, command and path, the remaining arguments are the same.
12008 *
12009 * With argument +sep+ given, parses lines as determined by that line separator
12010 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12011 *
12012 * # Ordinary separator.
12013 * IO.readlines('t.txt', 'li')
12014 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12015 * # Get-paragraphs separator.
12016 * IO.readlines('t.txt', '')
12017 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12018 * # Get-all separator.
12019 * IO.readlines('t.txt', nil)
12020 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12021 *
12022 * With argument +limit+ given, parses lines as determined by the default
12023 * line separator and the given line-length limit
12024 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
12025 *
12026 * IO.readlines('t.txt', 7)
12027 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12028 *
12029 * With arguments +sep+ and +limit+ given,
12030 * parses lines as determined by the given
12031 * line separator and the given line-length limit
12032 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
12033 *
12034 * Optional keyword arguments +opts+ specify:
12035 *
12036 * - {Open Options}[rdoc-ref:IO@Open+Options].
12037 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12038 * - {Line Options}[rdoc-ref:IO@Line+Options].
12039 *
12040 */
12041
12042static VALUE
12043rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12044{
12045 VALUE opt;
12046 struct foreach_arg arg;
12047 struct getline_arg garg;
12048
12049 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12050 extract_getline_args(argc-1, argv+1, &garg);
12051 open_key_args(io, argc, argv, opt, &arg);
12052 if (NIL_P(arg.io)) return Qnil;
12053 extract_getline_opts(opt, &garg);
12054 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12055 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12056}
12057
12058static VALUE
12059io_s_read(VALUE v)
12060{
12061 struct foreach_arg *arg = (void *)v;
12062 return io_read(arg->argc, arg->argv, arg->io);
12063}
12064
12065 struct seek_arg {
12066 VALUE io;
12067 VALUE offset;
12068 int mode;
12069};
12070
12071static VALUE
12072seek_before_access(VALUE argp)
12073{
12074 struct seek_arg *arg = (struct seek_arg *)argp;
12075 rb_io_binmode(arg->io);
12076 return rb_io_seek(arg->io, arg->offset, arg->mode);
12077}
12078
12079/*
12080 * call-seq:
12081 * IO.read(command, length = nil, offset = 0, **opts) -> string or nil
12082 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12083 *
12084 * Opens the stream, reads and returns some or all of its content,
12085 * and closes the stream; returns +nil+ if no bytes were read.
12086 *
12087 * When called from class \IO (but not subclasses of \IO),
12088 * this method has potential security vulnerabilities if called with untrusted input;
12089 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12090 *
12091 * The first argument must be a string;
12092 * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
12093 *
12094 * - If so (and if +self+ is \IO),
12095 * the rest of the string is a command to be executed as a subprocess.
12096 * - Otherwise, the string is the path to a file.
12097 *
12098 * With only argument +command+ given, executes the command in a shell,
12099 * returns its entire $stdout:
12100 *
12101 * IO.read('| cat t.txt')
12102 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12103 *
12104 * With only argument +path+ given, reads in text mode and returns the entire content
12105 * of the file at the given path:
12106 *
12107 * IO.read('t.txt')
12108 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12109 *
12110 * On Windows, text mode can terminate reading and leave bytes in the file
12111 * unread when encountering certain special bytes. Consider using
12112 * IO.binread if all bytes in the file should be read.
12113 *
12114 * For both forms, command and path, the remaining arguments are the same.
12115 *
12116 * With argument +length+, returns +length+ bytes if available:
12117 *
12118 * IO.read('t.txt', 7) # => "First l"
12119 * IO.read('t.txt', 700)
12120 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12121 *
12122 * With arguments +length+ and +offset+, returns +length+ bytes
12123 * if available, beginning at the given +offset+:
12124 *
12125 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12126 * IO.read('t.txt', 10, 200) # => nil
12127 *
12128 * Optional keyword arguments +opts+ specify:
12129 *
12130 * - {Open Options}[rdoc-ref:IO@Open+Options].
12131 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12132 *
12133 */
12134
12135static VALUE
12136rb_io_s_read(int argc, VALUE *argv, VALUE io)
12137{
12138 VALUE opt, offset;
12139 struct foreach_arg arg;
12140
12141 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12142 open_key_args(io, argc, argv, opt, &arg);
12143 if (NIL_P(arg.io)) return Qnil;
12144 if (!NIL_P(offset)) {
12145 struct seek_arg sarg;
12146 int state = 0;
12147 sarg.io = arg.io;
12148 sarg.offset = offset;
12149 sarg.mode = SEEK_SET;
12150 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12151 if (state) {
12152 rb_io_close(arg.io);
12153 rb_jump_tag(state);
12154 }
12155 if (arg.argc == 2) arg.argc = 1;
12156 }
12157 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12158}
12159
12160/*
12161 * call-seq:
12162 * IO.binread(command, length = nil, offset = 0) -> string or nil
12163 * IO.binread(path, length = nil, offset = 0) -> string or nil
12164 *
12165 * Behaves like IO.read, except that the stream is opened in binary mode
12166 * with ASCII-8BIT encoding.
12167 *
12168 * When called from class \IO (but not subclasses of \IO),
12169 * this method has potential security vulnerabilities if called with untrusted input;
12170 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12171 *
12172 */
12173
12174static VALUE
12175rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12176{
12177 VALUE offset;
12178 struct foreach_arg arg;
12179 enum {
12180 fmode = FMODE_READABLE|FMODE_BINMODE,
12181 oflags = O_RDONLY
12182#ifdef O_BINARY
12183 |O_BINARY
12184#endif
12185 };
12186 convconfig_t convconfig = {NULL, NULL, 0, Qnil};
12187
12188 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12189 FilePathValue(argv[0]);
12190 convconfig.enc = rb_ascii8bit_encoding();
12191 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12192 if (NIL_P(arg.io)) return Qnil;
12193 arg.argv = argv+1;
12194 arg.argc = (argc > 1) ? 1 : 0;
12195 if (!NIL_P(offset)) {
12196 struct seek_arg sarg;
12197 int state = 0;
12198 sarg.io = arg.io;
12199 sarg.offset = offset;
12200 sarg.mode = SEEK_SET;
12201 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12202 if (state) {
12203 rb_io_close(arg.io);
12204 rb_jump_tag(state);
12205 }
12206 }
12207 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12208}
12209
12210static VALUE
12211io_s_write0(VALUE v)
12212{
12213 struct write_arg *arg = (void *)v;
12214 return io_write(arg->io,arg->str,arg->nosync);
12215}
12216
12217static VALUE
12218io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12219{
12220 VALUE string, offset, opt;
12221 struct foreach_arg arg;
12222 struct write_arg warg;
12223
12224 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12225
12226 if (NIL_P(opt)) opt = rb_hash_new();
12227 else opt = rb_hash_dup(opt);
12228
12229
12230 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12231 int mode = O_WRONLY|O_CREAT;
12232#ifdef O_BINARY
12233 if (binary) mode |= O_BINARY;
12234#endif
12235 if (NIL_P(offset)) mode |= O_TRUNC;
12236 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12237 }
12238 open_key_args(klass, argc, argv, opt, &arg);
12239
12240#ifndef O_BINARY
12241 if (binary) rb_io_binmode_m(arg.io);
12242#endif
12243
12244 if (NIL_P(arg.io)) return Qnil;
12245 if (!NIL_P(offset)) {
12246 struct seek_arg sarg;
12247 int state = 0;
12248 sarg.io = arg.io;
12249 sarg.offset = offset;
12250 sarg.mode = SEEK_SET;
12251 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12252 if (state) {
12253 rb_io_close(arg.io);
12254 rb_jump_tag(state);
12255 }
12256 }
12257
12258 warg.io = arg.io;
12259 warg.str = string;
12260 warg.nosync = 0;
12261
12262 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12263}
12264
12265/*
12266 * call-seq:
12267 * IO.write(command, data, **opts) -> integer
12268 * IO.write(path, data, offset = 0, **opts) -> integer
12269 *
12270 * Opens the stream, writes the given +data+ to it,
12271 * and closes the stream; returns the number of bytes written.
12272 *
12273 * When called from class \IO (but not subclasses of \IO),
12274 * this method has potential security vulnerabilities if called with untrusted input;
12275 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12276 *
12277 * The first argument must be a string;
12278 * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
12279 *
12280 * - If so (and if +self+ is \IO),
12281 * the rest of the string is a command to be executed as a subprocess.
12282 * - Otherwise, the string is the path to a file.
12283 *
12284 * With argument +command+ given, executes the command in a shell,
12285 * passes +data+ through standard input, writes its output to $stdout,
12286 * and returns the length of the given +data+:
12287 *
12288 * IO.write('| cat', 'Hello World!') # => 12
12289 *
12290 * Output:
12291 *
12292 * Hello World!
12293 *
12294 * With argument +path+ given, writes the given +data+ to the file
12295 * at that path:
12296 *
12297 * IO.write('t.tmp', 'abc') # => 3
12298 * File.read('t.tmp') # => "abc"
12299 *
12300 * If +offset+ is zero (the default), the file is overwritten:
12301 *
12302 * IO.write('t.tmp', 'A') # => 1
12303 * File.read('t.tmp') # => "A"
12304 *
12305 * If +offset+ in within the file content, the file is partly overwritten:
12306 *
12307 * IO.write('t.tmp', 'abcdef') # => 3
12308 * File.read('t.tmp') # => "abcdef"
12309 * # Offset within content.
12310 * IO.write('t.tmp', '012', 2) # => 3
12311 * File.read('t.tmp') # => "ab012f"
12312 *
12313 * If +offset+ is outside the file content,
12314 * the file is padded with null characters <tt>"\u0000"</tt>:
12315 *
12316 * IO.write('t.tmp', 'xyz', 10) # => 3
12317 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12318 *
12319 * Optional keyword arguments +opts+ specify:
12320 *
12321 * - {Open Options}[rdoc-ref:IO@Open+Options].
12322 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12323 *
12324 */
12325
12326static VALUE
12327rb_io_s_write(int argc, VALUE *argv, VALUE io)
12328{
12329 return io_s_write(argc, argv, io, 0);
12330}
12331
12332/*
12333 * call-seq:
12334 * IO.binwrite(command, string, offset = 0) -> integer
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#ifdef HAVE_PREAD
12892 ss = pread(stp->src_fptr->fd, buf, len, offset);
12893#else
12894 stp->notimp = "pread";
12895 return -1;
12896#endif
12897 }
12898 if (ss == 0) {
12899 return 0;
12900 }
12901 if (ss < 0) {
12902 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12903 goto retry_read;
12904 switch (errno) {
12905 case EAGAIN:
12906#if EWOULDBLOCK != EAGAIN
12907 case EWOULDBLOCK:
12908#endif
12909 {
12910 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12911 if (ret < 0) return ret;
12912 }
12913 goto retry_read;
12914#ifdef ENOSYS
12915 case ENOSYS:
12916 stp->notimp = "pread";
12917 return ss;
12918#endif
12919 }
12920 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
12921 stp->error_no = errno;
12922 }
12923 return ss;
12924}
12925
12926static int
12927nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
12928{
12929 ssize_t ss;
12930 int off = 0;
12931 while (len) {
12932 ss = write(stp->dst_fptr->fd, buf+off, len);
12933 if (ss < 0) {
12934 if (maygvl_copy_stream_continue_p(0, stp))
12935 continue;
12936 if (io_again_p(errno)) {
12937 int ret = nogvl_copy_stream_wait_write(stp);
12938 if (ret < 0) return ret;
12939 continue;
12940 }
12941 stp->syserr = "write";
12942 stp->error_no = errno;
12943 return (int)ss;
12944 }
12945 off += (int)ss;
12946 len -= (int)ss;
12947 stp->total += ss;
12948 }
12949 return 0;
12950}
12951
12952static void
12953nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
12954{
12955 char buf[1024*16];
12956 size_t len;
12957 ssize_t ss;
12958 int ret;
12959 rb_off_t copy_length;
12960 rb_off_t src_offset;
12961 int use_eof;
12962 int use_pread;
12963
12964 copy_length = stp->copy_length;
12965 use_eof = copy_length < (rb_off_t)0;
12966 src_offset = stp->src_offset;
12967 use_pread = src_offset >= (rb_off_t)0;
12968
12969 if (use_pread && stp->close_src) {
12970 rb_off_t r;
12971 errno = 0;
12972 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12973 if (r < (rb_off_t)0 && errno) {
12974 stp->syserr = "lseek";
12975 stp->error_no = errno;
12976 return;
12977 }
12978 src_offset = (rb_off_t)-1;
12979 use_pread = 0;
12980 }
12981
12982 while (use_eof || 0 < copy_length) {
12983 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
12984 len = (size_t)copy_length;
12985 }
12986 else {
12987 len = sizeof(buf);
12988 }
12989 if (use_pread) {
12990 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
12991 if (0 < ss)
12992 src_offset += ss;
12993 }
12994 else {
12995 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
12996 }
12997 if (ss <= 0) /* EOF or error */
12998 return;
12999
13000 ret = nogvl_copy_stream_write(stp, buf, ss);
13001 if (ret < 0)
13002 return;
13003
13004 if (!use_eof)
13005 copy_length -= ss;
13006 }
13007}
13008
13009static void *
13010nogvl_copy_stream_func(void *arg)
13011{
13012 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13013#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13014 int ret;
13015#endif
13016
13017#ifdef USE_COPY_FILE_RANGE
13018 ret = nogvl_copy_file_range(stp);
13019 if (ret != 0)
13020 goto finish; /* error or success */
13021#endif
13022
13023#ifdef HAVE_FCOPYFILE
13024 ret = nogvl_fcopyfile(stp);
13025 if (ret != 0)
13026 goto finish; /* error or success */
13027#endif
13028
13029#ifdef USE_SENDFILE
13030 ret = nogvl_copy_stream_sendfile(stp);
13031 if (ret != 0)
13032 goto finish; /* error or success */
13033#endif
13034
13035 nogvl_copy_stream_read_write(stp);
13036
13037#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13038 finish:
13039#endif
13040 return 0;
13041}
13042
13043static VALUE
13044copy_stream_fallback_body(VALUE arg)
13045{
13046 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13047 const int buflen = 16*1024;
13048 VALUE n;
13049 VALUE buf = rb_str_buf_new(buflen);
13050 rb_off_t rest = stp->copy_length;
13051 rb_off_t off = stp->src_offset;
13052 ID read_method = id_readpartial;
13053
13054 if (!stp->src_fptr) {
13055 if (!rb_respond_to(stp->src, read_method)) {
13056 read_method = id_read;
13057 }
13058 }
13059
13060 while (1) {
13061 long numwrote;
13062 long l;
13063 if (stp->copy_length < (rb_off_t)0) {
13064 l = buflen;
13065 }
13066 else {
13067 if (rest == 0) {
13068 rb_str_resize(buf, 0);
13069 break;
13070 }
13071 l = buflen < rest ? buflen : (long)rest;
13072 }
13073 if (!stp->src_fptr) {
13074 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13075
13076 if (read_method == id_read && NIL_P(rc))
13077 break;
13078 }
13079 else {
13080 ssize_t ss;
13081 rb_str_resize(buf, buflen);
13082 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13083 rb_str_resize(buf, ss > 0 ? ss : 0);
13084 if (ss < 0)
13085 return Qnil;
13086 if (ss == 0)
13087 rb_eof_error();
13088 if (off >= (rb_off_t)0)
13089 off += ss;
13090 }
13091 n = rb_io_write(stp->dst, buf);
13092 numwrote = NUM2LONG(n);
13093 stp->total += numwrote;
13094 rest -= numwrote;
13095 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13096 break;
13097 }
13098 }
13099
13100 return Qnil;
13101}
13102
13103static VALUE
13104copy_stream_fallback(struct copy_stream_struct *stp)
13105{
13106 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13107 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13108 }
13109 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13110 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13111 rb_eEOFError, (VALUE)0);
13112 return Qnil;
13113}
13114
13115static VALUE
13116copy_stream_body(VALUE arg)
13117{
13118 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13119 VALUE src_io = stp->src, dst_io = stp->dst;
13120 const int common_oflags = 0
13121#ifdef O_NOCTTY
13122 | O_NOCTTY
13123#endif
13124 ;
13125
13126 stp->th = rb_thread_current();
13127
13128 stp->total = 0;
13129
13130 if (src_io == argf ||
13131 !(RB_TYPE_P(src_io, T_FILE) ||
13132 RB_TYPE_P(src_io, T_STRING) ||
13133 rb_respond_to(src_io, rb_intern("to_path")))) {
13134 stp->src_fptr = NULL;
13135 }
13136 else {
13137 int stat_ret;
13138 VALUE tmp_io = rb_io_check_io(src_io);
13139 if (!NIL_P(tmp_io)) {
13140 src_io = tmp_io;
13141 }
13142 else if (!RB_TYPE_P(src_io, T_FILE)) {
13143 VALUE args[2];
13144 FilePathValue(src_io);
13145 args[0] = src_io;
13146 args[1] = INT2NUM(O_RDONLY|common_oflags);
13147 src_io = rb_class_new_instance(2, args, rb_cFile);
13148 stp->src = src_io;
13149 stp->close_src = 1;
13150 }
13151 RB_IO_POINTER(src_io, stp->src_fptr);
13152 rb_io_check_byte_readable(stp->src_fptr);
13153
13154 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13155 if (stat_ret < 0) {
13156 stp->syserr = "fstat";
13157 stp->error_no = errno;
13158 return Qnil;
13159 }
13160 }
13161
13162 if (dst_io == argf ||
13163 !(RB_TYPE_P(dst_io, T_FILE) ||
13164 RB_TYPE_P(dst_io, T_STRING) ||
13165 rb_respond_to(dst_io, rb_intern("to_path")))) {
13166 stp->dst_fptr = NULL;
13167 }
13168 else {
13169 int stat_ret;
13170 VALUE tmp_io = rb_io_check_io(dst_io);
13171 if (!NIL_P(tmp_io)) {
13172 dst_io = GetWriteIO(tmp_io);
13173 }
13174 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13175 VALUE args[3];
13176 FilePathValue(dst_io);
13177 args[0] = dst_io;
13178 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13179 args[2] = INT2FIX(0666);
13180 dst_io = rb_class_new_instance(3, args, rb_cFile);
13181 stp->dst = dst_io;
13182 stp->close_dst = 1;
13183 }
13184 else {
13185 dst_io = GetWriteIO(dst_io);
13186 stp->dst = dst_io;
13187 }
13188 RB_IO_POINTER(dst_io, stp->dst_fptr);
13189 rb_io_check_writable(stp->dst_fptr);
13190
13191 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13192 if (stat_ret < 0) {
13193 stp->syserr = "fstat";
13194 stp->error_no = errno;
13195 return Qnil;
13196 }
13197 }
13198
13199#ifdef O_BINARY
13200 if (stp->src_fptr)
13201 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13202#endif
13203 if (stp->dst_fptr)
13204 io_ascii8bit_binmode(stp->dst_fptr);
13205
13206 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13207 size_t len = stp->src_fptr->rbuf.len;
13208 VALUE str;
13209 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13210 len = (size_t)stp->copy_length;
13211 }
13212 str = rb_str_buf_new(len);
13213 rb_str_resize(str,len);
13214 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13215 if (stp->dst_fptr) { /* IO or filename */
13216 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13217 rb_sys_fail_on_write(stp->dst_fptr);
13218 }
13219 else /* others such as StringIO */
13220 rb_io_write(dst_io, str);
13221 rb_str_resize(str, 0);
13222 stp->total += len;
13223 if (stp->copy_length >= (rb_off_t)0)
13224 stp->copy_length -= len;
13225 }
13226
13227 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13228 rb_raise(rb_eIOError, "flush failed");
13229 }
13230
13231 if (stp->copy_length == 0)
13232 return Qnil;
13233
13234 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13235 return copy_stream_fallback(stp);
13236 }
13237
13238 rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
13239 return Qnil;
13240}
13241
13242static VALUE
13243copy_stream_finalize(VALUE arg)
13244{
13245 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13246
13247#ifdef HAVE_FCOPYFILE
13248 if (stp->copyfile_state) {
13249 copyfile_state_free(stp->copyfile_state);
13250 }
13251#endif
13252
13253 if (stp->close_src) {
13254 rb_io_close_m(stp->src);
13255 }
13256 if (stp->close_dst) {
13257 rb_io_close_m(stp->dst);
13258 }
13259 if (stp->syserr) {
13260 rb_syserr_fail(stp->error_no, stp->syserr);
13261 }
13262 if (stp->notimp) {
13263 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13264 }
13265 return Qnil;
13266}
13267
13268/*
13269 * call-seq:
13270 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13271 *
13272 * Copies from the given +src+ to the given +dst+,
13273 * returning the number of bytes copied.
13274 *
13275 * - The given +src+ must be one of the following:
13276 *
13277 * - The path to a readable file, from which source data is to be read.
13278 * - An \IO-like object, opened for reading and capable of responding
13279 * to method +:readpartial+ or method +:read+.
13280 *
13281 * - The given +dst+ must be one of the following:
13282 *
13283 * - The path to a writable file, to which data is to be written.
13284 * - An \IO-like object, opened for writing and capable of responding
13285 * to method +:write+.
13286 *
13287 * The examples here use file <tt>t.txt</tt> as source:
13288 *
13289 * File.read('t.txt')
13290 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13291 * File.read('t.txt').size # => 47
13292 *
13293 * If only arguments +src+ and +dst+ are given,
13294 * the entire source stream is copied:
13295 *
13296 * # Paths.
13297 * IO.copy_stream('t.txt', 't.tmp') # => 47
13298 *
13299 * # IOs (recall that a File is also an IO).
13300 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13301 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13302 * IO.copy_stream(src_io, dst_io) # => 47
13303 * src_io.close
13304 * dst_io.close
13305 *
13306 * With argument +src_length+ a non-negative integer,
13307 * no more than that many bytes are copied:
13308 *
13309 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13310 * File.read('t.tmp') # => "First line"
13311 *
13312 * With argument +src_offset+ also given,
13313 * the source stream is read beginning at that offset:
13314 *
13315 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13316 * IO.read('t.tmp') # => "Second line"
13317 *
13318 */
13319static VALUE
13320rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13321{
13322 VALUE src, dst, length, src_offset;
13323 struct copy_stream_struct st;
13324
13325 MEMZERO(&st, struct copy_stream_struct, 1);
13326
13327 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13328
13329 st.src = src;
13330 st.dst = dst;
13331
13332 st.src_fptr = NULL;
13333 st.dst_fptr = NULL;
13334
13335 if (NIL_P(length))
13336 st.copy_length = (rb_off_t)-1;
13337 else
13338 st.copy_length = NUM2OFFT(length);
13339
13340 if (NIL_P(src_offset))
13341 st.src_offset = (rb_off_t)-1;
13342 else
13343 st.src_offset = NUM2OFFT(src_offset);
13344
13345 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13346
13347 return OFFT2NUM(st.total);
13348}
13349
13350/*
13351 * call-seq:
13352 * external_encoding -> encoding or nil
13353 *
13354 * Returns the Encoding object that represents the encoding of the stream,
13355 * or +nil+ if the stream is in write mode and no encoding is specified.
13356 *
13357 * See {Encodings}[rdoc-ref:File@Encodings].
13358 *
13359 */
13360
13361static VALUE
13362rb_io_external_encoding(VALUE io)
13363{
13364 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13365
13366 if (fptr->encs.enc2) {
13367 return rb_enc_from_encoding(fptr->encs.enc2);
13368 }
13369 if (fptr->mode & FMODE_WRITABLE) {
13370 if (fptr->encs.enc)
13371 return rb_enc_from_encoding(fptr->encs.enc);
13372 return Qnil;
13373 }
13374 return rb_enc_from_encoding(io_read_encoding(fptr));
13375}
13376
13377/*
13378 * call-seq:
13379 * internal_encoding -> encoding or nil
13380 *
13381 * Returns the Encoding object that represents the encoding of the internal string,
13382 * if conversion is specified,
13383 * or +nil+ otherwise.
13384 *
13385 * See {Encodings}[rdoc-ref:File@Encodings].
13386 *
13387 */
13388
13389static VALUE
13390rb_io_internal_encoding(VALUE io)
13391{
13392 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13393
13394 if (!fptr->encs.enc2) return Qnil;
13395 return rb_enc_from_encoding(io_read_encoding(fptr));
13396}
13397
13398/*
13399 * call-seq:
13400 * set_encoding(ext_enc) -> self
13401 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13402 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13403 *
13404 * See {Encodings}[rdoc-ref:File@Encodings].
13405 *
13406 * Argument +ext_enc+, if given, must be an Encoding object;
13407 * it is assigned as the encoding for the stream.
13408 *
13409 * Argument +int_enc+, if given, must be an Encoding object;
13410 * it is assigned as the encoding for the internal string.
13411 *
13412 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13413 * containing two colon-separated encoding names;
13414 * corresponding Encoding objects are assigned as the external
13415 * and internal encodings for the stream.
13416 *
13417 * Optional keyword arguments +enc_opts+ specify
13418 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13419 *
13420 */
13421
13422static VALUE
13423rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13424{
13425 rb_io_t *fptr;
13426 VALUE v1, v2, opt;
13427
13428 if (!RB_TYPE_P(io, T_FILE)) {
13429 return forward(io, id_set_encoding, argc, argv);
13430 }
13431
13432 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13433 GetOpenFile(io, fptr);
13434 io_encoding_set(fptr, v1, v2, opt);
13435 return io;
13436}
13437
13438void
13439rb_stdio_set_default_encoding(void)
13440{
13441 VALUE val = Qnil;
13442
13443#ifdef _WIN32
13444 if (isatty(fileno(stdin))) {
13445 rb_encoding *external = rb_locale_encoding();
13446 rb_encoding *internal = rb_default_internal_encoding();
13447 if (!internal) internal = rb_default_external_encoding();
13448 io_encoding_set(RFILE(rb_stdin)->fptr,
13449 rb_enc_from_encoding(external),
13450 rb_enc_from_encoding(internal),
13451 Qnil);
13452 }
13453 else
13454#endif
13455 rb_io_set_encoding(1, &val, rb_stdin);
13456 rb_io_set_encoding(1, &val, rb_stdout);
13457 rb_io_set_encoding(1, &val, rb_stderr);
13458}
13459
13460static inline int
13461global_argf_p(VALUE arg)
13462{
13463 return arg == argf;
13464}
13465
13466typedef VALUE (*argf_encoding_func)(VALUE io);
13467
13468static VALUE
13469argf_encoding(VALUE argf, argf_encoding_func func)
13470{
13471 if (!RTEST(ARGF.current_file)) {
13472 return rb_enc_default_external();
13473 }
13474 return func(rb_io_check_io(ARGF.current_file));
13475}
13476
13477/*
13478 * call-seq:
13479 * ARGF.external_encoding -> encoding
13480 *
13481 * Returns the external encoding for files read from ARGF as an Encoding
13482 * object. The external encoding is the encoding of the text as stored in a
13483 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13484 * represent this text within Ruby.
13485 *
13486 * To set the external encoding use ARGF.set_encoding.
13487 *
13488 * For example:
13489 *
13490 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13491 *
13492 */
13493static VALUE
13494argf_external_encoding(VALUE argf)
13495{
13496 return argf_encoding(argf, rb_io_external_encoding);
13497}
13498
13499/*
13500 * call-seq:
13501 * ARGF.internal_encoding -> encoding
13502 *
13503 * Returns the internal encoding for strings read from ARGF as an
13504 * Encoding object.
13505 *
13506 * If ARGF.set_encoding has been called with two encoding names, the second
13507 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13508 * value is returned. Failing that, if a default external encoding was
13509 * specified on the command-line, that value is used. If the encoding is
13510 * unknown, +nil+ is returned.
13511 */
13512static VALUE
13513argf_internal_encoding(VALUE argf)
13514{
13515 return argf_encoding(argf, rb_io_internal_encoding);
13516}
13517
13518/*
13519 * call-seq:
13520 * ARGF.set_encoding(ext_enc) -> ARGF
13521 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13522 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13523 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13524 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13525 *
13526 * If single argument is specified, strings read from ARGF are tagged with
13527 * the encoding specified.
13528 *
13529 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13530 * the read string is converted from the first encoding (external encoding)
13531 * to the second encoding (internal encoding), then tagged with the second
13532 * encoding.
13533 *
13534 * If two arguments are specified, they must be encoding objects or encoding
13535 * names. Again, the first specifies the external encoding; the second
13536 * specifies the internal encoding.
13537 *
13538 * If the external encoding and the internal encoding are specified, the
13539 * optional Hash argument can be used to adjust the conversion process. The
13540 * structure of this hash is explained in the String#encode documentation.
13541 *
13542 * For example:
13543 *
13544 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13545 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13546 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13547 * # to UTF-8.
13548 */
13549static VALUE
13550argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13551{
13552 rb_io_t *fptr;
13553
13554 if (!next_argv()) {
13555 rb_raise(rb_eArgError, "no stream to set encoding");
13556 }
13557 rb_io_set_encoding(argc, argv, ARGF.current_file);
13558 GetOpenFile(ARGF.current_file, fptr);
13559 ARGF.encs = fptr->encs;
13560 return argf;
13561}
13562
13563/*
13564 * call-seq:
13565 * ARGF.tell -> Integer
13566 * ARGF.pos -> Integer
13567 *
13568 * Returns the current offset (in bytes) of the current file in ARGF.
13569 *
13570 * ARGF.pos #=> 0
13571 * ARGF.gets #=> "This is line one\n"
13572 * ARGF.pos #=> 17
13573 *
13574 */
13575static VALUE
13576argf_tell(VALUE argf)
13577{
13578 if (!next_argv()) {
13579 rb_raise(rb_eArgError, "no stream to tell");
13580 }
13581 ARGF_FORWARD(0, 0);
13582 return rb_io_tell(ARGF.current_file);
13583}
13584
13585/*
13586 * call-seq:
13587 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13588 *
13589 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13590 * the value of _whence_. See IO#seek for further details.
13591 */
13592static VALUE
13593argf_seek_m(int argc, VALUE *argv, VALUE argf)
13594{
13595 if (!next_argv()) {
13596 rb_raise(rb_eArgError, "no stream to seek");
13597 }
13598 ARGF_FORWARD(argc, argv);
13599 return rb_io_seek_m(argc, argv, ARGF.current_file);
13600}
13601
13602/*
13603 * call-seq:
13604 * ARGF.pos = position -> Integer
13605 *
13606 * Seeks to the position given by _position_ (in bytes) in ARGF.
13607 *
13608 * For example:
13609 *
13610 * ARGF.pos = 17
13611 * ARGF.gets #=> "This is line two\n"
13612 */
13613static VALUE
13614argf_set_pos(VALUE argf, VALUE offset)
13615{
13616 if (!next_argv()) {
13617 rb_raise(rb_eArgError, "no stream to set position");
13618 }
13619 ARGF_FORWARD(1, &offset);
13620 return rb_io_set_pos(ARGF.current_file, offset);
13621}
13622
13623/*
13624 * call-seq:
13625 * ARGF.rewind -> 0
13626 *
13627 * Positions the current file to the beginning of input, resetting
13628 * ARGF.lineno to zero.
13629 *
13630 * ARGF.readline #=> "This is line one\n"
13631 * ARGF.rewind #=> 0
13632 * ARGF.lineno #=> 0
13633 * ARGF.readline #=> "This is line one\n"
13634 */
13635static VALUE
13636argf_rewind(VALUE argf)
13637{
13638 VALUE ret;
13639 int old_lineno;
13640
13641 if (!next_argv()) {
13642 rb_raise(rb_eArgError, "no stream to rewind");
13643 }
13644 ARGF_FORWARD(0, 0);
13645 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13646 ret = rb_io_rewind(ARGF.current_file);
13647 if (!global_argf_p(argf)) {
13648 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13649 }
13650 return ret;
13651}
13652
13653/*
13654 * call-seq:
13655 * ARGF.fileno -> integer
13656 * ARGF.to_i -> integer
13657 *
13658 * Returns an integer representing the numeric file descriptor for
13659 * the current file. Raises an ArgumentError if there isn't a current file.
13660 *
13661 * ARGF.fileno #=> 3
13662 */
13663static VALUE
13664argf_fileno(VALUE argf)
13665{
13666 if (!next_argv()) {
13667 rb_raise(rb_eArgError, "no stream");
13668 }
13669 ARGF_FORWARD(0, 0);
13670 return rb_io_fileno(ARGF.current_file);
13671}
13672
13673/*
13674 * call-seq:
13675 * ARGF.to_io -> IO
13676 *
13677 * Returns an IO object representing the current file. This will be a
13678 * File object unless the current file is a stream such as STDIN.
13679 *
13680 * For example:
13681 *
13682 * ARGF.to_io #=> #<File:glark.txt>
13683 * ARGF.to_io #=> #<IO:<STDIN>>
13684 */
13685static VALUE
13686argf_to_io(VALUE argf)
13687{
13688 next_argv();
13689 ARGF_FORWARD(0, 0);
13690 return ARGF.current_file;
13691}
13692
13693/*
13694 * call-seq:
13695 * ARGF.eof? -> true or false
13696 * ARGF.eof -> true or false
13697 *
13698 * Returns true if the current file in ARGF is at end of file, i.e. it has
13699 * no data to read. The stream must be opened for reading or an IOError
13700 * will be raised.
13701 *
13702 * $ echo "eof" | ruby argf.rb
13703 *
13704 * ARGF.eof? #=> false
13705 * 3.times { ARGF.readchar }
13706 * ARGF.eof? #=> false
13707 * ARGF.readchar #=> "\n"
13708 * ARGF.eof? #=> true
13709 */
13710
13711static VALUE
13712argf_eof(VALUE argf)
13713{
13714 next_argv();
13715 if (RTEST(ARGF.current_file)) {
13716 if (ARGF.init_p == 0) return Qtrue;
13717 next_argv();
13718 ARGF_FORWARD(0, 0);
13719 if (rb_io_eof(ARGF.current_file)) {
13720 return Qtrue;
13721 }
13722 }
13723 return Qfalse;
13724}
13725
13726/*
13727 * call-seq:
13728 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13729 *
13730 * Reads _length_ bytes from ARGF. The files named on the command line
13731 * are concatenated and treated as a single file by this method, so when
13732 * called without arguments the contents of this pseudo file are returned in
13733 * their entirety.
13734 *
13735 * _length_ must be a non-negative integer or +nil+.
13736 *
13737 * If _length_ is a positive integer, +read+ tries to read
13738 * _length_ bytes without any conversion (binary mode).
13739 * It returns +nil+ if an EOF is encountered before anything can be read.
13740 * Fewer than _length_ bytes are returned if an EOF is encountered during
13741 * the read.
13742 * In the case of an integer _length_, the resulting string is always
13743 * in ASCII-8BIT encoding.
13744 *
13745 * If _length_ is omitted or is +nil+, it reads until EOF
13746 * and the encoding conversion is applied, if applicable.
13747 * A string is returned even if EOF is encountered before any data is read.
13748 *
13749 * If _length_ is zero, it returns an empty string (<code>""</code>).
13750 *
13751 * If the optional _outbuf_ argument is present,
13752 * it must reference a String, which will receive the data.
13753 * The _outbuf_ will contain only the received data after the method call
13754 * even if it is not empty at the beginning.
13755 *
13756 * For example:
13757 *
13758 * $ echo "small" > small.txt
13759 * $ echo "large" > large.txt
13760 * $ ./glark.rb small.txt large.txt
13761 *
13762 * ARGF.read #=> "small\nlarge"
13763 * ARGF.read(200) #=> "small\nlarge"
13764 * ARGF.read(2) #=> "sm"
13765 * ARGF.read(0) #=> ""
13766 *
13767 * Note that this method behaves like the fread() function in C.
13768 * This means it retries to invoke read(2) system calls to read data
13769 * with the specified length.
13770 * If you need the behavior like a single read(2) system call,
13771 * consider ARGF#readpartial or ARGF#read_nonblock.
13772 */
13773
13774static VALUE
13775argf_read(int argc, VALUE *argv, VALUE argf)
13776{
13777 VALUE tmp, str, length;
13778 long len = 0;
13779
13780 rb_scan_args(argc, argv, "02", &length, &str);
13781 if (!NIL_P(length)) {
13782 len = NUM2LONG(argv[0]);
13783 }
13784 if (!NIL_P(str)) {
13785 StringValue(str);
13786 rb_str_resize(str,0);
13787 argv[1] = Qnil;
13788 }
13789
13790 retry:
13791 if (!next_argv()) {
13792 return str;
13793 }
13794 if (ARGF_GENERIC_INPUT_P()) {
13795 tmp = argf_forward(argc, argv, argf);
13796 }
13797 else {
13798 tmp = io_read(argc, argv, ARGF.current_file);
13799 }
13800 if (NIL_P(str)) str = tmp;
13801 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13802 if (NIL_P(tmp) || NIL_P(length)) {
13803 if (ARGF.next_p != -1) {
13804 argf_close(argf);
13805 ARGF.next_p = 1;
13806 goto retry;
13807 }
13808 }
13809 else if (argc >= 1) {
13810 long slen = RSTRING_LEN(str);
13811 if (slen < len) {
13812 argv[0] = LONG2NUM(len - slen);
13813 goto retry;
13814 }
13815 }
13816 return str;
13817}
13818
13819 struct argf_call_arg {
13820 int argc;
13821 VALUE *argv;
13822 VALUE argf;
13823};
13824
13825static VALUE
13826argf_forward_call(VALUE arg)
13827{
13828 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13829 argf_forward(p->argc, p->argv, p->argf);
13830 return Qnil;
13831}
13832
13833static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13834 int nonblock);
13835
13836/*
13837 * call-seq:
13838 * ARGF.readpartial(maxlen) -> string
13839 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13840 *
13841 * Reads at most _maxlen_ bytes from the ARGF stream.
13842 *
13843 * If the optional _outbuf_ argument is present,
13844 * it must reference a String, which will receive the data.
13845 * The _outbuf_ will contain only the received data after the method call
13846 * even if it is not empty at the beginning.
13847 *
13848 * It raises EOFError on end of ARGF stream.
13849 * Since ARGF stream is a concatenation of multiple files,
13850 * internally EOF is occur for each file.
13851 * ARGF.readpartial returns empty strings for EOFs except the last one and
13852 * raises EOFError for the last one.
13853 *
13854 */
13855
13856static VALUE
13857argf_readpartial(int argc, VALUE *argv, VALUE argf)
13858{
13859 return argf_getpartial(argc, argv, argf, Qnil, 0);
13860}
13861
13862/*
13863 * call-seq:
13864 * ARGF.read_nonblock(maxlen[, options]) -> string
13865 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13866 *
13867 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13868 */
13869
13870static VALUE
13871argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13872{
13873 VALUE opts;
13874
13875 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13876
13877 if (!NIL_P(opts))
13878 argc--;
13879
13880 return argf_getpartial(argc, argv, argf, opts, 1);
13881}
13882
13883static VALUE
13884argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13885{
13886 VALUE tmp, str, length;
13887 int no_exception;
13888
13889 rb_scan_args(argc, argv, "11", &length, &str);
13890 if (!NIL_P(str)) {
13891 StringValue(str);
13892 argv[1] = str;
13893 }
13894 no_exception = no_exception_p(opts);
13895
13896 if (!next_argv()) {
13897 if (!NIL_P(str)) {
13898 rb_str_resize(str, 0);
13899 }
13900 rb_eof_error();
13901 }
13902 if (ARGF_GENERIC_INPUT_P()) {
13903 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13904 struct argf_call_arg arg;
13905 arg.argc = argc;
13906 arg.argv = argv;
13907 arg.argf = argf;
13908 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
13909 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
13910 }
13911 else {
13912 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13913 }
13914 if (NIL_P(tmp)) {
13915 if (ARGF.next_p == -1) {
13916 return io_nonblock_eof(no_exception);
13917 }
13918 argf_close(argf);
13919 ARGF.next_p = 1;
13920 if (RARRAY_LEN(ARGF.argv) == 0) {
13921 return io_nonblock_eof(no_exception);
13922 }
13923 if (NIL_P(str))
13924 str = rb_str_new(NULL, 0);
13925 return str;
13926 }
13927 return tmp;
13928}
13929
13930/*
13931 * call-seq:
13932 * ARGF.getc -> String or nil
13933 *
13934 * Reads the next character from ARGF and returns it as a String. Returns
13935 * +nil+ at the end of the stream.
13936 *
13937 * ARGF treats the files named on the command line as a single file created
13938 * by concatenating their contents. After returning the last character of the
13939 * first file, it returns the first character of the second file, and so on.
13940 *
13941 * For example:
13942 *
13943 * $ echo "foo" > file
13944 * $ ruby argf.rb file
13945 *
13946 * ARGF.getc #=> "f"
13947 * ARGF.getc #=> "o"
13948 * ARGF.getc #=> "o"
13949 * ARGF.getc #=> "\n"
13950 * ARGF.getc #=> nil
13951 * ARGF.getc #=> nil
13952 */
13953static VALUE
13954argf_getc(VALUE argf)
13955{
13956 VALUE ch;
13957
13958 retry:
13959 if (!next_argv()) return Qnil;
13960 if (ARGF_GENERIC_INPUT_P()) {
13961 ch = forward_current(rb_intern("getc"), 0, 0);
13962 }
13963 else {
13964 ch = rb_io_getc(ARGF.current_file);
13965 }
13966 if (NIL_P(ch) && ARGF.next_p != -1) {
13967 argf_close(argf);
13968 ARGF.next_p = 1;
13969 goto retry;
13970 }
13971
13972 return ch;
13973}
13974
13975/*
13976 * call-seq:
13977 * ARGF.getbyte -> Integer or nil
13978 *
13979 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
13980 * the end of the stream.
13981 *
13982 * For example:
13983 *
13984 * $ echo "foo" > file
13985 * $ ruby argf.rb file
13986 *
13987 * ARGF.getbyte #=> 102
13988 * ARGF.getbyte #=> 111
13989 * ARGF.getbyte #=> 111
13990 * ARGF.getbyte #=> 10
13991 * ARGF.getbyte #=> nil
13992 */
13993static VALUE
13994argf_getbyte(VALUE argf)
13995{
13996 VALUE ch;
13997
13998 retry:
13999 if (!next_argv()) return Qnil;
14000 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14001 ch = forward_current(rb_intern("getbyte"), 0, 0);
14002 }
14003 else {
14004 ch = rb_io_getbyte(ARGF.current_file);
14005 }
14006 if (NIL_P(ch) && ARGF.next_p != -1) {
14007 argf_close(argf);
14008 ARGF.next_p = 1;
14009 goto retry;
14010 }
14011
14012 return ch;
14013}
14014
14015/*
14016 * call-seq:
14017 * ARGF.readchar -> String or nil
14018 *
14019 * Reads the next character from ARGF and returns it as a String. Raises
14020 * an EOFError after the last character of the last file has been read.
14021 *
14022 * For example:
14023 *
14024 * $ echo "foo" > file
14025 * $ ruby argf.rb file
14026 *
14027 * ARGF.readchar #=> "f"
14028 * ARGF.readchar #=> "o"
14029 * ARGF.readchar #=> "o"
14030 * ARGF.readchar #=> "\n"
14031 * ARGF.readchar #=> end of file reached (EOFError)
14032 */
14033static VALUE
14034argf_readchar(VALUE argf)
14035{
14036 VALUE ch;
14037
14038 retry:
14039 if (!next_argv()) rb_eof_error();
14040 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14041 ch = forward_current(rb_intern("getc"), 0, 0);
14042 }
14043 else {
14044 ch = rb_io_getc(ARGF.current_file);
14045 }
14046 if (NIL_P(ch) && ARGF.next_p != -1) {
14047 argf_close(argf);
14048 ARGF.next_p = 1;
14049 goto retry;
14050 }
14051
14052 return ch;
14053}
14054
14055/*
14056 * call-seq:
14057 * ARGF.readbyte -> Integer
14058 *
14059 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14060 * an EOFError after the last byte of the last file has been read.
14061 *
14062 * For example:
14063 *
14064 * $ echo "foo" > file
14065 * $ ruby argf.rb file
14066 *
14067 * ARGF.readbyte #=> 102
14068 * ARGF.readbyte #=> 111
14069 * ARGF.readbyte #=> 111
14070 * ARGF.readbyte #=> 10
14071 * ARGF.readbyte #=> end of file reached (EOFError)
14072 */
14073static VALUE
14074argf_readbyte(VALUE argf)
14075{
14076 VALUE c;
14077
14078 NEXT_ARGF_FORWARD(0, 0);
14079 c = argf_getbyte(argf);
14080 if (NIL_P(c)) {
14081 rb_eof_error();
14082 }
14083 return c;
14084}
14085
14086#define FOREACH_ARGF() while (next_argv())
14087
14088static VALUE
14089argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14090{
14091 const VALUE current = ARGF.current_file;
14092 rb_yield_values2(argc, argv);
14093 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14094 rb_iter_break_value(Qundef);
14095 }
14096 return Qnil;
14097}
14098
14099#define ARGF_block_call(mid, argc, argv, func, argf) \
14100 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14101 func, argf, rb_keyword_given_p())
14102
14103static void
14104argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14105{
14106 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14107 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14108}
14109
14110static VALUE
14111argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14112{
14113 if (!global_argf_p(argf)) {
14114 ARGF.last_lineno = ++ARGF.lineno;
14115 }
14116 return argf_block_call_i(i, argf, argc, argv, blockarg);
14117}
14118
14119static void
14120argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14121{
14122 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14123 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14124}
14125
14126/*
14127 * call-seq:
14128 * ARGF.each(sep=$/) {|line| block } -> ARGF
14129 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14130 * ARGF.each(...) -> an_enumerator
14131 *
14132 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14133 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14134 * ARGF.each_line(...) -> an_enumerator
14135 *
14136 * Returns an enumerator which iterates over each line (separated by _sep_,
14137 * which defaults to your platform's newline character) of each file in
14138 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14139 * block, otherwise an enumerator is returned.
14140 * The optional _limit_ argument is an Integer specifying the maximum
14141 * length of each line; longer lines will be split according to this limit.
14142 *
14143 * This method allows you to treat the files supplied on the command line as
14144 * a single file consisting of the concatenation of each named file. After
14145 * the last line of the first file has been returned, the first line of the
14146 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14147 * used to determine the filename of the current line and line number of the
14148 * whole input, respectively.
14149 *
14150 * For example, the following code prints out each line of each named file
14151 * prefixed with its line number, displaying the filename once per file:
14152 *
14153 * ARGF.each_line do |line|
14154 * puts ARGF.filename if ARGF.file.lineno == 1
14155 * puts "#{ARGF.file.lineno}: #{line}"
14156 * end
14157 *
14158 * While the following code prints only the first file's name at first, and
14159 * the contents with line number counted through all named files.
14160 *
14161 * ARGF.each_line do |line|
14162 * puts ARGF.filename if ARGF.lineno == 1
14163 * puts "#{ARGF.lineno}: #{line}"
14164 * end
14165 */
14166static VALUE
14167argf_each_line(int argc, VALUE *argv, VALUE argf)
14168{
14169 RETURN_ENUMERATOR(argf, argc, argv);
14170 FOREACH_ARGF() {
14171 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14172 }
14173 return argf;
14174}
14175
14176/*
14177 * call-seq:
14178 * ARGF.each_byte {|byte| block } -> ARGF
14179 * ARGF.each_byte -> an_enumerator
14180 *
14181 * Iterates over each byte of each file in +ARGV+.
14182 * A byte is returned as an Integer in the range 0..255.
14183 *
14184 * This method allows you to treat the files supplied on the command line as
14185 * a single file consisting of the concatenation of each named file. After
14186 * the last byte of the first file has been returned, the first byte of the
14187 * second file is returned. The ARGF.filename method can be used to
14188 * determine the filename of the current byte.
14189 *
14190 * If no block is given, an enumerator is returned instead.
14191 *
14192 * For example:
14193 *
14194 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14195 *
14196 */
14197static VALUE
14198argf_each_byte(VALUE argf)
14199{
14200 RETURN_ENUMERATOR(argf, 0, 0);
14201 FOREACH_ARGF() {
14202 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14203 }
14204 return argf;
14205}
14206
14207/*
14208 * call-seq:
14209 * ARGF.each_char {|char| block } -> ARGF
14210 * ARGF.each_char -> an_enumerator
14211 *
14212 * Iterates over each character of each file in ARGF.
14213 *
14214 * This method allows you to treat the files supplied on the command line as
14215 * a single file consisting of the concatenation of each named file. After
14216 * the last character of the first file has been returned, the first
14217 * character of the second file is returned. The ARGF.filename method can
14218 * be used to determine the name of the file in which the current character
14219 * appears.
14220 *
14221 * If no block is given, an enumerator is returned instead.
14222 */
14223static VALUE
14224argf_each_char(VALUE argf)
14225{
14226 RETURN_ENUMERATOR(argf, 0, 0);
14227 FOREACH_ARGF() {
14228 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14229 }
14230 return argf;
14231}
14232
14233/*
14234 * call-seq:
14235 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14236 * ARGF.each_codepoint -> an_enumerator
14237 *
14238 * Iterates over each codepoint of each file in ARGF.
14239 *
14240 * This method allows you to treat the files supplied on the command line as
14241 * a single file consisting of the concatenation of each named file. After
14242 * the last codepoint of the first file has been returned, the first
14243 * codepoint of the second file is returned. The ARGF.filename method can
14244 * be used to determine the name of the file in which the current codepoint
14245 * appears.
14246 *
14247 * If no block is given, an enumerator is returned instead.
14248 */
14249static VALUE
14250argf_each_codepoint(VALUE argf)
14251{
14252 RETURN_ENUMERATOR(argf, 0, 0);
14253 FOREACH_ARGF() {
14254 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14255 }
14256 return argf;
14257}
14258
14259/*
14260 * call-seq:
14261 * ARGF.filename -> String
14262 * ARGF.path -> String
14263 *
14264 * Returns the current filename. "-" is returned when the current file is
14265 * STDIN.
14266 *
14267 * For example:
14268 *
14269 * $ echo "foo" > foo
14270 * $ echo "bar" > bar
14271 * $ echo "glark" > glark
14272 *
14273 * $ ruby argf.rb foo bar glark
14274 *
14275 * ARGF.filename #=> "foo"
14276 * ARGF.read(5) #=> "foo\nb"
14277 * ARGF.filename #=> "bar"
14278 * ARGF.skip
14279 * ARGF.filename #=> "glark"
14280 */
14281static VALUE
14282argf_filename(VALUE argf)
14283{
14284 next_argv();
14285 return ARGF.filename;
14286}
14287
14288static VALUE
14289argf_filename_getter(ID id, VALUE *var)
14290{
14291 return argf_filename(*var);
14292}
14293
14294/*
14295 * call-seq:
14296 * ARGF.file -> IO or File object
14297 *
14298 * Returns the current file as an IO or File object.
14299 * <code>$stdin</code> is returned when the current file is STDIN.
14300 *
14301 * For example:
14302 *
14303 * $ echo "foo" > foo
14304 * $ echo "bar" > bar
14305 *
14306 * $ ruby argf.rb foo bar
14307 *
14308 * ARGF.file #=> #<File:foo>
14309 * ARGF.read(5) #=> "foo\nb"
14310 * ARGF.file #=> #<File:bar>
14311 */
14312static VALUE
14313argf_file(VALUE argf)
14314{
14315 next_argv();
14316 return ARGF.current_file;
14317}
14318
14319/*
14320 * call-seq:
14321 * ARGF.binmode -> ARGF
14322 *
14323 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14324 * be reset to non-binary mode. This option has the following effects:
14325 *
14326 * * Newline conversion is disabled.
14327 * * Encoding conversion is disabled.
14328 * * Content is treated as ASCII-8BIT.
14329 */
14330static VALUE
14331argf_binmode_m(VALUE argf)
14332{
14333 ARGF.binmode = 1;
14334 next_argv();
14335 ARGF_FORWARD(0, 0);
14336 rb_io_ascii8bit_binmode(ARGF.current_file);
14337 return argf;
14338}
14339
14340/*
14341 * call-seq:
14342 * ARGF.binmode? -> true or false
14343 *
14344 * Returns true if ARGF is being read in binary mode; false otherwise.
14345 * To enable binary mode use ARGF.binmode.
14346 *
14347 * For example:
14348 *
14349 * ARGF.binmode? #=> false
14350 * ARGF.binmode
14351 * ARGF.binmode? #=> true
14352 */
14353static VALUE
14354argf_binmode_p(VALUE argf)
14355{
14356 return RBOOL(ARGF.binmode);
14357}
14358
14359/*
14360 * call-seq:
14361 * ARGF.skip -> ARGF
14362 *
14363 * Sets the current file to the next file in ARGV. If there aren't any more
14364 * files it has no effect.
14365 *
14366 * For example:
14367 *
14368 * $ ruby argf.rb foo bar
14369 * ARGF.filename #=> "foo"
14370 * ARGF.skip
14371 * ARGF.filename #=> "bar"
14372 */
14373static VALUE
14374argf_skip(VALUE argf)
14375{
14376 if (ARGF.init_p && ARGF.next_p == 0) {
14377 argf_close(argf);
14378 ARGF.next_p = 1;
14379 }
14380 return argf;
14381}
14382
14383/*
14384 * call-seq:
14385 * ARGF.close -> ARGF
14386 *
14387 * Closes the current file and skips to the next file in ARGV. If there are
14388 * no more files to open, just closes the current file. STDIN will not be
14389 * closed.
14390 *
14391 * For example:
14392 *
14393 * $ ruby argf.rb foo bar
14394 *
14395 * ARGF.filename #=> "foo"
14396 * ARGF.close
14397 * ARGF.filename #=> "bar"
14398 * ARGF.close
14399 */
14400static VALUE
14401argf_close_m(VALUE argf)
14402{
14403 next_argv();
14404 argf_close(argf);
14405 if (ARGF.next_p != -1) {
14406 ARGF.next_p = 1;
14407 }
14408 ARGF.lineno = 0;
14409 return argf;
14410}
14411
14412/*
14413 * call-seq:
14414 * ARGF.closed? -> true or false
14415 *
14416 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14417 * ARGF.close to actually close the current file.
14418 */
14419static VALUE
14420argf_closed(VALUE argf)
14421{
14422 next_argv();
14423 ARGF_FORWARD(0, 0);
14424 return rb_io_closed(ARGF.current_file);
14425}
14426
14427/*
14428 * call-seq:
14429 * ARGF.to_s -> String
14430 *
14431 * Returns "ARGF".
14432 */
14433static VALUE
14434argf_to_s(VALUE argf)
14435{
14436 return rb_str_new2("ARGF");
14437}
14438
14439/*
14440 * call-seq:
14441 * ARGF.inplace_mode -> String
14442 *
14443 * Returns the file extension appended to the names of backup copies of
14444 * modified files under in-place edit mode. This value can be set using
14445 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14446 */
14447static VALUE
14448argf_inplace_mode_get(VALUE argf)
14449{
14450 if (!ARGF.inplace) return Qnil;
14451 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14452 return rb_str_dup(ARGF.inplace);
14453}
14454
14455static VALUE
14456opt_i_get(ID id, VALUE *var)
14457{
14458 return argf_inplace_mode_get(*var);
14459}
14460
14461/*
14462 * call-seq:
14463 * ARGF.inplace_mode = ext -> ARGF
14464 *
14465 * Sets the filename extension for in-place editing mode to the given String.
14466 * The backup copy of each file being edited has this value appended to its
14467 * filename.
14468 *
14469 * For example:
14470 *
14471 * $ ruby argf.rb file.txt
14472 *
14473 * ARGF.inplace_mode = '.bak'
14474 * ARGF.each_line do |line|
14475 * print line.sub("foo","bar")
14476 * end
14477 *
14478 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14479 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14480 * "bar".
14481 */
14482static VALUE
14483argf_inplace_mode_set(VALUE argf, VALUE val)
14484{
14485 if (!RTEST(val)) {
14486 ARGF.inplace = Qfalse;
14487 }
14488 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14489 ARGF.inplace = Qnil;
14490 }
14491 else {
14492 ARGF.inplace = rb_str_new_frozen(val);
14493 }
14494 return argf;
14495}
14496
14497static void
14498opt_i_set(VALUE val, ID id, VALUE *var)
14499{
14500 argf_inplace_mode_set(*var, val);
14501}
14502
14503void
14504ruby_set_inplace_mode(const char *suffix)
14505{
14506 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14507}
14508
14509/*
14510 * call-seq:
14511 * ARGF.argv -> ARGV
14512 *
14513 * Returns the +ARGV+ array, which contains the arguments passed to your
14514 * script, one per element.
14515 *
14516 * For example:
14517 *
14518 * $ ruby argf.rb -v glark.txt
14519 *
14520 * ARGF.argv #=> ["-v", "glark.txt"]
14521 *
14522 */
14523static VALUE
14524argf_argv(VALUE argf)
14525{
14526 return ARGF.argv;
14527}
14528
14529static VALUE
14530argf_argv_getter(ID id, VALUE *var)
14531{
14532 return argf_argv(*var);
14533}
14534
14535 VALUE
14536rb_get_argv(void)
14537{
14538 return ARGF.argv;
14539}
14540
14541/*
14542 * call-seq:
14543 * ARGF.to_write_io -> io
14544 *
14545 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14546 * enabled.
14547 */
14548static VALUE
14549argf_write_io(VALUE argf)
14550{
14551 if (!RTEST(ARGF.current_file)) {
14552 rb_raise(rb_eIOError, "not opened for writing");
14553 }
14554 return GetWriteIO(ARGF.current_file);
14555}
14556
14557/*
14558 * call-seq:
14559 * ARGF.write(string) -> integer
14560 *
14561 * Writes _string_ if inplace mode.
14562 */
14563static VALUE
14564argf_write(VALUE argf, VALUE str)
14565{
14566 return rb_io_write(argf_write_io(argf), str);
14567}
14568
14569void
14570rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14571{
14572 rb_readwrite_syserr_fail(waiting, errno, mesg);
14573}
14574
14575void
14576rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14577{
14578 VALUE arg, c = Qnil;
14579 arg = mesg ? rb_str_new2(mesg) : Qnil;
14580 switch (waiting) {
14581 case RB_IO_WAIT_WRITABLE:
14582 switch (n) {
14583 case EAGAIN:
14584 c = rb_eEAGAINWaitWritable;
14585 break;
14586#if EAGAIN != EWOULDBLOCK
14587 case EWOULDBLOCK:
14588 c = rb_eEWOULDBLOCKWaitWritable;
14589 break;
14590#endif
14591 case EINPROGRESS:
14592 c = rb_eEINPROGRESSWaitWritable;
14593 break;
14594 default:
14595 rb_mod_syserr_fail_str(rb_mWaitWritable, n, arg);
14596 }
14597 break;
14598 case RB_IO_WAIT_READABLE:
14599 switch (n) {
14600 case EAGAIN:
14601 c = rb_eEAGAINWaitReadable;
14602 break;
14603#if EAGAIN != EWOULDBLOCK
14604 case EWOULDBLOCK:
14605 c = rb_eEWOULDBLOCKWaitReadable;
14606 break;
14607#endif
14608 case EINPROGRESS:
14609 c = rb_eEINPROGRESSWaitReadable;
14610 break;
14611 default:
14612 rb_mod_syserr_fail_str(rb_mWaitReadable, n, arg);
14613 }
14614 break;
14615 default:
14616 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14617 }
14618 rb_exc_raise(rb_class_new_instance(1, &arg, c));
14619}
14620
14621static VALUE
14622get_LAST_READ_LINE(ID _x, VALUE *_y)
14623{
14624 return rb_lastline_get();
14625}
14626
14627static void
14628set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14629{
14630 rb_lastline_set(val);
14631}
14632
14633/*
14634 * Document-class: IOError
14635 *
14636 * Raised when an IO operation fails.
14637 *
14638 * File.open("/etc/hosts") {|f| f << "example"}
14639 * #=> IOError: not opened for writing
14640 *
14641 * File.open("/etc/hosts") {|f| f.close; f.read }
14642 * #=> IOError: closed stream
14643 *
14644 * Note that some IO failures raise <code>SystemCallError</code>s
14645 * and these are not subclasses of IOError:
14646 *
14647 * File.open("does/not/exist")
14648 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14649 */
14650
14651/*
14652 * Document-class: EOFError
14653 *
14654 * Raised by some IO operations when reaching the end of file. Many IO
14655 * methods exist in two forms,
14656 *
14657 * one that returns +nil+ when the end of file is reached, the other
14658 * raises EOFError.
14659 *
14660 * EOFError is a subclass of IOError.
14661 *
14662 * file = File.open("/etc/hosts")
14663 * file.read
14664 * file.gets #=> nil
14665 * file.readline #=> EOFError: end of file reached
14666 * file.close
14667 */
14668
14669/*
14670 * Document-class: ARGF
14671 *
14672 * ARGF is a stream designed for use in scripts that process files given as
14673 * command-line arguments or passed in via STDIN.
14674 *
14675 * The arguments passed to your script are stored in the +ARGV+ Array, one
14676 * argument per element. ARGF assumes that any arguments that aren't
14677 * filenames have been removed from +ARGV+. For example:
14678 *
14679 * $ ruby argf.rb --verbose file1 file2
14680 *
14681 * ARGV #=> ["--verbose", "file1", "file2"]
14682 * option = ARGV.shift #=> "--verbose"
14683 * ARGV #=> ["file1", "file2"]
14684 *
14685 * You can now use ARGF to work with a concatenation of each of these named
14686 * files. For instance, ARGF.read will return the contents of _file1_
14687 * followed by the contents of _file2_.
14688 *
14689 * After a file in +ARGV+ has been read ARGF removes it from the Array.
14690 * Thus, after all files have been read +ARGV+ will be empty.
14691 *
14692 * You can manipulate +ARGV+ yourself to control what ARGF operates on. If
14693 * you remove a file from +ARGV+, it is ignored by ARGF; if you add files to
14694 * +ARGV+, they are treated as if they were named on the command line. For
14695 * example:
14696 *
14697 * ARGV.replace ["file1"]
14698 * ARGF.readlines # Returns the contents of file1 as an Array
14699 * ARGV #=> []
14700 * ARGV.replace ["file2", "file3"]
14701 * ARGF.read # Returns the contents of file2 and file3
14702 *
14703 * If +ARGV+ is empty, ARGF acts as if it contained STDIN, i.e. the data
14704 * piped to your script. For example:
14705 *
14706 * $ echo "glark" | ruby -e 'p ARGF.read'
14707 * "glark\n"
14708 */
14709
14710/*
14711 * An instance of class \IO (commonly called a _stream_)
14712 * represents an input/output stream in the underlying operating system.
14713 * \Class \IO is the basis for input and output in Ruby.
14714 *
14715 * \Class File is the only class in the Ruby core that is a subclass of \IO.
14716 * Some classes in the Ruby standard library are also subclasses of \IO;
14717 * these include TCPSocket and UDPSocket.
14718 *
14719 * The global constant ARGF (also accessible as <tt>$<</tt>)
14720 * provides an IO-like stream that allows access to all file paths
14721 * found in ARGV (or found in STDIN if ARGV is empty).
14722 * ARGF is not itself a subclass of \IO.
14723 *
14724 * \Class StringIO provides an IO-like stream that handles a String.
14725 * \StringIO is not itself a subclass of \IO.
14726 *
14727 * Important objects based on \IO include:
14728 *
14729 * - $stdin.
14730 * - $stdout.
14731 * - $stderr.
14732 * - Instances of class File.
14733 *
14734 * An instance of \IO may be created using:
14735 *
14736 * - IO.new: returns a new \IO object for the given integer file descriptor.
14737 * - IO.open: passes a new \IO object to the given block.
14738 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
14739 * of a newly-launched subprocess.
14740 * - Kernel#open: Returns a new \IO object connected to a given source:
14741 * stream, file, or subprocess.
14742 *
14743 * Like a \File stream, an \IO stream has:
14744 *
14745 * - A read/write mode, which may be read-only, write-only, or read/write;
14746 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
14747 * - A data mode, which may be text-only or binary;
14748 * see {Data Mode}[rdoc-ref:File@Data+Mode].
14749 * - Internal and external encodings;
14750 * see {Encodings}[rdoc-ref:File@Encodings].
14751 *
14752 * And like other \IO streams, it has:
14753 *
14754 * - A position, which determines where in the stream the next
14755 * read or write is to occur;
14756 * see {Position}[rdoc-ref:IO@Position].
14757 * - A line number, which is a special, line-oriented, "position"
14758 * (different from the position mentioned above);
14759 * see {Line Number}[rdoc-ref:IO@Line+Number].
14760 *
14761 * == Extension <tt>io/console</tt>
14762 *
14763 * Extension <tt>io/console</tt> provides numerous methods
14764 * for interacting with the console;
14765 * requiring it adds numerous methods to class \IO.
14766 *
14767 * == Example Files
14768 *
14769 * Many examples here use these variables:
14770 *
14771 * :include: doc/examples/files.rdoc
14772 *
14773 * == Open Options
14774 *
14775 * A number of \IO methods accept optional keyword arguments
14776 * that determine how a new stream is to be opened:
14777 *
14778 * - +:mode+: Stream mode.
14779 * - +:flags+: \Integer file open flags;
14780 * If +mode+ is also given, the two are bitwise-ORed.
14781 * - +:external_encoding+: External encoding for the stream.
14782 * - +:internal_encoding+: Internal encoding for the stream.
14783 * <tt>'-'</tt> is a synonym for the default internal encoding.
14784 * If the value is +nil+ no conversion occurs.
14785 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
14786 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
14787 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
14788 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
14789 * when the stream closes; otherwise it remains open.
14790 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
14791 * #path method.
14792 *
14793 * Also available are the options offered in String#encode,
14794 * which may control conversion between external internal encoding.
14795 *
14796 * == Basic \IO
14797 *
14798 * You can perform basic stream \IO with these methods,
14799 * which typically operate on multi-byte strings:
14800 *
14801 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
14802 * - IO#write: Writes zero or more strings to the stream;
14803 * each given object that is not already a string is converted via +to_s+.
14804 *
14805 * === Position
14806 *
14807 * An \IO stream has a nonnegative integer _position_,
14808 * which is the byte offset at which the next read or write is to occur.
14809 * A new stream has position zero (and line number zero);
14810 * method +rewind+ resets the position (and line number) to zero.
14811 *
14812 * The relevant methods:
14813 *
14814 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
14815 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
14816 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
14817 * relative to a given position +whence+
14818 * (indicating the beginning, end, or current position).
14819 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
14820 *
14821 * === Open and Closed Streams
14822 *
14823 * A new \IO stream may be open for reading, open for writing, or both.
14824 *
14825 * A stream is automatically closed when claimed by the garbage collector.
14826 *
14827 * Attempted reading or writing on a closed stream raises an exception.
14828 *
14829 * The relevant methods:
14830 *
14831 * - IO#close: Closes the stream for both reading and writing.
14832 * - IO#close_read: Closes the stream for reading.
14833 * - IO#close_write: Closes the stream for writing.
14834 * - IO#closed?: Returns whether the stream is closed.
14835 *
14836 * === End-of-Stream
14837 *
14838 * You can query whether a stream is positioned at its end:
14839 *
14840 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
14841 *
14842 * You can reposition to end-of-stream by using method IO#seek:
14843 *
14844 * f = File.new('t.txt')
14845 * f.eof? # => false
14846 * f.seek(0, :END)
14847 * f.eof? # => true
14848 * f.close
14849 *
14850 * Or by reading all stream content (which is slower than using IO#seek):
14851 *
14852 * f.rewind
14853 * f.eof? # => false
14854 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14855 * f.eof? # => true
14856 *
14857 * == Line \IO
14858 *
14859 * You can read an \IO stream line-by-line using these methods:
14860 *
14861 * - IO#each_line: Reads each remaining line, passing it to the given block.
14862 * - IO#gets: Returns the next line.
14863 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
14864 * - IO#readlines: Returns all remaining lines in an array.
14865 *
14866 * Each of these reader methods accepts:
14867 *
14868 * - An optional line separator, +sep+;
14869 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
14870 * - An optional line-size limit, +limit+;
14871 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
14872 *
14873 * For each of these reader methods, reading may begin mid-line,
14874 * depending on the stream's position;
14875 * see {Position}[rdoc-ref:IO@Position]:
14876 *
14877 * f = File.new('t.txt')
14878 * f.pos = 27
14879 * f.each_line {|line| p line }
14880 * f.close
14881 *
14882 * Output:
14883 *
14884 * "rth line\n"
14885 * "Fifth line\n"
14886 *
14887 * You can write to an \IO stream line-by-line using this method:
14888 *
14889 * - IO#puts: Writes objects to the stream.
14890 *
14891 * === Line Separator
14892 *
14893 * Each of these methods uses a <i>line separator</i>,
14894 * which is the string that delimits lines:
14895 *
14896 * - IO.foreach.
14897 * - IO.readlines.
14898 * - IO#each_line.
14899 * - IO#gets.
14900 * - IO#readline.
14901 * - IO#readlines.
14902 *
14903 * The default line separator is the given by the global variable <tt>$/</tt>,
14904 * whose value is by default <tt>"\n"</tt>.
14905 * The line to be read next is all data from the current position
14906 * to the next line separator:
14907 *
14908 * f = File.new('t.txt')
14909 * f.gets # => "First line\n"
14910 * f.gets # => "Second line\n"
14911 * f.gets # => "\n"
14912 * f.gets # => "Fourth line\n"
14913 * f.gets # => "Fifth line\n"
14914 * f.close
14915 *
14916 * You can specify a different line separator:
14917 *
14918 * f = File.new('t.txt')
14919 * f.gets('l') # => "First l"
14920 * f.gets('li') # => "ine\nSecond li"
14921 * f.gets('lin') # => "ne\n\nFourth lin"
14922 * f.gets # => "e\n"
14923 * f.close
14924 *
14925 * There are two special line separators:
14926 *
14927 * - +nil+: The entire stream is read into a single string:
14928 *
14929 * f = File.new('t.txt')
14930 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14931 * f.close
14932 *
14933 * - <tt>''</tt> (the empty string): The next "paragraph" is read
14934 * (paragraphs being separated by two consecutive line separators):
14935 *
14936 * f = File.new('t.txt')
14937 * f.gets('') # => "First line\nSecond line\n\n"
14938 * f.gets('') # => "Fourth line\nFifth line\n"
14939 * f.close
14940 *
14941 * === Line Limit
14942 *
14943 * Each of these methods uses a <i>line limit</i>,
14944 * which specifies that the number of bytes returned may not be (much) longer
14945 * than the given +limit+;
14946 *
14947 * - IO.foreach.
14948 * - IO.readlines.
14949 * - IO#each_line.
14950 * - IO#gets.
14951 * - IO#readline.
14952 * - IO#readlines.
14953 *
14954 * A multi-byte character will not be split, and so a line may be slightly longer
14955 * than the given limit.
14956 *
14957 * If +limit+ is not given, the line is determined only by +sep+.
14958 *
14959 * # Text with 1-byte characters.
14960 * File.open('t.txt') {|f| f.gets(1) } # => "F"
14961 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
14962 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
14963 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
14964 * # No more than one line.
14965 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
14966 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
14967 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
14968 *
14969 * # Text with 2-byte characters, which will not be split.
14970 * File.open('t.rus') {|f| f.gets(1).size } # => 1
14971 * File.open('t.rus') {|f| f.gets(2).size } # => 1
14972 * File.open('t.rus') {|f| f.gets(3).size } # => 2
14973 * File.open('t.rus') {|f| f.gets(4).size } # => 2
14974 *
14975 * === Line Separator and Line Limit
14976 *
14977 * With arguments +sep+ and +limit+ given,
14978 * combines the two behaviors:
14979 *
14980 * - Returns the next line as determined by line separator +sep+.
14981 * - But returns no more bytes than are allowed by the limit.
14982 *
14983 * Example:
14984 *
14985 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
14986 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
14987 *
14988 * === Line Number
14989 *
14990 * A readable \IO stream has a non-negative integer <i>line number</i>.
14991 *
14992 * The relevant methods:
14993 *
14994 * - IO#lineno: Returns the line number.
14995 * - IO#lineno=: Resets and returns the line number.
14996 *
14997 * Unless modified by a call to method IO#lineno=,
14998 * the line number is the number of lines read
14999 * by certain line-oriented methods,
15000 * according to the given line separator +sep+:
15001 *
15002 * - IO.foreach: Increments the line number on each call to the block.
15003 * - IO#each_line: Increments the line number on each call to the block.
15004 * - IO#gets: Increments the line number.
15005 * - IO#readline: Increments the line number.
15006 * - IO#readlines: Increments the line number for each line read.
15007 *
15008 * A new stream is initially has line number zero (and position zero);
15009 * method +rewind+ resets the line number (and position) to zero:
15010 *
15011 * f = File.new('t.txt')
15012 * f.lineno # => 0
15013 * f.gets # => "First line\n"
15014 * f.lineno # => 1
15015 * f.rewind
15016 * f.lineno # => 0
15017 * f.close
15018 *
15019 * Reading lines from a stream usually changes its line number:
15020 *
15021 * f = File.new('t.txt', 'r')
15022 * f.lineno # => 0
15023 * f.readline # => "This is line one.\n"
15024 * f.lineno # => 1
15025 * f.readline # => "This is the second line.\n"
15026 * f.lineno # => 2
15027 * f.readline # => "Here's the third line.\n"
15028 * f.lineno # => 3
15029 * f.eof? # => true
15030 * f.close
15031 *
15032 * Iterating over lines in a stream usually changes its line number:
15033 *
15034 * File.open('t.txt') do |f|
15035 * f.each_line do |line|
15036 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15037 * end
15038 * end
15039 *
15040 * Output:
15041 *
15042 * "position=11 eof?=false lineno=1"
15043 * "position=23 eof?=false lineno=2"
15044 * "position=24 eof?=false lineno=3"
15045 * "position=36 eof?=false lineno=4"
15046 * "position=47 eof?=true lineno=5"
15047 *
15048 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15049 * the line number does not affect where the next read or write will occur:
15050 *
15051 * f = File.new('t.txt')
15052 * f.lineno = 1000
15053 * f.lineno # => 1000
15054 * f.gets # => "First line\n"
15055 * f.lineno # => 1001
15056 * f.close
15057 *
15058 * Associated with the line number is the global variable <tt>$.</tt>:
15059 *
15060 * - When a stream is opened, <tt>$.</tt> is not set;
15061 * its value is left over from previous activity in the process:
15062 *
15063 * $. = 41
15064 * f = File.new('t.txt')
15065 * $. = 41
15066 * # => 41
15067 * f.close
15068 *
15069 * - When a stream is read, <tt>#.</tt> is set to the line number for that stream:
15070 *
15071 * f0 = File.new('t.txt')
15072 * f1 = File.new('t.dat')
15073 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15074 * $. # => 5
15075 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15076 * $. # => 1
15077 * f0.close
15078 * f1.close
15079 *
15080 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15081 *
15082 * f = File.new('t.txt')
15083 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15084 * $. # => 5
15085 * f.rewind
15086 * f.seek(0, :SET)
15087 * $. # => 5
15088 * f.close
15089 *
15090 * == Character \IO
15091 *
15092 * You can process an \IO stream character-by-character using these methods:
15093 *
15094 * - IO#getc: Reads and returns the next character from the stream.
15095 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15096 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15097 * - IO#putc: Writes a character to the stream.
15098 * - IO#each_char: Reads each remaining character in the stream,
15099 * passing the character to the given block.
15100 * == Byte \IO
15101 *
15102 * You can process an \IO stream byte-by-byte using these methods:
15103 *
15104 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15105 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15106 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15107 * - IO#each_byte: Reads each remaining byte in the stream,
15108 * passing the byte to the given block.
15109 *
15110 * == Codepoint \IO
15111 *
15112 * You can process an \IO stream codepoint-by-codepoint:
15113 *
15114 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15115 *
15116 * == What's Here
15117 *
15118 * First, what's elsewhere. \Class \IO:
15119 *
15120 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15121 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15122 * which provides dozens of additional methods.
15123 *
15124 * Here, class \IO provides methods that are useful for:
15125 *
15126 * - {Creating}[rdoc-ref:IO@Creating]
15127 * - {Reading}[rdoc-ref:IO@Reading]
15128 * - {Writing}[rdoc-ref:IO@Writing]
15129 * - {Positioning}[rdoc-ref:IO@Positioning]
15130 * - {Iterating}[rdoc-ref:IO@Iterating]
15131 * - {Settings}[rdoc-ref:IO@Settings]
15132 * - {Querying}[rdoc-ref:IO@Querying]
15133 * - {Buffering}[rdoc-ref:IO@Buffering]
15134 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15135 * - {Other}[rdoc-ref:IO@Other]
15136 *
15137 * === Creating
15138 *
15139 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15140 * integer file descriptor.
15141 * - ::open: Creates a new \IO object.
15142 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15143 * - ::popen: Creates an \IO object to interact with a subprocess.
15144 * - ::select: Selects which given \IO instances are ready for reading,
15145 * writing, or have pending exceptions.
15146 *
15147 * === Reading
15148 *
15149 * - ::binread: Returns a binary string with all or a subset of bytes
15150 * from the given file.
15151 * - ::read: Returns a string with all or a subset of bytes from the given file.
15152 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15153 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15154 * - #getc: Returns the next character read from +self+ as a string.
15155 * - #gets: Returns the line read from +self+.
15156 * - #pread: Returns all or the next _n_ bytes read from +self+,
15157 * not updating the receiver's offset.
15158 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15159 * for a given _n_.
15160 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15161 * in non-block mode.
15162 * - #readbyte: Returns the next byte read from +self+;
15163 * same as #getbyte, but raises an exception on end-of-stream.
15164 * - #readchar: Returns the next character read from +self+;
15165 * same as #getc, but raises an exception on end-of-stream.
15166 * - #readline: Returns the next line read from +self+;
15167 * same as #getline, but raises an exception of end-of-stream.
15168 * - #readlines: Returns an array of all lines read read from +self+.
15169 * - #readpartial: Returns up to the given number of bytes from +self+.
15170 *
15171 * === Writing
15172 *
15173 * - ::binwrite: Writes the given string to the file at the given filepath,
15174 * in binary mode.
15175 * - ::write: Writes the given string to +self+.
15176 * - #<<: Appends the given string to +self+.
15177 * - #print: Prints last read line or given objects to +self+.
15178 * - #printf: Writes to +self+ based on the given format string and objects.
15179 * - #putc: Writes a character to +self+.
15180 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15181 * - #pwrite: Writes the given string at the given offset,
15182 * not updating the receiver's offset.
15183 * - #write: Writes one or more given strings to +self+.
15184 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15185 *
15186 * === Positioning
15187 *
15188 * - #lineno: Returns the current line number in +self+.
15189 * - #lineno=: Sets the line number is +self+.
15190 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15191 * - #pos=: Sets the byte offset in +self+.
15192 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15193 * - #rewind: Positions +self+ to the beginning of input.
15194 * - #seek: Sets the offset for +self+ relative to given position.
15195 *
15196 * === Iterating
15197 *
15198 * - ::foreach: Yields each line of given file to the block.
15199 * - #each (aliased as #each_line): Calls the given block
15200 * with each successive line in +self+.
15201 * - #each_byte: Calls the given block with each successive byte in +self+
15202 * as an integer.
15203 * - #each_char: Calls the given block with each successive character in +self+
15204 * as a string.
15205 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15206 * as an integer.
15207 *
15208 * === Settings
15209 *
15210 * - #autoclose=: Sets whether +self+ auto-closes.
15211 * - #binmode: Sets +self+ to binary mode.
15212 * - #close: Closes +self+.
15213 * - #close_on_exec=: Sets the close-on-exec flag.
15214 * - #close_read: Closes +self+ for reading.
15215 * - #close_write: Closes +self+ for writing.
15216 * - #set_encoding: Sets the encoding for +self+.
15217 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15218 * Unicode byte-order-mark.
15219 * - #sync=: Sets the sync-mode to the given value.
15220 *
15221 * === Querying
15222 *
15223 * - #autoclose?: Returns whether +self+ auto-closes.
15224 * - #binmode?: Returns whether +self+ is in binary mode.
15225 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15226 * - #closed?: Returns whether +self+ is closed.
15227 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15228 * - #external_encoding: Returns the external encoding object for +self+.
15229 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15230 * - #internal_encoding: Returns the internal encoding object for +self+.
15231 * - #pid: Returns the process ID of a child process associated with +self+,
15232 * if +self+ was created by ::popen.
15233 * - #stat: Returns the File::Stat object containing status information for +self+.
15234 * - #sync: Returns whether +self+ is in sync-mode.
15235 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15236 *
15237 * === Buffering
15238 *
15239 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15240 * - #flush: Flushes any buffered data within +self+ to the underlying
15241 * operating system.
15242 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15243 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15244 * - #ungetc: Prepends buffer for +self+ with given string.
15245 *
15246 * === Low-Level Access
15247 *
15248 * - ::sysopen: Opens the file given by its path,
15249 * returning the integer file descriptor.
15250 * - #advise: Announces the intention to access data from +self+ in a specific way.
15251 * - #fcntl: Passes a low-level command to the file specified
15252 * by the given file descriptor.
15253 * - #ioctl: Passes a low-level command to the device specified
15254 * by the given file descriptor.
15255 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15256 * - #sysseek: Sets the offset for +self+.
15257 * - #syswrite: Writes the given string to +self+ using a low-level write.
15258 *
15259 * === Other
15260 *
15261 * - ::copy_stream: Copies data from a source to a destination,
15262 * each of which is a filepath or an \IO-like object.
15263 * - ::try_convert: Returns a new \IO object resulting from converting
15264 * the given object.
15265 * - #inspect: Returns the string representation of +self+.
15266 *
15267 */
15268
15269void
15270Init_IO(void)
15271{
15272 VALUE rb_cARGF;
15273#ifdef __CYGWIN__
15274#include <sys/cygwin.h>
15275 static struct __cygwin_perfile pf[] =
15276 {
15277 {"", O_RDONLY | O_BINARY},
15278 {"", O_WRONLY | O_BINARY},
15279 {"", O_RDWR | O_BINARY},
15280 {"", O_APPEND | O_BINARY},
15281 {NULL, 0}
15282 };
15283 cygwin_internal(CW_PERFILE, pf);
15284#endif
15285
15286 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15287 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15288
15289 id_write = rb_intern_const("write");
15290 id_read = rb_intern_const("read");
15291 id_getc = rb_intern_const("getc");
15292 id_flush = rb_intern_const("flush");
15293 id_readpartial = rb_intern_const("readpartial");
15294 id_set_encoding = rb_intern_const("set_encoding");
15295 id_fileno = rb_intern_const("fileno");
15296
15297 rb_define_global_function("syscall", rb_f_syscall, -1);
15298
15299 rb_define_global_function("open", rb_f_open, -1);
15300 rb_define_global_function("printf", rb_f_printf, -1);
15301 rb_define_global_function("print", rb_f_print, -1);
15302 rb_define_global_function("putc", rb_f_putc, 1);
15303 rb_define_global_function("puts", rb_f_puts, -1);
15304 rb_define_global_function("gets", rb_f_gets, -1);
15305 rb_define_global_function("readline", rb_f_readline, -1);
15306 rb_define_global_function("select", rb_f_select, -1);
15307
15308 rb_define_global_function("readlines", rb_f_readlines, -1);
15309
15310 rb_define_global_function("`", rb_f_backquote, 1);
15311
15312 rb_define_global_function("p", rb_f_p, -1);
15313 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15314
15315 rb_cIO = rb_define_class("IO", rb_cObject);
15316 rb_include_module(rb_cIO, rb_mEnumerable);
15317
15318 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15319
15320 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15321 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15322 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15323
15324 /* exception to wait for reading. see IO.select. */
15325 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15326 /* exception to wait for writing. see IO.select. */
15327 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15328 /* exception to wait for reading by EAGAIN. see IO.select. */
15329 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15330 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15331 /* exception to wait for writing by EAGAIN. see IO.select. */
15332 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15333 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15334#if EAGAIN == EWOULDBLOCK
15335 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15336 /* same as IO::EAGAINWaitReadable */
15337 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15338 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15339 /* same as IO::EAGAINWaitWritable */
15340 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15341#else
15342 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15343 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15344 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15345 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15346 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15347 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15348#endif
15349 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15350 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15351 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15352 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15353 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15354 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15355
15356#if 0
15357 /* This is necessary only for forcing rdoc handle File::open */
15358 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15359#endif
15360
15361 rb_define_alloc_func(rb_cIO, io_alloc);
15362 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15363 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15364 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15365 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15366 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15367 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15368 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15369 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15370 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15371 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15372 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15373 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15374 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15375 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15376 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15377
15378 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15379
15380 rb_output_fs = Qnil;
15381 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15382
15383 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15384 rb_gc_register_mark_object(rb_default_rs);
15385 rb_rs = rb_default_rs;
15386 rb_output_rs = Qnil;
15387 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15388 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15389 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15390
15391 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15392 rb_gvar_ractor_local("$_");
15393
15394 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15395 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15396
15397 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15398 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15399 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15400 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15401
15402 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15403 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15404 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15405 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15406 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15407
15408 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15409 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15410
15411 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15412 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15413
15414 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15415 rb_define_alias(rb_cIO, "to_i", "fileno");
15416 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15417
15418 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15419 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15420
15421 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15422 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15423 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15424 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15425
15426 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15427 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15428
15429 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15430
15431 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15432 rb_define_method(rb_cIO, "read", io_read, -1);
15433 rb_define_method(rb_cIO, "write", io_write_m, -1);
15434 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15435 rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
15436 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15437 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15438 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15439 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15440 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15441 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15442 rb_define_method(rb_cIO, "<<", rb_io_addstr, 1);
15443 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15444 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15445 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15446 /* Set I/O position from the beginning */
15447 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15448 /* Set I/O position from the current position */
15449 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15450 /* Set I/O position from the end */
15451 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15452#ifdef SEEK_DATA
15453 /* Set I/O position to the next location containing data */
15454 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15455#endif
15456#ifdef SEEK_HOLE
15457 /* Set I/O position to the next hole */
15458 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15459#endif
15460 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15461 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15462 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15463 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15464 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15465
15466 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15467 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15468
15469 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15470 rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
15471 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15472 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15473
15474 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15475 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15476 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15477 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15478 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15479 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15480
15481 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15482 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15483 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15484
15485 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15486 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15487
15488 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15489
15490 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15491 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15492 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15493 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15494
15495 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15496 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15497
15498 rb_define_method(rb_cIO, "wait", io_wait, -1);
15499
15500 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15501 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15502 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15503
15504 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15505 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15506 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15507 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15508
15509 rb_gvar_ractor_local("$stdin");
15510 rb_gvar_ractor_local("$stdout");
15511 rb_gvar_ractor_local("$>");
15512 rb_gvar_ractor_local("$stderr");
15513
15514 rb_stdin = rb_io_prep_stdin();
15515 rb_stdout = rb_io_prep_stdout();
15516 rb_stderr = rb_io_prep_stderr();
15517
15518 rb_global_variable(&rb_stdin);
15519 rb_global_variable(&rb_stdout);
15520 rb_global_variable(&rb_stderr);
15521
15522 orig_stdout = rb_stdout;
15523 orig_stderr = rb_stderr;
15524
15525 /* Holds the original stdin */
15526 rb_define_global_const("STDIN", rb_stdin);
15527 /* Holds the original stdout */
15528 rb_define_global_const("STDOUT", rb_stdout);
15529 /* Holds the original stderr */
15530 rb_define_global_const("STDERR", rb_stderr);
15531
15532#if 0
15533 /* Hack to get rdoc to regard ARGF as a class: */
15534 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15535#endif
15536
15537 rb_cARGF = rb_class_new(rb_cObject);
15538 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15539 rb_define_alloc_func(rb_cARGF, argf_alloc);
15540
15541 rb_include_module(rb_cARGF, rb_mEnumerable);
15542
15543 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15544 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15545 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15546 rb_define_alias(rb_cARGF, "inspect", "to_s");
15547 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15548
15549 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15550 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15551 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15552 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15553 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15554 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15555 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15556 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15557 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15558
15559 rb_define_method(rb_cARGF, "read", argf_read, -1);
15560 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15561 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15562 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15563 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15564 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15565 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15566 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15567 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15568 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15569 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15570 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15571 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15572 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15573 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15574 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15575 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15576 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15577 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15578 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15579
15580 rb_define_method(rb_cARGF, "write", argf_write, 1);
15581 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15582 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15583 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15584 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15585
15586 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15587 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15588 rb_define_method(rb_cARGF, "file", argf_file, 0);
15589 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15590 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15591 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15592
15593 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15594 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15595
15596 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15597 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15598
15599 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15600 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15601 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15602
15603 argf = rb_class_new_instance(0, 0, rb_cARGF);
15604
15605 rb_define_readonly_variable("$<", &argf);
15606 /*
15607 * ARGF is a stream designed for use in scripts that process files given
15608 * as command-line arguments or passed in via STDIN.
15609 *
15610 * See ARGF (the class) for more details.
15611 */
15612 rb_define_global_const("ARGF", argf);
15613
15614 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15615 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15616 ARGF.filename = rb_str_new2("-");
15617
15618 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15619 rb_gvar_ractor_local("$-i");
15620
15621 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15622
15623#if defined (_WIN32) || defined(__CYGWIN__)
15624 atexit(pipe_atexit);
15625#endif
15626
15627 Init_File();
15628
15629 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15630
15631 sym_mode = ID2SYM(rb_intern_const("mode"));
15632 sym_perm = ID2SYM(rb_intern_const("perm"));
15633 sym_flags = ID2SYM(rb_intern_const("flags"));
15634 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15635 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15636 sym_encoding = ID2SYM(rb_id_encoding());
15637 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15638 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15639 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15640 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15641 sym_normal = ID2SYM(rb_intern_const("normal"));
15642 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15643 sym_random = ID2SYM(rb_intern_const("random"));
15644 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15645 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15646 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15647 sym_SET = ID2SYM(rb_intern_const("SET"));
15648 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15649 sym_END = ID2SYM(rb_intern_const("END"));
15650#ifdef SEEK_DATA
15651 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15652#endif
15653#ifdef SEEK_HOLE
15654 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15655#endif
15656 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15657 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15658}
15659
15660#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:133
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:1130
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:923
rb_class_new
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:325
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:955
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:1062
rb_define_alias
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2289
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:2592
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:2579
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:868
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:2368
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:143
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:536
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:533
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:534
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:535
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:532
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:139
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:3193
rb_category_warn
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports always regardless of runtime -W flag.
Definition error.c:421
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition error.c:3150
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:453
rb_eNotImpError
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1101
rb_exc_raise
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:688
rb_syserr_fail
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3262
rb_bug
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition error.c:794
rb_sys_fail
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
Definition error.c:3274
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:14576
rb_eIOError
VALUE rb_eIOError
IOError exception.
Definition io.c:182
rb_eStandardError
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1088
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:3350
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:3268
ruby_verbose
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:459
rb_eTypeError
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1091
rb_eEOFError
VALUE rb_eEOFError
EOFError exception.
Definition io.c:181
rb_fatal
void rb_fatal(const char *fmt,...)
Raises the unsung "fatal" exception.
Definition error.c:3201
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:14570
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:1907
rb_io_wait_readwrite
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:57
rb_eRuntimeError
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1089
rb_warn
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
Definition error.c:411
rb_eArgError
VALUE rb_eArgError
ArgumentError exception.
Definition error.c:1092
rb_sys_fail_str
void rb_sys_fail_str(VALUE mesg)
Identical to rb_sys_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3280
rb_eSystemCallError
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1111
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:51
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:3033
rb_any_to_s
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:590
rb_obj_alloc
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:1940
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:1981
rb_cIO
VALUE rb_cIO
IO class.
Definition io.c:180
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:1969
rb_mEnumerable
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
rb_stdin
VALUE rb_stdin
STDIN constant.
Definition io.c:194
rb_stderr
VALUE rb_stderr
STDERR constant.
Definition io.c:194
rb_obj_class
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:191
rb_obj_dup
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:488
rb_inspect
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:601
rb_mWaitReadable
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:184
rb_mWaitWritable
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:185
rb_obj_freeze
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1183
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:3014
rb_cFile
VALUE rb_cFile
File class.
Definition file.c:176
rb_stdout
VALUE rb_stdout
STDOUT constant.
Definition io.c:194
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:3027
rb_enc_name
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
Definition encoding.h:433
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:699
rb_enc_asciicompat
static bool rb_enc_asciicompat(rb_encoding *enc)
Queries if the passed encoding is in some sense compatible with ASCII.
Definition encoding.h:784
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:587
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:448
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:3747
rb_enc_str_new
VALUE rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it additionally takes an encoding.
Definition string.c:981
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:719
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:2579
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:2076
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:1453
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:1749
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:1793
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:1910
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:2630
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:1975
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:2884
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:4245
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:4251
rb_econv_close
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1709
rb_econv_putback
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1760
rb_funcall
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1102
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:1069
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:8544
rb_io_gets
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4219
rb_cloexec_pipe
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:409
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:8670
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:2315
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:5084
rb_io_getbyte
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:4990
rb_io_puts
VALUE rb_io_puts(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8902
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:356
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:9203
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:230
rb_io_write
VALUE rb_io_write(VALUE io, VALUE str)
Writes the given string to the given IO.
Definition io.c:2267
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:310
rb_output_rs
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:199
rb_io_eof
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2666
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:280
rb_io_flush
VALUE rb_io_flush(VALUE io)
Flushes any buffered data within the passed IO to the underlying operating system.
Definition io.c:2371
rb_io_ascii8bit_binmode
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6281
rb_io_binmode
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6235
rb_io_ungetc
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5148
rb_pipe
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7286
rb_gets
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10265
rb_cloexec_fcntl_dupfd
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:443
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:7169
rb_cloexec_dup
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:349
rb_file_open
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7176
rb_io_close
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5671
rb_default_rs
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:200
rb_lastline_set
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:1680
rb_lastline_get
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1674
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:2891
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:1434
rb_last_status_set
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:686
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:3353
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:871
rb_str_new_frozen
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1382
rb_str_dup
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1834
rb_str_modify
void rb_str_modify(VALUE str)
Declares that the string is about to be modified.
Definition string.c:2437
rb_str_cat
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3177
rb_str_locktmp
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_str_setter
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
rb_str_set_len
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3020
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:3295
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:2640
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:2921
rb_str_unlocktmp
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3003
rb_str_resize
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3064
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:2445
rb_str_buf_new
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1532
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_obj_as_string
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1682
rb_thread_interrupted
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1457
rb_mutex_new
VALUE rb_mutex_new(void)
Creates a mutex.
Definition thread_sync.c:188
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:1570
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:5237
rb_thread_fd_close
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
Definition thread.c:2530
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:617
rb_thread_check_ints
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1440
rb_thread_current
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:2808
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:1564
rb_thread_schedule
void rb_thread_schedule(void)
Tries to switch to another thread.
Definition thread.c:1488
rb_thread_sleep
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1463
rb_time_interval
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2847
rb_attr_get
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
Definition variable.c:1226
rb_set_class_path
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:251
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:1606
rb_class_name
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:310
rb_respond_to
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:2805
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:664
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_intern
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
Definition symbol.c:796
RB_ID2SYM
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
rb_id2name
const char * rb_id2name(ID id)
Retrieves the name mapped to the given id.
Definition symbol.c:960
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:3452
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:604
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:3440
io.h
FMODE_READABLE
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:251
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:6367
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:797
rb_io_timeout
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:843
rb_io_taint_check
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:767
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:1051
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:6500
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:340
FMODE_READWRITE
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:257
GetOpenFile
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:362
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:997
FMODE_TTY
#define FMODE_TTY
The IO is a TTY.
Definition io.h:281
FMODE_CREATE
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:304
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:1006
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:6649
rb_io_t
struct rb_io_t rb_io_t
Ruby's IO, metadata and buffers.
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:6424
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:1558
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:6970
rb_io_descriptor
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2869
FMODE_WRITABLE
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:254
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:9249
FMODE_APPEND
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:296
MakeOpenFile
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:385
FMODE_DUPLEX
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:289
FMODE_BINMODE
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:268
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:1617
RB_IO_POINTER
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:356
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:1576
rb_eIOTimeoutError
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:183
FMODE_SYNC
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:275
rb_io_check_initialized
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:774
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:312
FMODE_TEXTMODE
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:332
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:803
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:869
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:1980
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:978
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:318
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:1042
rb_io_get_write_io
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:809
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:3379
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:6776
rb_io_wait_writable
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1515
rb_io_set_write_io
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:820
rb_io_check_writable
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1030
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:1630
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:782
rb_eof_error
void rb_eof_error(void)
Utility function to raise rb_eEOFError.
Definition io.c:761
rb_io_event_t
rb_io_event_t
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
rb_io_wait_readable
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1481
rb_io_synchronized
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7273
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:1420
ractor.h
rb_ractor_stderr
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
Definition ractor.c:2148
rb_ractor_stdin
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:2124
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:2184
rb_ractor_stdout
VALUE rb_ractor_stdout(void)
Queries the standard output of the current Ractor that is calling this function.
Definition ractor.c:2136
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:2172
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:2160
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:1774
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:1679
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_sprintf
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition sprintf.c:1219
rb_str_catf
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
Definition sprintf.c:1242
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:1391
rb_yield
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1357
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:68
RARRAY_LENINT
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:343
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition rarray.h:583
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:69
RFILE
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
SafeStringValue
#define SafeStringValue(v)
Definition rstring.h:104
StringValue
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:72
RSTRING_END
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:528
RSTRING_GETMEM
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:574
RSTRING_LEN
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition rstring.h:484
RSTRING_PTR
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition rstring.h:498
StringValueCStr
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:95
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:489
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:14536
ruby.h
rb_p
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:8978
FilePathValue
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:91
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_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_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_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_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_fiber_scheduler_io_write_memory
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *buffer, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:598
rb_fiber_scheduler_io_read_memory
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *buffer, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:585
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:4201
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:13819
argf
Definition io.c:218
binwrite_arg
Definition io.c:1698
bufread_arg
Definition io.c:3048
copy_stream_struct
Definition io.c:12352
fiber_scheduler_wait_for_arguments
Definition io.c:12406
finish_writeconv_arg
Definition io.c:5380
foreach_arg
Definition io.c:11805
getline_arg
Definition io.c:3995
io_encoding_set_args
Definition io.c:11619
io_internal_read_struct
Definition io.c:1102
io_internal_write_struct
Definition io.c:1113
iovec
Definition win32.h:216
pipe_list
Definition io.c:7182
rb_data_type_struct
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:190
rb_execarg
Definition process.h:30
rb_execution_context_struct
Definition vm_core.h:899
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:337
rb_io_buffer_t
IO buffers.
Definition io.h:104
rb_io_buffer_t::len
int len
Length of the buffer.
Definition io.h:104
rb_io_buffer_t::ptr
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:104
rb_io_buffer_t::off
int off
Offset inside of ptr.
Definition io.h:104
rb_io_buffer_t::capa
int capa
Designed capacity of the buffer.
Definition io.h:104
rb_io_enc_t
Decomposed encoding flags (e.g.
Definition io.h:116
rb_io_enc_t::ecflags
int ecflags
Flags.
Definition io.h:126
rb_io_enc_t::enc2
rb_encoding * enc2
External encoding.
Definition io.h:120
rb_io_enc_t::ecopts
VALUE ecopts
Flags as Ruby hash.
Definition io.h:134
rb_io_enc_t::enc
rb_encoding * enc
Internal encoding.
Definition io.h:118
rb_io_t
Ruby's IO, metadata and buffers.
Definition io.h:138
rb_io_t::fd
int fd
file descriptor.
Definition io.h:147
rb_io_t::lineno
int lineno
number of lines read
Definition io.h:156
rb_io_t::writeconv
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:192
rb_io_t::pid
rb_pid_t pid
child's pid (for pipes)
Definition io.h:153
rb_io_t::wbuf
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:165
rb_io_t::readconv
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:183
rb_io_t::writeconv_asciicompat
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:200
rb_io_t::stdio_file
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:144
rb_io_t::writeconv_initialized
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:203
rb_io_t::pathv
VALUE pathv
pathname for file
Definition io.h:159
rb_io_t::mode
int mode
mode flags: FMODE_XXXs
Definition io.h:150
rb_io_t::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:209
rb_io_t::encs
struct rb_io_enc_t encs
Decomposed encoding flags.
Definition io.h:180
rb_io_t::write_lock
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:224
rb_io_t::cbuf
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:189
rb_io_t::self
VALUE self
The IO's Ruby level counterpart.
Definition io.h:141
rb_io_t::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:215
rb_io_t::tied_io_for_writing
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:178
rb_io_t::finalize
void(* finalize)(struct rb_io_t *, int)
finalize proc
Definition io.h:162
rb_io_t::timeout
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:229
rb_io_t::rbuf
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:171
seek_arg
Definition io.c:12065
select_args
Definition io.c:10632
sysopen_struct
Definition io.c:6921
timeval
Definition missing.h:63
write_arg
Definition io.c:1705
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
RB_TYPE_P
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:375