[rubygems/rubygems] Use a constant empty tar header to avoid extra allocations
[ruby.git] / io.c
blobfeff4459437ccadb6917be4ffed2ba32d8759323
1 /**********************************************************************
3 io.c -
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
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
12 **********************************************************************/
14 #include "ruby/internal/config.h"
16 #include "ruby/fiber/scheduler.h"
17 #include "ruby/io/buffer.h"
19 #include <ctype.h>
20 #include <errno.h>
21 #include <stddef.h>
23 /* non-Linux poll may not work on all FDs */
24 #if defined(HAVE_POLL)
25 # if defined(__linux__)
26 # define USE_POLL 1
27 # endif
28 # if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29 # define USE_POLL 1
30 # endif
31 #endif
33 #ifndef USE_POLL
34 # define USE_POLL 0
35 #endif
37 #undef free
38 #define free(x) xfree(x)
40 #if defined(DOSISH) || defined(__CYGWIN__)
41 #include <io.h>
42 #endif
44 #include <sys/types.h>
45 #if defined HAVE_NET_SOCKET_H
46 # include <net/socket.h>
47 #elif defined HAVE_SYS_SOCKET_H
48 # include <sys/socket.h>
49 #endif
51 #if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52 # define NO_SAFE_RENAME
53 #endif
55 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56 # define USE_SETVBUF
57 #endif
59 #ifdef __QNXNTO__
60 #include <unix.h>
61 #endif
63 #include <sys/types.h>
64 #if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65 #include <sys/ioctl.h>
66 #endif
67 #if defined(HAVE_FCNTL_H) || defined(_WIN32)
68 #include <fcntl.h>
69 #elif defined(HAVE_SYS_FCNTL_H)
70 #include <sys/fcntl.h>
71 #endif
73 #ifdef HAVE_SYS_TIME_H
74 # include <sys/time.h>
75 #endif
77 #include <sys/stat.h>
79 #if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80 # include <sys/param.h>
81 #endif
83 #if !defined NOFILE
84 # define NOFILE 64
85 #endif
87 #ifdef HAVE_UNISTD_H
88 #include <unistd.h>
89 #endif
91 #ifdef HAVE_SYSCALL_H
92 #include <syscall.h>
93 #elif defined HAVE_SYS_SYSCALL_H
94 #include <sys/syscall.h>
95 #endif
97 #ifdef HAVE_SYS_UIO_H
98 #include <sys/uio.h>
99 #endif
101 #ifdef HAVE_SYS_WAIT_H
102 # include <sys/wait.h> /* for WNOHANG on BSD */
103 #endif
105 #ifdef HAVE_COPYFILE_H
106 # include <copyfile.h>
107 #endif
109 #include "ruby/internal/stdbool.h"
110 #include "ccan/list/list.h"
111 #include "dln.h"
112 #include "encindex.h"
113 #include "id.h"
114 #include "internal.h"
115 #include "internal/class.h"
116 #include "internal/encoding.h"
117 #include "internal/error.h"
118 #include "internal/inits.h"
119 #include "internal/io.h"
120 #include "internal/numeric.h"
121 #include "internal/object.h"
122 #include "internal/process.h"
123 #include "internal/thread.h"
124 #include "internal/transcode.h"
125 #include "internal/variable.h"
126 #include "ruby/io.h"
127 #include "ruby/io/buffer.h"
128 #include "ruby/missing.h"
129 #include "ruby/thread.h"
130 #include "ruby/util.h"
131 #include "ruby_atomic.h"
132 #include "ruby/ractor.h"
134 #if !USE_POLL
135 # include "vm_core.h"
136 #endif
138 #include "builtin.h"
140 #ifndef O_ACCMODE
141 #define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
142 #endif
144 #ifndef PIPE_BUF
145 # ifdef _POSIX_PIPE_BUF
146 # define PIPE_BUF _POSIX_PIPE_BUF
147 # else
148 # define PIPE_BUF 512 /* is this ok? */
149 # endif
150 #endif
152 #ifndef EWOULDBLOCK
153 # define EWOULDBLOCK EAGAIN
154 #endif
156 #if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
157 /* Mac OS X and OpenBSD have __syscall but don't define it in headers */
158 off_t __syscall(quad_t number, ...);
159 #endif
161 #define IO_RBUF_CAPA_MIN 8192
162 #define IO_CBUF_CAPA_MIN (128*1024)
163 #define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
164 #define IO_WBUF_CAPA_MIN 8192
166 #define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
168 /* define system APIs */
169 #ifdef _WIN32
170 #undef open
171 #define open rb_w32_uopen
172 #undef rename
173 #define rename(f, t) rb_w32_urename((f), (t))
174 #include "win32/file.h"
175 #endif
177 VALUE rb_cIO;
178 VALUE rb_eEOFError;
179 VALUE rb_eIOError;
180 VALUE rb_eIOTimeoutError;
181 VALUE rb_mWaitReadable;
182 VALUE rb_mWaitWritable;
184 static VALUE rb_eEAGAINWaitReadable;
185 static VALUE rb_eEAGAINWaitWritable;
186 static VALUE rb_eEWOULDBLOCKWaitReadable;
187 static VALUE rb_eEWOULDBLOCKWaitWritable;
188 static VALUE rb_eEINPROGRESSWaitWritable;
189 static VALUE rb_eEINPROGRESSWaitReadable;
191 VALUE rb_stdin, rb_stdout, rb_stderr;
192 static VALUE orig_stdout, orig_stderr;
194 VALUE rb_output_fs;
195 VALUE rb_rs;
196 VALUE rb_output_rs;
197 VALUE rb_default_rs;
199 static VALUE argf;
201 static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
202 static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
203 static VALUE sym_textmode, sym_binmode, sym_autoclose;
204 static VALUE sym_SET, sym_CUR, sym_END;
205 static VALUE sym_wait_readable, sym_wait_writable;
206 #ifdef SEEK_DATA
207 static VALUE sym_DATA;
208 #endif
209 #ifdef SEEK_HOLE
210 static VALUE sym_HOLE;
211 #endif
213 static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
215 struct argf {
216 VALUE filename, current_file;
217 long last_lineno; /* $. */
218 long lineno;
219 VALUE argv;
220 VALUE inplace;
221 struct rb_io_encoding encs;
222 int8_t init_p, next_p, binmode;
225 static rb_atomic_t max_file_descriptor = NOFILE;
226 void
227 rb_update_max_fd(int fd)
229 rb_atomic_t afd = (rb_atomic_t)fd;
230 rb_atomic_t max_fd = max_file_descriptor;
231 int err;
233 if (fd < 0 || afd <= max_fd)
234 return;
236 #if defined(HAVE_FCNTL) && defined(F_GETFL)
237 err = fcntl(fd, F_GETFL) == -1;
238 #else
240 struct stat buf;
241 err = fstat(fd, &buf) != 0;
243 #endif
244 if (err && errno == EBADF) {
245 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
248 while (max_fd < afd) {
249 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
253 void
254 rb_maygvl_fd_fix_cloexec(int fd)
256 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
257 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
258 int flags, flags2, ret;
259 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
260 if (flags == -1) {
261 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
263 if (fd <= 2)
264 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
265 else
266 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
267 if (flags != flags2) {
268 ret = fcntl(fd, F_SETFD, flags2);
269 if (ret != 0) {
270 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
273 #endif
276 void
277 rb_fd_fix_cloexec(int fd)
279 rb_maygvl_fd_fix_cloexec(fd);
280 rb_update_max_fd(fd);
283 /* this is only called once */
284 static int
285 rb_fix_detect_o_cloexec(int fd)
287 #if defined(O_CLOEXEC) && defined(F_GETFD)
288 int flags = fcntl(fd, F_GETFD);
290 if (flags == -1)
291 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
293 if (flags & FD_CLOEXEC)
294 return 1;
295 #endif /* fall through if O_CLOEXEC does not work: */
296 rb_maygvl_fd_fix_cloexec(fd);
297 return 0;
300 static inline bool
301 io_again_p(int e)
303 return (e == EWOULDBLOCK) || (e == EAGAIN);
307 rb_cloexec_open(const char *pathname, int flags, mode_t mode)
309 int ret;
310 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
312 static const int retry_interval = 0;
313 static const int retry_max_count = 10000;
315 int retry_count = 0;
317 #ifdef O_CLOEXEC
318 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
319 flags |= O_CLOEXEC;
320 #elif defined O_NOINHERIT
321 flags |= O_NOINHERIT;
322 #endif
324 while ((ret = open(pathname, flags, mode)) == -1) {
325 int e = errno;
326 if (!io_again_p(e)) break;
327 if (retry_count++ >= retry_max_count) break;
329 sleep(retry_interval);
332 if (ret < 0) return ret;
333 if (ret <= 2 || o_cloexec_state == 0) {
334 rb_maygvl_fd_fix_cloexec(ret);
336 else if (o_cloexec_state > 0) {
337 return ret;
339 else {
340 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
342 return ret;
346 rb_cloexec_dup(int oldfd)
348 /* Don't allocate standard file descriptors: 0, 1, 2 */
349 return rb_cloexec_fcntl_dupfd(oldfd, 3);
353 rb_cloexec_dup2(int oldfd, int newfd)
355 int ret;
357 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
358 * rb_cloexec_dup2 succeeds as dup2. */
359 if (oldfd == newfd) {
360 ret = newfd;
362 else {
363 #if defined(HAVE_DUP3) && defined(O_CLOEXEC)
364 static int try_dup3 = 1;
365 if (2 < newfd && try_dup3) {
366 ret = dup3(oldfd, newfd, O_CLOEXEC);
367 if (ret != -1)
368 return ret;
369 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
370 if (errno == ENOSYS) {
371 try_dup3 = 0;
372 ret = dup2(oldfd, newfd);
375 else {
376 ret = dup2(oldfd, newfd);
378 #else
379 ret = dup2(oldfd, newfd);
380 #endif
381 if (ret < 0) return ret;
383 rb_maygvl_fd_fix_cloexec(ret);
384 return ret;
387 static int
388 rb_fd_set_nonblock(int fd)
390 #ifdef _WIN32
391 return rb_w32_set_nonblock(fd);
392 #elif defined(F_GETFL)
393 int oflags = fcntl(fd, F_GETFL);
395 if (oflags == -1)
396 return -1;
397 if (oflags & O_NONBLOCK)
398 return 0;
399 oflags |= O_NONBLOCK;
400 return fcntl(fd, F_SETFL, oflags);
401 #endif
402 return 0;
406 rb_cloexec_pipe(int descriptors[2])
408 #ifdef HAVE_PIPE2
409 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
410 #else
411 int result = pipe(descriptors);
412 #endif
414 if (result < 0)
415 return result;
417 #ifdef __CYGWIN__
418 if (result == 0 && descriptors[1] == -1) {
419 close(descriptors[0]);
420 descriptors[0] = -1;
421 errno = ENFILE;
422 return -1;
424 #endif
426 #ifndef HAVE_PIPE2
427 rb_maygvl_fd_fix_cloexec(descriptors[0]);
428 rb_maygvl_fd_fix_cloexec(descriptors[1]);
430 #ifndef _WIN32
431 rb_fd_set_nonblock(descriptors[0]);
432 rb_fd_set_nonblock(descriptors[1]);
433 #endif
434 #endif
436 return result;
440 rb_cloexec_fcntl_dupfd(int fd, int minfd)
442 int ret;
444 #if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
445 static int try_dupfd_cloexec = 1;
446 if (try_dupfd_cloexec) {
447 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
448 if (ret != -1) {
449 if (ret <= 2)
450 rb_maygvl_fd_fix_cloexec(ret);
451 return ret;
453 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
454 if (errno == EINVAL) {
455 ret = fcntl(fd, F_DUPFD, minfd);
456 if (ret != -1) {
457 try_dupfd_cloexec = 0;
461 else {
462 ret = fcntl(fd, F_DUPFD, minfd);
464 #elif defined(HAVE_FCNTL) && defined(F_DUPFD)
465 ret = fcntl(fd, F_DUPFD, minfd);
466 #else
467 ret = dup(fd);
468 if (ret >= 0 && ret < minfd) {
469 const int prev_fd = ret;
470 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
471 close(prev_fd);
473 return ret;
474 #endif
475 if (ret < 0) return ret;
476 rb_maygvl_fd_fix_cloexec(ret);
477 return ret;
480 #define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
481 #define ARGF argf_of(argf)
483 #define GetWriteIO(io) rb_io_get_write_io(io)
485 #define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
486 #define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
487 #define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
488 #define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
490 #define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
491 #define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
492 #define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
494 #if defined(_WIN32)
495 #define WAIT_FD_IN_WIN32(fptr) \
496 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
497 #else
498 #define WAIT_FD_IN_WIN32(fptr)
499 #endif
501 #define READ_CHECK(fptr) do {\
502 if (!READ_DATA_PENDING(fptr)) {\
503 WAIT_FD_IN_WIN32(fptr);\
504 rb_io_check_closed(fptr);\
506 } while(0)
508 #ifndef S_ISSOCK
509 # ifdef _S_ISSOCK
510 # define S_ISSOCK(m) _S_ISSOCK(m)
511 # else
512 # ifdef _S_IFSOCK
513 # define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
514 # else
515 # ifdef S_IFSOCK
516 # define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
517 # endif
518 # endif
519 # endif
520 #endif
522 static int io_fflush(rb_io_t *);
523 static rb_io_t *flush_before_seek(rb_io_t *fptr);
525 #define FMODE_SIGNAL_ON_EPIPE (1<<17)
527 #define fptr_signal_on_epipe(fptr) \
528 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
530 #define fptr_set_signal_on_epipe(fptr, flag) \
531 ((flag) ? \
532 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
533 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
535 extern ID ruby_static_id_signo;
537 NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
538 static void
539 rb_sys_fail_on_write(rb_io_t *fptr)
541 int e = errno;
542 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
543 #if defined EPIPE
544 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
545 const VALUE sig =
546 # if defined SIGPIPE
547 INT2FIX(SIGPIPE) - INT2FIX(0) +
548 # endif
549 INT2FIX(0);
550 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
552 #endif
553 rb_exc_raise(errinfo);
556 #define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
557 #define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
558 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
559 # define RUBY_CRLF_ENVIRONMENT 1
560 #else
561 # define RUBY_CRLF_ENVIRONMENT 0
562 #endif
564 #if RUBY_CRLF_ENVIRONMENT
565 /* Windows */
566 # define DEFAULT_TEXTMODE FMODE_TEXTMODE
567 # define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
569 * CRLF newline is set as default newline decorator.
570 * If only CRLF newline conversion is needed, we use binary IO process
571 * with OS's text mode for IO performance improvement.
572 * If encoding conversion is needed or a user sets text mode, we use encoding
573 * conversion IO process and universal newline decorator by default.
575 #define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
576 #define WRITECONV_MASK ( \
577 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
578 ECONV_STATEFUL_DECORATOR_MASK|\
580 #define NEED_WRITECONV(fptr) ( \
581 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
582 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
584 #define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
586 #define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
587 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
588 if (((fptr)->mode & FMODE_READABLE) &&\
589 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
590 setmode((fptr)->fd, O_BINARY);\
592 else {\
593 setmode((fptr)->fd, O_TEXT);\
596 } while(0)
598 #define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
599 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
600 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
602 } while(0)
605 * IO unread with taking care of removed '\r' in text mode.
607 static void
608 io_unread(rb_io_t *fptr)
610 rb_off_t r, pos;
611 ssize_t read_size;
612 long i;
613 long newlines = 0;
614 long extra_max;
615 char *p;
616 char *buf;
618 rb_io_check_closed(fptr);
619 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
620 return;
623 errno = 0;
624 if (!rb_w32_fd_is_text(fptr->fd)) {
625 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
626 if (r < 0 && errno) {
627 if (errno == ESPIPE)
628 fptr->mode |= FMODE_DUPLEX;
629 return;
632 fptr->rbuf.off = 0;
633 fptr->rbuf.len = 0;
634 return;
637 pos = lseek(fptr->fd, 0, SEEK_CUR);
638 if (pos < 0 && errno) {
639 if (errno == ESPIPE)
640 fptr->mode |= FMODE_DUPLEX;
641 return;
644 /* add extra offset for removed '\r' in rbuf */
645 extra_max = (long)(pos - fptr->rbuf.len);
646 p = fptr->rbuf.ptr + fptr->rbuf.off;
648 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
649 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
650 newlines++;
653 for (i = 0; i < fptr->rbuf.len; i++) {
654 if (*p == '\n') newlines++;
655 if (extra_max == newlines) break;
656 p++;
659 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
660 while (newlines >= 0) {
661 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
662 if (newlines == 0) break;
663 if (r < 0) {
664 newlines--;
665 continue;
667 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
668 if (read_size < 0) {
669 int e = errno;
670 free(buf);
671 rb_syserr_fail_path(e, fptr->pathv);
673 if (read_size == fptr->rbuf.len) {
674 lseek(fptr->fd, r, SEEK_SET);
675 break;
677 else {
678 newlines--;
681 free(buf);
682 fptr->rbuf.off = 0;
683 fptr->rbuf.len = 0;
684 return;
688 * We use io_seek to back cursor position when changing mode from text to binary,
689 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
690 * conversion for working properly with mode change.
692 * Return previous translation mode.
694 static inline int
695 set_binary_mode_with_seek_cur(rb_io_t *fptr)
697 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
699 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
700 return setmode(fptr->fd, O_BINARY);
702 flush_before_seek(fptr);
703 return setmode(fptr->fd, O_BINARY);
705 #define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
707 #else
708 /* Unix */
709 # define DEFAULT_TEXTMODE 0
710 #define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
711 #define NEED_WRITECONV(fptr) ( \
712 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
713 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
714 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
716 #define SET_BINARY_MODE(fptr) (void)(fptr)
717 #define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
718 #define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
719 #define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
720 #endif
722 #if !defined HAVE_SHUTDOWN && !defined shutdown
723 #define shutdown(a,b) 0
724 #endif
726 #if defined(_WIN32)
727 #define is_socket(fd, path) rb_w32_is_socket(fd)
728 #elif !defined(S_ISSOCK)
729 #define is_socket(fd, path) 0
730 #else
731 static int
732 is_socket(int fd, VALUE path)
734 struct stat sbuf;
735 if (fstat(fd, &sbuf) < 0)
736 rb_sys_fail_path(path);
737 return S_ISSOCK(sbuf.st_mode);
739 #endif
741 static const char closed_stream[] = "closed stream";
743 static void
744 io_fd_check_closed(int fd)
746 if (fd < 0) {
747 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
748 rb_raise(rb_eIOError, closed_stream);
752 void
753 rb_eof_error(void)
755 rb_raise(rb_eEOFError, "end of file reached");
758 VALUE
759 rb_io_taint_check(VALUE io)
761 rb_check_frozen(io);
762 return io;
765 void
766 rb_io_check_initialized(rb_io_t *fptr)
768 if (!fptr) {
769 rb_raise(rb_eIOError, "uninitialized stream");
773 void
774 rb_io_check_closed(rb_io_t *fptr)
776 rb_io_check_initialized(fptr);
777 io_fd_check_closed(fptr->fd);
780 static rb_io_t *
781 rb_io_get_fptr(VALUE io)
783 rb_io_t *fptr = RFILE(io)->fptr;
784 rb_io_check_initialized(fptr);
785 return fptr;
788 VALUE
789 rb_io_get_io(VALUE io)
791 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
794 VALUE
795 rb_io_check_io(VALUE io)
797 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
800 VALUE
801 rb_io_get_write_io(VALUE io)
803 VALUE write_io;
804 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
805 if (write_io) {
806 return write_io;
808 return io;
811 VALUE
812 rb_io_set_write_io(VALUE io, VALUE w)
814 VALUE write_io;
815 rb_io_t *fptr = rb_io_get_fptr(io);
816 if (!RTEST(w)) {
817 w = 0;
819 else {
820 GetWriteIO(w);
822 write_io = fptr->tied_io_for_writing;
823 fptr->tied_io_for_writing = w;
824 return write_io ? write_io : Qnil;
828 * call-seq:
829 * timeout -> duration or nil
831 * Get the internal timeout duration or nil if it was not set.
834 VALUE
835 rb_io_timeout(VALUE self)
837 rb_io_t *fptr = rb_io_get_fptr(self);
839 return fptr->timeout;
843 * call-seq:
844 * timeout = duration -> duration
845 * timeout = nil -> nil
847 * Sets the internal timeout to the specified duration or nil. The timeout
848 * applies to all blocking operations where possible.
850 * When the operation performs longer than the timeout set, IO::TimeoutError
851 * is raised.
853 * This affects the following methods (but is not limited to): #gets, #puts,
854 * #read, #write, #wait_readable and #wait_writable. This also affects
855 * blocking socket operations like Socket#accept and Socket#connect.
857 * Some operations like File#open and IO#close are not affected by the
858 * timeout. A timeout during a write operation may leave the IO in an
859 * inconsistent state, e.g. data was partially written. Generally speaking, a
860 * timeout is a last ditch effort to prevent an application from hanging on
861 * slow I/O operations, such as those that occur during a slowloris attack.
863 VALUE
864 rb_io_set_timeout(VALUE self, VALUE timeout)
866 // Validate it:
867 if (RTEST(timeout)) {
868 rb_time_interval(timeout);
871 rb_io_t *fptr = rb_io_get_fptr(self);
873 fptr->timeout = timeout;
875 return self;
879 * call-seq:
880 * IO.try_convert(object) -> new_io or nil
882 * Attempts to convert +object+ into an \IO object via method +to_io+;
883 * returns the new \IO object if successful, or +nil+ otherwise:
885 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
886 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
887 * IO.try_convert('STDOUT') # => nil
890 static VALUE
891 rb_io_s_try_convert(VALUE dummy, VALUE io)
893 return rb_io_check_io(io);
896 #if !RUBY_CRLF_ENVIRONMENT
897 static void
898 io_unread(rb_io_t *fptr)
900 rb_off_t r;
901 rb_io_check_closed(fptr);
902 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
903 return;
904 /* xxx: target position may be negative if buffer is filled by ungetc */
905 errno = 0;
906 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
907 if (r < 0 && errno) {
908 if (errno == ESPIPE)
909 fptr->mode |= FMODE_DUPLEX;
910 return;
912 fptr->rbuf.off = 0;
913 fptr->rbuf.len = 0;
914 return;
916 #endif
918 static rb_encoding *io_input_encoding(rb_io_t *fptr);
920 static void
921 io_ungetbyte(VALUE str, rb_io_t *fptr)
923 long len = RSTRING_LEN(str);
925 if (fptr->rbuf.ptr == NULL) {
926 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
927 fptr->rbuf.off = 0;
928 fptr->rbuf.len = 0;
929 #if SIZEOF_LONG > SIZEOF_INT
930 if (len > INT_MAX)
931 rb_raise(rb_eIOError, "ungetbyte failed");
932 #endif
933 if (len > min_capa)
934 fptr->rbuf.capa = (int)len;
935 else
936 fptr->rbuf.capa = min_capa;
937 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
939 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
940 rb_raise(rb_eIOError, "ungetbyte failed");
942 if (fptr->rbuf.off < len) {
943 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
944 fptr->rbuf.ptr+fptr->rbuf.off,
945 char, fptr->rbuf.len);
946 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
948 fptr->rbuf.off-=(int)len;
949 fptr->rbuf.len+=(int)len;
950 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
953 static rb_io_t *
954 flush_before_seek(rb_io_t *fptr)
956 if (io_fflush(fptr) < 0)
957 rb_sys_fail_on_write(fptr);
958 io_unread(fptr);
959 errno = 0;
960 return fptr;
963 #define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
964 #define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
966 #ifndef SEEK_CUR
967 # define SEEK_SET 0
968 # define SEEK_CUR 1
969 # define SEEK_END 2
970 #endif
972 void
973 rb_io_check_char_readable(rb_io_t *fptr)
975 rb_io_check_closed(fptr);
976 if (!(fptr->mode & FMODE_READABLE)) {
977 rb_raise(rb_eIOError, "not opened for reading");
979 if (fptr->wbuf.len) {
980 if (io_fflush(fptr) < 0)
981 rb_sys_fail_on_write(fptr);
983 if (fptr->tied_io_for_writing) {
984 rb_io_t *wfptr;
985 GetOpenFile(fptr->tied_io_for_writing, wfptr);
986 if (io_fflush(wfptr) < 0)
987 rb_sys_fail_on_write(wfptr);
991 void
992 rb_io_check_byte_readable(rb_io_t *fptr)
994 rb_io_check_char_readable(fptr);
995 if (READ_CHAR_PENDING(fptr)) {
996 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1000 void
1001 rb_io_check_readable(rb_io_t *fptr)
1003 rb_io_check_byte_readable(fptr);
1006 static rb_encoding*
1007 io_read_encoding(rb_io_t *fptr)
1009 if (fptr->encs.enc) {
1010 return fptr->encs.enc;
1012 return rb_default_external_encoding();
1015 static rb_encoding*
1016 io_input_encoding(rb_io_t *fptr)
1018 if (fptr->encs.enc2) {
1019 return fptr->encs.enc2;
1021 return io_read_encoding(fptr);
1024 void
1025 rb_io_check_writable(rb_io_t *fptr)
1027 rb_io_check_closed(fptr);
1028 if (!(fptr->mode & FMODE_WRITABLE)) {
1029 rb_raise(rb_eIOError, "not opened for writing");
1031 if (fptr->rbuf.len) {
1032 io_unread(fptr);
1037 rb_io_read_pending(rb_io_t *fptr)
1039 /* This function is used for bytes and chars. Confusing. */
1040 if (READ_CHAR_PENDING(fptr))
1041 return 1; /* should raise? */
1042 return READ_DATA_PENDING(fptr);
1045 void
1046 rb_io_read_check(rb_io_t *fptr)
1048 if (!READ_DATA_PENDING(fptr)) {
1049 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1051 return;
1055 rb_gc_for_fd(int err)
1057 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1058 rb_gc();
1059 return 1;
1061 return 0;
1064 /* try `expr` upto twice while it returns false and `errno`
1065 * is to GC. Each `errno`s are available as `first_errno` and
1066 * `retried_errno` respectively */
1067 #define TRY_WITH_GC(expr) \
1068 for (int first_errno, retried_errno = 0, retried = 0; \
1069 (!retried && \
1070 !(expr) && \
1071 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1072 (retried_errno = errno, 1)); \
1073 (void)retried_errno, retried = 1)
1075 static int
1076 ruby_dup(int orig)
1078 int fd = -1;
1080 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1081 rb_syserr_fail(first_errno, 0);
1083 rb_update_max_fd(fd);
1084 return fd;
1087 static VALUE
1088 io_alloc(VALUE klass)
1090 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1092 io->fptr = 0;
1094 return (VALUE)io;
1097 #ifndef S_ISREG
1098 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1099 #endif
1101 struct io_internal_read_struct {
1102 VALUE th;
1103 rb_io_t *fptr;
1104 int nonblock;
1105 int fd;
1107 void *buf;
1108 size_t capa;
1109 struct timeval *timeout;
1112 struct io_internal_write_struct {
1113 VALUE th;
1114 rb_io_t *fptr;
1115 int nonblock;
1116 int fd;
1118 const void *buf;
1119 size_t capa;
1120 struct timeval *timeout;
1123 #ifdef HAVE_WRITEV
1124 struct io_internal_writev_struct {
1125 VALUE th;
1126 rb_io_t *fptr;
1127 int nonblock;
1128 int fd;
1130 int iovcnt;
1131 const struct iovec *iov;
1132 struct timeval *timeout;
1134 #endif
1136 static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1139 * Wait for the given events on the given file descriptor.
1140 * Returns -1 if an error or timeout occurred. +errno+ will be set.
1141 * Returns the event mask if an event occurred.
1143 static inline int
1144 io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1146 if (!timeout && rb_thread_mn_schedulable(thread)) {
1147 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1148 return -1;
1151 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1153 if (ready > 0) {
1154 return ready;
1156 else if (ready == 0) {
1157 errno = ETIMEDOUT;
1158 return -1;
1161 errno = error;
1162 return -1;
1165 static VALUE
1166 internal_read_func(void *ptr)
1168 struct io_internal_read_struct *iis = ptr;
1169 ssize_t result;
1171 if (iis->timeout && !iis->nonblock) {
1172 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1173 return -1;
1177 retry:
1178 result = read(iis->fd, iis->buf, iis->capa);
1180 if (result < 0 && !iis->nonblock) {
1181 if (io_again_p(errno)) {
1182 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1183 return -1;
1185 else {
1186 goto retry;
1191 return result;
1194 #if defined __APPLE__
1195 # define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1196 #else
1197 # define do_write_retry(code) result = code
1198 #endif
1200 static VALUE
1201 internal_write_func(void *ptr)
1203 struct io_internal_write_struct *iis = ptr;
1204 ssize_t result;
1206 if (iis->timeout && !iis->nonblock) {
1207 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1208 return -1;
1212 retry:
1213 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1215 if (result < 0 && !iis->nonblock) {
1216 int e = errno;
1217 if (io_again_p(e)) {
1218 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1219 return -1;
1221 else {
1222 goto retry;
1227 return result;
1230 #ifdef HAVE_WRITEV
1231 static VALUE
1232 internal_writev_func(void *ptr)
1234 struct io_internal_writev_struct *iis = ptr;
1235 ssize_t result;
1237 if (iis->timeout && !iis->nonblock) {
1238 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1239 return -1;
1243 retry:
1244 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1246 if (result < 0 && !iis->nonblock) {
1247 if (io_again_p(errno)) {
1248 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1249 return -1;
1251 else {
1252 goto retry;
1257 return result;
1259 #endif
1261 static ssize_t
1262 rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1264 VALUE scheduler = rb_fiber_scheduler_current();
1265 if (scheduler != Qnil) {
1266 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1268 if (!UNDEF_P(result)) {
1269 return rb_fiber_scheduler_io_result_apply(result);
1273 struct io_internal_read_struct iis = {
1274 .th = rb_thread_current(),
1275 .fptr = fptr,
1276 .nonblock = 0,
1277 .fd = fptr->fd,
1279 .buf = buf,
1280 .capa = count,
1281 .timeout = NULL,
1284 struct timeval timeout_storage;
1286 if (fptr->timeout != Qnil) {
1287 timeout_storage = rb_time_interval(fptr->timeout);
1288 iis.timeout = &timeout_storage;
1291 return (ssize_t)rb_thread_io_blocking_call(internal_read_func, &iis, fptr->fd, RB_WAITFD_IN);
1294 static ssize_t
1295 rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1297 VALUE scheduler = rb_fiber_scheduler_current();
1298 if (scheduler != Qnil) {
1299 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1301 if (!UNDEF_P(result)) {
1302 return rb_fiber_scheduler_io_result_apply(result);
1306 struct io_internal_write_struct iis = {
1307 .th = rb_thread_current(),
1308 .fptr = fptr,
1309 .nonblock = 0,
1310 .fd = fptr->fd,
1312 .buf = buf,
1313 .capa = count,
1314 .timeout = NULL
1317 struct timeval timeout_storage;
1319 if (fptr->timeout != Qnil) {
1320 timeout_storage = rb_time_interval(fptr->timeout);
1321 iis.timeout = &timeout_storage;
1324 return (ssize_t)rb_thread_io_blocking_call(internal_write_func, &iis, fptr->fd, RB_WAITFD_OUT);
1327 #ifdef HAVE_WRITEV
1328 static ssize_t
1329 rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1331 if (!iovcnt) return 0;
1333 VALUE scheduler = rb_fiber_scheduler_current();
1334 if (scheduler != Qnil) {
1335 // This path assumes at least one `iov`:
1336 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1338 if (!UNDEF_P(result)) {
1339 return rb_fiber_scheduler_io_result_apply(result);
1343 struct io_internal_writev_struct iis = {
1344 .th = rb_thread_current(),
1345 .fptr = fptr,
1346 .nonblock = 0,
1347 .fd = fptr->fd,
1349 .iov = iov,
1350 .iovcnt = iovcnt,
1351 .timeout = NULL
1354 struct timeval timeout_storage;
1356 if (fptr->timeout != Qnil) {
1357 timeout_storage = rb_time_interval(fptr->timeout);
1358 iis.timeout = &timeout_storage;
1361 return (ssize_t)rb_thread_io_blocking_call(internal_writev_func, &iis, fptr->fd, RB_WAITFD_OUT);
1363 #endif
1365 static VALUE
1366 io_flush_buffer_sync(void *arg)
1368 rb_io_t *fptr = arg;
1369 long l = fptr->wbuf.len;
1370 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1372 if (fptr->wbuf.len <= r) {
1373 fptr->wbuf.off = 0;
1374 fptr->wbuf.len = 0;
1375 return 0;
1378 if (0 <= r) {
1379 fptr->wbuf.off += (int)r;
1380 fptr->wbuf.len -= (int)r;
1381 errno = EAGAIN;
1384 return (VALUE)-1;
1387 static VALUE
1388 io_flush_buffer_async(VALUE arg)
1390 rb_io_t *fptr = (rb_io_t *)arg;
1391 return rb_thread_io_blocking_call(io_flush_buffer_sync, fptr, fptr->fd, RB_WAITFD_OUT);
1394 static inline int
1395 io_flush_buffer(rb_io_t *fptr)
1397 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1398 return (int)io_flush_buffer_async((VALUE)fptr);
1400 else {
1401 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1405 static int
1406 io_fflush(rb_io_t *fptr)
1408 rb_io_check_closed(fptr);
1410 if (fptr->wbuf.len == 0)
1411 return 0;
1413 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1414 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1415 return -1;
1417 rb_io_check_closed(fptr);
1420 return 0;
1423 VALUE
1424 rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1426 VALUE scheduler = rb_fiber_scheduler_current();
1428 if (scheduler != Qnil) {
1429 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1432 rb_io_t * fptr = NULL;
1433 RB_IO_POINTER(io, fptr);
1435 struct timeval tv_storage;
1436 struct timeval *tv = NULL;
1438 if (NIL_OR_UNDEF_P(timeout)) {
1439 timeout = fptr->timeout;
1442 if (timeout != Qnil) {
1443 tv_storage = rb_time_interval(timeout);
1444 tv = &tv_storage;
1447 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1449 if (ready < 0) {
1450 rb_sys_fail(0);
1453 // Not sure if this is necessary:
1454 rb_io_check_closed(fptr);
1456 if (ready) {
1457 return RB_INT2NUM(ready);
1459 else {
1460 return Qfalse;
1464 static VALUE
1465 io_from_fd(int fd)
1467 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1470 static int
1471 io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1473 VALUE scheduler = rb_fiber_scheduler_current();
1475 if (scheduler != Qnil) {
1476 return RTEST(
1477 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1481 return rb_thread_wait_for_single_fd(fd, events, timeout);
1485 rb_io_wait_readable(int f)
1487 io_fd_check_closed(f);
1489 VALUE scheduler = rb_fiber_scheduler_current();
1491 switch (errno) {
1492 case EINTR:
1493 #if defined(ERESTART)
1494 case ERESTART:
1495 #endif
1496 rb_thread_check_ints();
1497 return TRUE;
1499 case EAGAIN:
1500 #if EWOULDBLOCK != EAGAIN
1501 case EWOULDBLOCK:
1502 #endif
1503 if (scheduler != Qnil) {
1504 return RTEST(
1505 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1508 else {
1509 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1511 return TRUE;
1513 default:
1514 return FALSE;
1519 rb_io_wait_writable(int f)
1521 io_fd_check_closed(f);
1523 VALUE scheduler = rb_fiber_scheduler_current();
1525 switch (errno) {
1526 case EINTR:
1527 #if defined(ERESTART)
1528 case ERESTART:
1529 #endif
1531 * In old Linux, several special files under /proc and /sys don't handle
1532 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1533 * Otherwise, we face nasty hang up. Sigh.
1534 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1535 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1536 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1537 * Then rb_thread_check_ints() is enough.
1539 rb_thread_check_ints();
1540 return TRUE;
1542 case EAGAIN:
1543 #if EWOULDBLOCK != EAGAIN
1544 case EWOULDBLOCK:
1545 #endif
1546 if (scheduler != Qnil) {
1547 return RTEST(
1548 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1551 else {
1552 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1554 return TRUE;
1556 default:
1557 return FALSE;
1562 rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1564 return io_wait_for_single_fd(fd, events, timeout);
1568 rb_thread_wait_fd(int fd)
1570 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1574 rb_thread_fd_writable(int fd)
1576 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1579 VALUE
1580 rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1582 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1583 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1584 // instead relies on `read(-1) -> -1` which causes this code path. We then
1585 // check here whether the IO was in fact closed. Probably it's better to
1586 // check that `fptr->fd != -1` before using it in syscall.
1587 rb_io_check_closed(RFILE(io)->fptr);
1589 switch (error) {
1590 // In old Linux, several special files under /proc and /sys don't handle
1591 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1592 // Otherwise, we face nasty hang up. Sigh.
1593 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1594 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1595 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1596 // Then rb_thread_check_ints() is enough.
1597 case EINTR:
1598 #if defined(ERESTART)
1599 case ERESTART:
1600 #endif
1601 // We might have pending interrupts since the previous syscall was interrupted:
1602 rb_thread_check_ints();
1604 // The operation was interrupted, so retry it immediately:
1605 return events;
1607 case EAGAIN:
1608 #if EWOULDBLOCK != EAGAIN
1609 case EWOULDBLOCK:
1610 #endif
1611 // The operation would block, so wait for the specified events:
1612 return rb_io_wait(io, events, timeout);
1614 default:
1615 // Non-specific error, no event is ready:
1616 return Qfalse;
1621 rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
1623 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1625 if (RTEST(result)) {
1626 return RB_NUM2INT(result);
1628 else {
1629 return 0;
1634 rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
1636 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1638 if (RTEST(result)) {
1639 return RB_NUM2INT(result);
1641 else {
1642 return 0;
1646 static void
1647 make_writeconv(rb_io_t *fptr)
1649 if (!fptr->writeconv_initialized) {
1650 const char *senc, *denc;
1651 rb_encoding *enc;
1652 int ecflags;
1653 VALUE ecopts;
1655 fptr->writeconv_initialized = 1;
1657 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1658 ecopts = fptr->encs.ecopts;
1660 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1661 /* no encoding conversion */
1662 fptr->writeconv_pre_ecflags = 0;
1663 fptr->writeconv_pre_ecopts = Qnil;
1664 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1665 if (!fptr->writeconv)
1666 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1667 fptr->writeconv_asciicompat = Qnil;
1669 else {
1670 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1671 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1672 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1673 /* single conversion */
1674 fptr->writeconv_pre_ecflags = ecflags;
1675 fptr->writeconv_pre_ecopts = ecopts;
1676 fptr->writeconv = NULL;
1677 fptr->writeconv_asciicompat = Qnil;
1679 else {
1680 /* double conversion */
1681 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1682 fptr->writeconv_pre_ecopts = ecopts;
1683 if (senc) {
1684 denc = rb_enc_name(enc);
1685 fptr->writeconv_asciicompat = rb_str_new2(senc);
1687 else {
1688 senc = denc = "";
1689 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1691 ecflags = fptr->encs.ecflags & (ECONV_ERROR_HANDLER_MASK|ECONV_STATEFUL_DECORATOR_MASK);
1692 ecopts = fptr->encs.ecopts;
1693 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1694 if (!fptr->writeconv)
1695 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1701 /* writing functions */
1702 struct binwrite_arg {
1703 rb_io_t *fptr;
1704 const char *ptr;
1705 long length;
1708 struct write_arg {
1709 VALUE io;
1710 VALUE str;
1711 int nosync;
1714 #ifdef HAVE_WRITEV
1715 static ssize_t
1716 io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1718 if (fptr->wbuf.len) {
1719 struct iovec iov[2];
1721 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1722 iov[0].iov_len = fptr->wbuf.len;
1723 iov[1].iov_base = (void*)ptr;
1724 iov[1].iov_len = length;
1726 ssize_t result = rb_writev_internal(fptr, iov, 2);
1728 if (result < 0)
1729 return result;
1731 if (result >= fptr->wbuf.len) {
1732 // We wrote more than the internal buffer:
1733 result -= fptr->wbuf.len;
1734 fptr->wbuf.off = 0;
1735 fptr->wbuf.len = 0;
1737 else {
1738 // We only wrote less data than the internal buffer:
1739 fptr->wbuf.off += (int)result;
1740 fptr->wbuf.len -= (int)result;
1742 result = 0;
1745 return result;
1747 else {
1748 return rb_io_write_memory(fptr, ptr, length);
1751 #else
1752 static ssize_t
1753 io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1755 long remaining = length;
1757 if (fptr->wbuf.len) {
1758 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1759 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1760 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1761 fptr->wbuf.off = 0;
1764 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1765 fptr->wbuf.len += (int)length;
1767 // We copied the entire incoming data to the internal buffer:
1768 remaining = 0;
1771 // Flush the internal buffer:
1772 if (io_fflush(fptr) < 0) {
1773 return -1;
1776 // If all the data was buffered, we are done:
1777 if (remaining == 0) {
1778 return length;
1782 // Otherwise, we should write the data directly:
1783 return rb_io_write_memory(fptr, ptr, length);
1785 #endif
1787 static VALUE
1788 io_binwrite_string(VALUE arg)
1790 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1792 const char *ptr = p->ptr;
1793 size_t remaining = p->length;
1795 while (remaining) {
1796 // Write as much as possible:
1797 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1799 if (result == 0) {
1800 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1801 // should try again immediately.
1803 else if (result > 0) {
1804 if ((size_t)result == remaining) break;
1805 ptr += result;
1806 remaining -= result;
1808 // Wait for it to become writable:
1809 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1810 rb_io_check_closed(p->fptr);
1812 else {
1813 // The error was unrelated to waiting for it to become writable, so we fail:
1814 return -1;
1818 return p->length;
1821 inline static void
1822 io_allocate_write_buffer(rb_io_t *fptr, int sync)
1824 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1825 fptr->wbuf.off = 0;
1826 fptr->wbuf.len = 0;
1827 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1828 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1831 if (NIL_P(fptr->write_lock)) {
1832 fptr->write_lock = rb_mutex_new();
1833 rb_mutex_allow_trap(fptr->write_lock, 1);
1837 static inline int
1838 io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1840 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1841 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1842 return 1;
1844 // If the amount of data we want to write exceeds the internal buffer:
1845 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1846 return 1;
1848 // Otherwise, we can append to the internal buffer:
1849 return 0;
1852 static long
1853 io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1855 if (len <= 0) return len;
1857 // Don't write anything if current thread has a pending interrupt:
1858 rb_thread_check_ints();
1860 io_allocate_write_buffer(fptr, !nosync);
1862 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1863 struct binwrite_arg arg;
1865 arg.fptr = fptr;
1866 arg.ptr = ptr;
1867 arg.length = len;
1869 if (!NIL_P(fptr->write_lock)) {
1870 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1872 else {
1873 return io_binwrite_string((VALUE)&arg);
1876 else {
1877 if (fptr->wbuf.off) {
1878 if (fptr->wbuf.len)
1879 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1880 fptr->wbuf.off = 0;
1883 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1884 fptr->wbuf.len += (int)len;
1886 return len;
1890 # define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1891 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1893 #define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1894 MODE_BTMODE(d, e, f) : \
1895 MODE_BTMODE(a, b, c))
1897 static VALUE
1898 do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1900 if (NEED_WRITECONV(fptr)) {
1901 VALUE common_encoding = Qnil;
1902 SET_BINARY_MODE(fptr);
1904 make_writeconv(fptr);
1906 if (fptr->writeconv) {
1907 #define fmode (fptr->mode)
1908 if (!NIL_P(fptr->writeconv_asciicompat))
1909 common_encoding = fptr->writeconv_asciicompat;
1910 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1911 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1912 rb_enc_name(rb_enc_get(str)));
1914 #undef fmode
1916 else {
1917 if (fptr->encs.enc2)
1918 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1919 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1920 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1923 if (!NIL_P(common_encoding)) {
1924 str = rb_str_encode(str, common_encoding,
1925 fptr->writeconv_pre_ecflags, fptr->writeconv_pre_ecopts);
1926 *converted = 1;
1929 if (fptr->writeconv) {
1930 str = rb_econv_str_convert(fptr->writeconv, str, ECONV_PARTIAL_INPUT);
1931 *converted = 1;
1934 #if RUBY_CRLF_ENVIRONMENT
1935 #define fmode (fptr->mode)
1936 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1937 if ((fptr->mode & FMODE_READABLE) &&
1938 !(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
1939 setmode(fptr->fd, O_BINARY);
1941 else {
1942 setmode(fptr->fd, O_TEXT);
1944 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1945 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1946 rb_enc_name(rb_enc_get(str)));
1949 #undef fmode
1950 #endif
1951 return str;
1954 static long
1955 io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1957 int converted = 0;
1958 VALUE tmp;
1959 long n, len;
1960 const char *ptr;
1962 #ifdef _WIN32
1963 if (fptr->mode & FMODE_TTY) {
1964 long len = rb_w32_write_console(str, fptr->fd);
1965 if (len > 0) return len;
1967 #endif
1969 str = do_writeconv(str, fptr, &converted);
1970 if (converted)
1971 OBJ_FREEZE(str);
1973 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
1974 RSTRING_GETMEM(tmp, ptr, len);
1975 n = io_binwrite(ptr, len, fptr, nosync);
1976 rb_str_tmp_frozen_release(str, tmp);
1978 return n;
1981 ssize_t
1982 rb_io_bufwrite(VALUE io, const void *buf, size_t size)
1984 rb_io_t *fptr;
1986 GetOpenFile(io, fptr);
1987 rb_io_check_writable(fptr);
1988 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
1991 static VALUE
1992 io_write(VALUE io, VALUE str, int nosync)
1994 rb_io_t *fptr;
1995 long n;
1996 VALUE tmp;
1998 io = GetWriteIO(io);
1999 str = rb_obj_as_string(str);
2000 tmp = rb_io_check_io(io);
2002 if (NIL_P(tmp)) {
2003 /* port is not IO, call write method for it. */
2004 return rb_funcall(io, id_write, 1, str);
2007 io = tmp;
2008 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2010 GetOpenFile(io, fptr);
2011 rb_io_check_writable(fptr);
2013 n = io_fwrite(str, fptr, nosync);
2014 if (n < 0L) rb_sys_fail_on_write(fptr);
2016 return LONG2FIX(n);
2019 #ifdef HAVE_WRITEV
2020 struct binwritev_arg {
2021 rb_io_t *fptr;
2022 struct iovec *iov;
2023 int iovcnt;
2024 size_t total;
2027 static VALUE
2028 io_binwritev_internal(VALUE arg)
2030 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2032 size_t remaining = p->total;
2033 size_t offset = 0;
2035 rb_io_t *fptr = p->fptr;
2036 struct iovec *iov = p->iov;
2037 int iovcnt = p->iovcnt;
2039 while (remaining) {
2040 long result = rb_writev_internal(fptr, iov, iovcnt);
2042 if (result >= 0) {
2043 offset += result;
2044 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2045 if (offset < (size_t)fptr->wbuf.len) {
2046 fptr->wbuf.off += result;
2047 fptr->wbuf.len -= result;
2049 else {
2050 offset -= (size_t)fptr->wbuf.len;
2051 fptr->wbuf.off = 0;
2052 fptr->wbuf.len = 0;
2056 if (offset == p->total) {
2057 return p->total;
2060 while (result >= (ssize_t)iov->iov_len) {
2061 /* iovcnt > 0 */
2062 result -= iov->iov_len;
2063 iov->iov_len = 0;
2064 iov++;
2066 if (!--iovcnt) {
2067 // I don't believe this code path can ever occur.
2068 return offset;
2072 iov->iov_base = (char *)iov->iov_base + result;
2073 iov->iov_len -= result;
2075 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2076 rb_io_check_closed(fptr);
2078 else {
2079 return -1;
2083 return offset;
2086 static long
2087 io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2089 // Don't write anything if current thread has a pending interrupt:
2090 rb_thread_check_ints();
2092 if (iovcnt == 0) return 0;
2094 size_t total = 0;
2095 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2097 io_allocate_write_buffer(fptr, 1);
2099 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2100 // The end of the buffered data:
2101 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2103 if (offset + total <= (size_t)fptr->wbuf.capa) {
2104 for (int i = 1; i < iovcnt; i++) {
2105 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2106 offset += iov[i].iov_len;
2109 fptr->wbuf.len += total;
2111 return total;
2113 else {
2114 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2115 iov[0].iov_len = fptr->wbuf.len;
2118 else {
2119 // The first iov is reserved for the internal buffer, and it's empty.
2120 iov++;
2122 if (!--iovcnt) {
2123 // If there are no other io vectors we are done.
2124 return 0;
2128 struct binwritev_arg arg;
2129 arg.fptr = fptr;
2130 arg.iov = iov;
2131 arg.iovcnt = iovcnt;
2132 arg.total = total;
2134 if (!NIL_P(fptr->write_lock)) {
2135 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2137 else {
2138 return io_binwritev_internal((VALUE)&arg);
2142 static long
2143 io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2145 int i, converted, iovcnt = argc + 1;
2146 long n;
2147 VALUE v1, v2, str, tmp, *tmp_array;
2148 struct iovec *iov;
2150 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2151 tmp_array = ALLOCV_N(VALUE, v2, argc);
2153 for (i = 0; i < argc; i++) {
2154 str = rb_obj_as_string(argv[i]);
2155 converted = 0;
2156 str = do_writeconv(str, fptr, &converted);
2158 if (converted)
2159 OBJ_FREEZE(str);
2161 tmp = rb_str_tmp_frozen_acquire(str);
2162 tmp_array[i] = tmp;
2164 /* iov[0] is reserved for buffer of fptr */
2165 iov[i+1].iov_base = RSTRING_PTR(tmp);
2166 iov[i+1].iov_len = RSTRING_LEN(tmp);
2169 n = io_binwritev(iov, iovcnt, fptr);
2170 if (v1) ALLOCV_END(v1);
2172 for (i = 0; i < argc; i++) {
2173 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2176 if (v2) ALLOCV_END(v2);
2178 return n;
2181 static int
2182 iovcnt_ok(int iovcnt)
2184 #ifdef IOV_MAX
2185 return iovcnt < IOV_MAX;
2186 #else /* GNU/Hurd has writev, but no IOV_MAX */
2187 return 1;
2188 #endif
2190 #endif /* HAVE_WRITEV */
2192 static VALUE
2193 io_writev(int argc, const VALUE *argv, VALUE io)
2195 rb_io_t *fptr;
2196 long n;
2197 VALUE tmp, total = INT2FIX(0);
2198 int i, cnt = 1;
2200 io = GetWriteIO(io);
2201 tmp = rb_io_check_io(io);
2203 if (NIL_P(tmp)) {
2204 /* port is not IO, call write method for it. */
2205 return rb_funcallv(io, id_write, argc, argv);
2208 io = tmp;
2210 GetOpenFile(io, fptr);
2211 rb_io_check_writable(fptr);
2213 for (i = 0; i < argc; i += cnt) {
2214 #ifdef HAVE_WRITEV
2215 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2216 n = io_fwritev(cnt, &argv[i], fptr);
2218 else
2219 #endif
2221 cnt = 1;
2222 /* sync at last item */
2223 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2226 if (n < 0L)
2227 rb_sys_fail_on_write(fptr);
2229 total = rb_fix_plus(LONG2FIX(n), total);
2232 return total;
2236 * call-seq:
2237 * write(*objects) -> integer
2239 * Writes each of the given +objects+ to +self+,
2240 * which must be opened for writing
2241 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2242 * returns the total number bytes written;
2243 * each of +objects+ that is not a string is converted via method +to_s+:
2245 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2246 * $stdout.write('foo', :bar, 2, "\n") # => 8
2248 * Output:
2250 * Hello, World!
2251 * foobar2
2253 * Related: IO#read.
2256 static VALUE
2257 io_write_m(int argc, VALUE *argv, VALUE io)
2259 if (argc != 1) {
2260 return io_writev(argc, argv, io);
2262 else {
2263 VALUE str = argv[0];
2264 return io_write(io, str, 0);
2268 VALUE
2269 rb_io_write(VALUE io, VALUE str)
2271 return rb_funcallv(io, id_write, 1, &str);
2274 static VALUE
2275 rb_io_writev(VALUE io, int argc, const VALUE *argv)
2277 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2278 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2279 VALUE klass = CLASS_OF(io);
2280 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2281 rb_category_warning(
2282 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2283 " which accepts just one argument",
2284 klass, sep
2288 do rb_io_write(io, *argv++); while (--argc);
2290 return Qnil;
2293 return rb_funcallv(io, id_write, argc, argv);
2297 * call-seq:
2298 * self << object -> self
2300 * Writes the given +object+ to +self+,
2301 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2302 * returns +self+;
2303 * if +object+ is not a string, it is converted via method +to_s+:
2305 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2306 * $stdout << 'foo' << :bar << 2 << "\n"
2308 * Output:
2310 * Hello, World!
2311 * foobar2
2316 VALUE
2317 rb_io_addstr(VALUE io, VALUE str)
2319 rb_io_write(io, str);
2320 return io;
2323 #ifdef HAVE_FSYNC
2324 static VALUE
2325 nogvl_fsync(void *ptr)
2327 rb_io_t *fptr = ptr;
2329 #ifdef _WIN32
2330 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2331 return 0;
2332 #endif
2333 return (VALUE)fsync(fptr->fd);
2335 #endif
2337 VALUE
2338 rb_io_flush_raw(VALUE io, int sync)
2340 rb_io_t *fptr;
2342 if (!RB_TYPE_P(io, T_FILE)) {
2343 return rb_funcall(io, id_flush, 0);
2346 io = GetWriteIO(io);
2347 GetOpenFile(io, fptr);
2349 if (fptr->mode & FMODE_WRITABLE) {
2350 if (io_fflush(fptr) < 0)
2351 rb_sys_fail_on_write(fptr);
2353 if (fptr->mode & FMODE_READABLE) {
2354 io_unread(fptr);
2357 return io;
2361 * call-seq:
2362 * flush -> self
2364 * Flushes data buffered in +self+ to the operating system
2365 * (but does not necessarily flush data buffered in the operating system):
2367 * $stdout.print 'no newline' # Not necessarily flushed.
2368 * $stdout.flush # Flushed.
2372 VALUE
2373 rb_io_flush(VALUE io)
2375 return rb_io_flush_raw(io, 1);
2379 * call-seq:
2380 * tell -> integer
2382 * Returns the current position (in bytes) in +self+
2383 * (see {Position}[rdoc-ref:IO@Position]):
2385 * f = File.open('t.txt')
2386 * f.tell # => 0
2387 * f.gets # => "First line\n"
2388 * f.tell # => 12
2389 * f.close
2391 * Related: IO#pos=, IO#seek.
2394 static VALUE
2395 rb_io_tell(VALUE io)
2397 rb_io_t *fptr;
2398 rb_off_t pos;
2400 GetOpenFile(io, fptr);
2401 pos = io_tell(fptr);
2402 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2403 pos -= fptr->rbuf.len;
2404 return OFFT2NUM(pos);
2407 static VALUE
2408 rb_io_seek(VALUE io, VALUE offset, int whence)
2410 rb_io_t *fptr;
2411 rb_off_t pos;
2413 pos = NUM2OFFT(offset);
2414 GetOpenFile(io, fptr);
2415 pos = io_seek(fptr, pos, whence);
2416 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2418 return INT2FIX(0);
2421 static int
2422 interpret_seek_whence(VALUE vwhence)
2424 if (vwhence == sym_SET)
2425 return SEEK_SET;
2426 if (vwhence == sym_CUR)
2427 return SEEK_CUR;
2428 if (vwhence == sym_END)
2429 return SEEK_END;
2430 #ifdef SEEK_DATA
2431 if (vwhence == sym_DATA)
2432 return SEEK_DATA;
2433 #endif
2434 #ifdef SEEK_HOLE
2435 if (vwhence == sym_HOLE)
2436 return SEEK_HOLE;
2437 #endif
2438 return NUM2INT(vwhence);
2442 * call-seq:
2443 * seek(offset, whence = IO::SEEK_SET) -> 0
2445 * Seeks to the position given by integer +offset+
2446 * (see {Position}[rdoc-ref:IO@Position])
2447 * and constant +whence+, which is one of:
2449 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2450 * Repositions the stream to its current position plus the given +offset+:
2452 * f = File.open('t.txt')
2453 * f.tell # => 0
2454 * f.seek(20, :CUR) # => 0
2455 * f.tell # => 20
2456 * f.seek(-10, :CUR) # => 0
2457 * f.tell # => 10
2458 * f.close
2460 * - +:END+ or <tt>IO::SEEK_END</tt>:
2461 * Repositions the stream to its end plus the given +offset+:
2463 * f = File.open('t.txt')
2464 * f.tell # => 0
2465 * f.seek(0, :END) # => 0 # Repositions to stream end.
2466 * f.tell # => 52
2467 * f.seek(-20, :END) # => 0
2468 * f.tell # => 32
2469 * f.seek(-40, :END) # => 0
2470 * f.tell # => 12
2471 * f.close
2473 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2474 * Repositions the stream to the given +offset+:
2476 * f = File.open('t.txt')
2477 * f.tell # => 0
2478 * f.seek(20, :SET) # => 0
2479 * f.tell # => 20
2480 * f.seek(40, :SET) # => 0
2481 * f.tell # => 40
2482 * f.close
2484 * Related: IO#pos=, IO#tell.
2488 static VALUE
2489 rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2491 VALUE offset, ptrname;
2492 int whence = SEEK_SET;
2494 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2495 whence = interpret_seek_whence(ptrname);
2498 return rb_io_seek(io, offset, whence);
2502 * call-seq:
2503 * pos = new_position -> new_position
2505 * Seeks to the given +new_position+ (in bytes);
2506 * see {Position}[rdoc-ref:IO@Position]:
2508 * f = File.open('t.txt')
2509 * f.tell # => 0
2510 * f.pos = 20 # => 20
2511 * f.tell # => 20
2512 * f.close
2514 * Related: IO#seek, IO#tell.
2518 static VALUE
2519 rb_io_set_pos(VALUE io, VALUE offset)
2521 rb_io_t *fptr;
2522 rb_off_t pos;
2524 pos = NUM2OFFT(offset);
2525 GetOpenFile(io, fptr);
2526 pos = io_seek(fptr, pos, SEEK_SET);
2527 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2529 return OFFT2NUM(pos);
2532 static void clear_readconv(rb_io_t *fptr);
2535 * call-seq:
2536 * rewind -> 0
2538 * Repositions the stream to its beginning,
2539 * setting both the position and the line number to zero;
2540 * see {Position}[rdoc-ref:IO@Position]
2541 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2543 * f = File.open('t.txt')
2544 * f.tell # => 0
2545 * f.lineno # => 0
2546 * f.gets # => "First line\n"
2547 * f.tell # => 12
2548 * f.lineno # => 1
2549 * f.rewind # => 0
2550 * f.tell # => 0
2551 * f.lineno # => 0
2552 * f.close
2554 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2558 static VALUE
2559 rb_io_rewind(VALUE io)
2561 rb_io_t *fptr;
2563 GetOpenFile(io, fptr);
2564 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2565 if (io == ARGF.current_file) {
2566 ARGF.lineno -= fptr->lineno;
2568 fptr->lineno = 0;
2569 if (fptr->readconv) {
2570 clear_readconv(fptr);
2573 return INT2FIX(0);
2576 static int
2577 fptr_wait_readable(rb_io_t *fptr)
2579 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2581 if (result)
2582 rb_io_check_closed(fptr);
2584 return result;
2587 static int
2588 io_fillbuf(rb_io_t *fptr)
2590 ssize_t r;
2592 if (fptr->rbuf.ptr == NULL) {
2593 fptr->rbuf.off = 0;
2594 fptr->rbuf.len = 0;
2595 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2596 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2597 #ifdef _WIN32
2598 fptr->rbuf.capa--;
2599 #endif
2601 if (fptr->rbuf.len == 0) {
2602 retry:
2603 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2605 if (r < 0) {
2606 if (fptr_wait_readable(fptr))
2607 goto retry;
2609 int e = errno;
2610 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2611 if (!NIL_P(fptr->pathv)) {
2612 rb_str_append(path, fptr->pathv);
2615 rb_syserr_fail_path(e, path);
2617 if (r > 0) rb_io_check_closed(fptr);
2618 fptr->rbuf.off = 0;
2619 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2620 if (r == 0)
2621 return -1; /* EOF */
2623 return 0;
2627 * call-seq:
2628 * eof -> true or false
2630 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2631 * see {Position}[rdoc-ref:IO@Position]:
2633 * f = File.open('t.txt')
2634 * f.eof # => false
2635 * f.seek(0, :END) # => 0
2636 * f.eof # => true
2637 * f.close
2639 * Raises an exception unless the stream is opened for reading;
2640 * see {Mode}[rdoc-ref:File@Access+Modes].
2642 * If +self+ is a stream such as pipe or socket, this method
2643 * blocks until the other end sends some data or closes it:
2645 * r, w = IO.pipe
2646 * Thread.new { sleep 1; w.close }
2647 * r.eof? # => true # After 1-second wait.
2649 * r, w = IO.pipe
2650 * Thread.new { sleep 1; w.puts "a" }
2651 * r.eof? # => false # After 1-second wait.
2653 * r, w = IO.pipe
2654 * r.eof? # blocks forever
2656 * Note that this method reads data to the input byte buffer. So
2657 * IO#sysread may not behave as you intend with IO#eof?, unless you
2658 * call IO#rewind first (which is not available for some streams).
2661 VALUE
2662 rb_io_eof(VALUE io)
2664 rb_io_t *fptr;
2666 GetOpenFile(io, fptr);
2667 rb_io_check_char_readable(fptr);
2669 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2670 if (READ_DATA_PENDING(fptr)) return Qfalse;
2671 READ_CHECK(fptr);
2672 #if RUBY_CRLF_ENVIRONMENT
2673 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2674 return RBOOL(eof(fptr->fd));
2676 #endif
2677 return RBOOL(io_fillbuf(fptr) < 0);
2681 * call-seq:
2682 * sync -> true or false
2684 * Returns the current sync mode of the stream.
2685 * When sync mode is true, all output is immediately flushed to the underlying
2686 * operating system and is not buffered by Ruby internally. See also #fsync.
2688 * f = File.open('t.tmp', 'w')
2689 * f.sync # => false
2690 * f.sync = true
2691 * f.sync # => true
2692 * f.close
2696 static VALUE
2697 rb_io_sync(VALUE io)
2699 rb_io_t *fptr;
2701 io = GetWriteIO(io);
2702 GetOpenFile(io, fptr);
2703 return RBOOL(fptr->mode & FMODE_SYNC);
2706 #ifdef HAVE_FSYNC
2709 * call-seq:
2710 * sync = boolean -> boolean
2712 * Sets the _sync_ _mode_ for the stream to the given value;
2713 * returns the given value.
2715 * Values for the sync mode:
2717 * - +true+: All output is immediately flushed to the
2718 * underlying operating system and is not buffered internally.
2719 * - +false+: Output may be buffered internally.
2721 * Example;
2723 * f = File.open('t.tmp', 'w')
2724 * f.sync # => false
2725 * f.sync = true
2726 * f.sync # => true
2727 * f.close
2729 * Related: IO#fsync.
2733 static VALUE
2734 rb_io_set_sync(VALUE io, VALUE sync)
2736 rb_io_t *fptr;
2738 io = GetWriteIO(io);
2739 GetOpenFile(io, fptr);
2740 if (RTEST(sync)) {
2741 fptr->mode |= FMODE_SYNC;
2743 else {
2744 fptr->mode &= ~FMODE_SYNC;
2746 return sync;
2750 * call-seq:
2751 * fsync -> 0
2753 * Immediately writes to disk all data buffered in the stream,
2754 * via the operating system's <tt>fsync(2)</tt>.
2756 * Note this difference:
2758 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2759 * but does not guarantee that the operating system actually writes the data to disk.
2760 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2761 * and that data is written to disk.
2763 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2767 static VALUE
2768 rb_io_fsync(VALUE io)
2770 rb_io_t *fptr;
2772 io = GetWriteIO(io);
2773 GetOpenFile(io, fptr);
2775 if (io_fflush(fptr) < 0)
2776 rb_sys_fail_on_write(fptr);
2777 if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
2778 rb_sys_fail_path(fptr->pathv);
2779 return INT2FIX(0);
2781 #else
2782 # define rb_io_fsync rb_f_notimplement
2783 # define rb_io_sync rb_f_notimplement
2784 static VALUE
2785 rb_io_set_sync(VALUE io, VALUE sync)
2787 rb_notimplement();
2788 UNREACHABLE;
2790 #endif
2792 #ifdef HAVE_FDATASYNC
2793 static VALUE
2794 nogvl_fdatasync(void *ptr)
2796 rb_io_t *fptr = ptr;
2798 #ifdef _WIN32
2799 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2800 return 0;
2801 #endif
2802 return (VALUE)fdatasync(fptr->fd);
2806 * call-seq:
2807 * fdatasync -> 0
2809 * Immediately writes to disk all data buffered in the stream,
2810 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2811 * otherwise via <tt>fsync(2)</tt>, if supported;
2812 * otherwise raises an exception.
2816 static VALUE
2817 rb_io_fdatasync(VALUE io)
2819 rb_io_t *fptr;
2821 io = GetWriteIO(io);
2822 GetOpenFile(io, fptr);
2824 if (io_fflush(fptr) < 0)
2825 rb_sys_fail_on_write(fptr);
2827 if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
2828 return INT2FIX(0);
2830 /* fall back */
2831 return rb_io_fsync(io);
2833 #else
2834 #define rb_io_fdatasync rb_io_fsync
2835 #endif
2838 * call-seq:
2839 * fileno -> integer
2841 * Returns the integer file descriptor for the stream:
2843 * $stdin.fileno # => 0
2844 * $stdout.fileno # => 1
2845 * $stderr.fileno # => 2
2846 * File.open('t.txt').fileno # => 10
2847 * f.close
2851 static VALUE
2852 rb_io_fileno(VALUE io)
2854 rb_io_t *fptr = RFILE(io)->fptr;
2855 int fd;
2857 rb_io_check_closed(fptr);
2858 fd = fptr->fd;
2859 return INT2FIX(fd);
2863 rb_io_descriptor(VALUE io)
2865 if (RB_TYPE_P(io, T_FILE)) {
2866 rb_io_t *fptr = RFILE(io)->fptr;
2867 rb_io_check_closed(fptr);
2868 return fptr->fd;
2870 else {
2871 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2872 if (!UNDEF_P(fileno)) {
2873 return RB_NUM2INT(fileno);
2877 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2879 UNREACHABLE_RETURN(-1);
2883 rb_io_mode(VALUE io)
2885 rb_io_t *fptr;
2886 GetOpenFile(io, fptr);
2887 return fptr->mode;
2891 * call-seq:
2892 * pid -> integer or nil
2894 * Returns the process ID of a child process associated with the stream,
2895 * which will have been set by IO#popen, or +nil+ if the stream was not
2896 * created by IO#popen:
2898 * pipe = IO.popen("-")
2899 * if pipe
2900 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2901 * else
2902 * $stderr.puts "In child, pid is #{$$}"
2903 * end
2905 * Output:
2907 * In child, pid is 26209
2908 * In parent, child pid is 26209
2912 static VALUE
2913 rb_io_pid(VALUE io)
2915 rb_io_t *fptr;
2917 GetOpenFile(io, fptr);
2918 if (!fptr->pid)
2919 return Qnil;
2920 return PIDT2NUM(fptr->pid);
2924 * call-seq:
2925 * path -> string or nil
2927 * Returns the path associated with the IO, or +nil+ if there is no path
2928 * associated with the IO. It is not guaranteed that the path exists on
2929 * the filesystem.
2931 * $stdin.path # => "<STDIN>"
2933 * File.open("testfile") {|f| f.path} # => "testfile"
2936 VALUE
2937 rb_io_path(VALUE io)
2939 rb_io_t *fptr = RFILE(io)->fptr;
2941 if (!fptr)
2942 return Qnil;
2944 return rb_obj_dup(fptr->pathv);
2948 * call-seq:
2949 * inspect -> string
2951 * Returns a string representation of +self+:
2953 * f = File.open('t.txt')
2954 * f.inspect # => "#<File:t.txt>"
2955 * f.close
2959 static VALUE
2960 rb_io_inspect(VALUE obj)
2962 rb_io_t *fptr;
2963 VALUE result;
2964 static const char closed[] = " (closed)";
2966 fptr = RFILE(obj)->fptr;
2967 if (!fptr) return rb_any_to_s(obj);
2968 result = rb_str_new_cstr("#<");
2969 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2970 rb_str_cat2(result, ":");
2971 if (NIL_P(fptr->pathv)) {
2972 if (fptr->fd < 0) {
2973 rb_str_cat(result, closed+1, strlen(closed)-1);
2975 else {
2976 rb_str_catf(result, "fd %d", fptr->fd);
2979 else {
2980 rb_str_append(result, fptr->pathv);
2981 if (fptr->fd < 0) {
2982 rb_str_cat(result, closed, strlen(closed));
2985 return rb_str_cat2(result, ">");
2989 * call-seq:
2990 * to_io -> self
2992 * Returns +self+.
2996 static VALUE
2997 rb_io_to_io(VALUE io)
2999 return io;
3002 /* reading functions */
3003 static long
3004 read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3006 int n;
3008 n = READ_DATA_PENDING_COUNT(fptr);
3009 if (n <= 0) return 0;
3010 if (n > len) n = (int)len;
3011 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3012 fptr->rbuf.off += n;
3013 fptr->rbuf.len -= n;
3014 return n;
3017 static long
3018 io_bufread(char *ptr, long len, rb_io_t *fptr)
3020 long offset = 0;
3021 long n = len;
3022 long c;
3024 if (READ_DATA_PENDING(fptr) == 0) {
3025 while (n > 0) {
3026 again:
3027 rb_io_check_closed(fptr);
3028 c = rb_io_read_memory(fptr, ptr+offset, n);
3029 if (c == 0) break;
3030 if (c < 0) {
3031 if (fptr_wait_readable(fptr))
3032 goto again;
3033 return -1;
3035 offset += c;
3036 if ((n -= c) <= 0) break;
3038 return len - n;
3041 while (n > 0) {
3042 c = read_buffered_data(ptr+offset, n, fptr);
3043 if (c > 0) {
3044 offset += c;
3045 if ((n -= c) <= 0) break;
3047 rb_io_check_closed(fptr);
3048 if (io_fillbuf(fptr) < 0) {
3049 break;
3052 return len - n;
3055 static int io_setstrbuf(VALUE *str, long len);
3057 struct bufread_arg {
3058 char *str_ptr;
3059 long len;
3060 rb_io_t *fptr;
3063 static VALUE
3064 bufread_call(VALUE arg)
3066 struct bufread_arg *p = (struct bufread_arg *)arg;
3067 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3068 return Qundef;
3071 static long
3072 io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3074 long len;
3075 struct bufread_arg arg;
3077 io_setstrbuf(&str, offset + size);
3078 arg.str_ptr = RSTRING_PTR(str) + offset;
3079 arg.len = size;
3080 arg.fptr = fptr;
3081 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3082 len = arg.len;
3083 if (len < 0) rb_sys_fail_path(fptr->pathv);
3084 return len;
3087 static long
3088 remain_size(rb_io_t *fptr)
3090 struct stat st;
3091 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3092 rb_off_t pos;
3094 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3095 #if defined(__HAIKU__)
3096 && (st.st_dev > 3)
3097 #endif
3100 if (io_fflush(fptr) < 0)
3101 rb_sys_fail_on_write(fptr);
3102 pos = lseek(fptr->fd, 0, SEEK_CUR);
3103 if (st.st_size >= pos && pos >= 0) {
3104 siz += st.st_size - pos;
3105 if (siz > LONG_MAX) {
3106 rb_raise(rb_eIOError, "file too big for single read");
3110 else {
3111 siz += BUFSIZ;
3113 return (long)siz;
3116 static VALUE
3117 io_enc_str(VALUE str, rb_io_t *fptr)
3119 rb_enc_associate(str, io_read_encoding(fptr));
3120 return str;
3123 static rb_encoding *io_read_encoding(rb_io_t *fptr);
3125 static void
3126 make_readconv(rb_io_t *fptr, int size)
3128 if (!fptr->readconv) {
3129 int ecflags;
3130 VALUE ecopts;
3131 const char *sname, *dname;
3132 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3133 ecopts = fptr->encs.ecopts;
3134 if (fptr->encs.enc2) {
3135 sname = rb_enc_name(fptr->encs.enc2);
3136 dname = rb_enc_name(io_read_encoding(fptr));
3138 else {
3139 sname = dname = "";
3141 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3142 if (!fptr->readconv)
3143 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3144 fptr->cbuf.off = 0;
3145 fptr->cbuf.len = 0;
3146 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3147 fptr->cbuf.capa = size;
3148 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3152 #define MORE_CHAR_SUSPENDED Qtrue
3153 #define MORE_CHAR_FINISHED Qnil
3154 static VALUE
3155 fill_cbuf(rb_io_t *fptr, int ec_flags)
3157 const unsigned char *ss, *sp, *se;
3158 unsigned char *ds, *dp, *de;
3159 rb_econv_result_t res;
3160 int putbackable;
3161 int cbuf_len0;
3162 VALUE exc;
3164 ec_flags |= ECONV_PARTIAL_INPUT;
3166 if (fptr->cbuf.len == fptr->cbuf.capa)
3167 return MORE_CHAR_SUSPENDED; /* cbuf full */
3168 if (fptr->cbuf.len == 0)
3169 fptr->cbuf.off = 0;
3170 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3171 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3172 fptr->cbuf.off = 0;
3175 cbuf_len0 = fptr->cbuf.len;
3177 while (1) {
3178 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3179 se = sp + fptr->rbuf.len;
3180 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3181 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3182 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3183 fptr->rbuf.off += (int)(sp - ss);
3184 fptr->rbuf.len -= (int)(sp - ss);
3185 fptr->cbuf.len += (int)(dp - ds);
3187 putbackable = rb_econv_putbackable(fptr->readconv);
3188 if (putbackable) {
3189 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3190 fptr->rbuf.off -= putbackable;
3191 fptr->rbuf.len += putbackable;
3194 exc = rb_econv_make_exception(fptr->readconv);
3195 if (!NIL_P(exc))
3196 return exc;
3198 if (cbuf_len0 != fptr->cbuf.len)
3199 return MORE_CHAR_SUSPENDED;
3201 if (res == econv_finished) {
3202 return MORE_CHAR_FINISHED;
3205 if (res == econv_source_buffer_empty) {
3206 if (fptr->rbuf.len == 0) {
3207 READ_CHECK(fptr);
3208 if (io_fillbuf(fptr) < 0) {
3209 if (!fptr->readconv) {
3210 return MORE_CHAR_FINISHED;
3212 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3213 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3214 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3215 fptr->cbuf.len += (int)(dp - ds);
3216 rb_econv_check_error(fptr->readconv);
3217 break;
3222 if (cbuf_len0 != fptr->cbuf.len)
3223 return MORE_CHAR_SUSPENDED;
3225 return MORE_CHAR_FINISHED;
3228 static VALUE
3229 more_char(rb_io_t *fptr)
3231 VALUE v;
3232 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3233 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3234 rb_exc_raise(v);
3235 return v;
3238 static VALUE
3239 io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3241 VALUE str = Qnil;
3242 if (strp) {
3243 str = *strp;
3244 if (NIL_P(str)) {
3245 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3247 else {
3248 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3250 rb_enc_associate(str, fptr->encs.enc);
3252 fptr->cbuf.off += len;
3253 fptr->cbuf.len -= len;
3254 /* xxx: set coderange */
3255 if (fptr->cbuf.len == 0)
3256 fptr->cbuf.off = 0;
3257 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3258 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3259 fptr->cbuf.off = 0;
3261 return str;
3264 static int
3265 io_setstrbuf(VALUE *str, long len)
3267 #ifdef _WIN32
3268 if (len > 0)
3269 len = (len + 1) & ~1L; /* round up for wide char */
3270 #endif
3271 if (NIL_P(*str)) {
3272 *str = rb_str_new(0, len);
3273 return TRUE;
3275 else {
3276 VALUE s = StringValue(*str);
3277 rb_str_modify(s);
3279 long clen = RSTRING_LEN(s);
3280 if (clen >= len) {
3281 return FALSE;
3283 len -= clen;
3285 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3286 rb_str_modify_expand(*str, len);
3288 return FALSE;
3291 #define MAX_REALLOC_GAP 4096
3292 static void
3293 io_shrink_read_string(VALUE str, long n)
3295 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3296 rb_str_resize(str, n);
3300 static void
3301 io_set_read_length(VALUE str, long n, int shrinkable)
3303 if (RSTRING_LEN(str) != n) {
3304 rb_str_modify(str);
3305 rb_str_set_len(str, n);
3306 if (shrinkable) io_shrink_read_string(str, n);
3310 static VALUE
3311 read_all(rb_io_t *fptr, long siz, VALUE str)
3313 long bytes;
3314 long n;
3315 long pos;
3316 rb_encoding *enc;
3317 int cr;
3318 int shrinkable;
3320 if (NEED_READCONV(fptr)) {
3321 int first = !NIL_P(str);
3322 SET_BINARY_MODE(fptr);
3323 shrinkable = io_setstrbuf(&str,0);
3324 make_readconv(fptr, 0);
3325 while (1) {
3326 VALUE v;
3327 if (fptr->cbuf.len) {
3328 if (first) rb_str_set_len(str, first = 0);
3329 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3331 v = fill_cbuf(fptr, 0);
3332 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3333 if (fptr->cbuf.len) {
3334 if (first) rb_str_set_len(str, first = 0);
3335 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3337 rb_exc_raise(v);
3339 if (v == MORE_CHAR_FINISHED) {
3340 clear_readconv(fptr);
3341 if (first) rb_str_set_len(str, first = 0);
3342 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3343 return io_enc_str(str, fptr);
3348 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3349 bytes = 0;
3350 pos = 0;
3352 enc = io_read_encoding(fptr);
3353 cr = 0;
3355 if (siz == 0) siz = BUFSIZ;
3356 shrinkable = io_setstrbuf(&str, siz);
3357 for (;;) {
3358 READ_CHECK(fptr);
3359 n = io_fread(str, bytes, siz - bytes, fptr);
3360 if (n == 0 && bytes == 0) {
3361 rb_str_set_len(str, 0);
3362 break;
3364 bytes += n;
3365 rb_str_set_len(str, bytes);
3366 if (cr != ENC_CODERANGE_BROKEN)
3367 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3368 if (bytes < siz) break;
3369 siz += BUFSIZ;
3371 size_t capa = rb_str_capacity(str);
3372 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3373 if (capa < BUFSIZ) {
3374 capa = BUFSIZ;
3376 else if (capa > IO_MAX_BUFFER_GROWTH) {
3377 capa = IO_MAX_BUFFER_GROWTH;
3379 rb_str_modify_expand(str, capa);
3382 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3383 str = io_enc_str(str, fptr);
3384 ENC_CODERANGE_SET(str, cr);
3385 return str;
3388 void
3389 rb_io_set_nonblock(rb_io_t *fptr)
3391 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3392 rb_sys_fail_path(fptr->pathv);
3396 static VALUE
3397 io_read_memory_call(VALUE arg)
3399 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3401 VALUE scheduler = rb_fiber_scheduler_current();
3402 if (scheduler != Qnil) {
3403 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3405 if (!UNDEF_P(result)) {
3406 // This is actually returned as a pseudo-VALUE and later cast to a long:
3407 return (VALUE)rb_fiber_scheduler_io_result_apply(result);
3411 if (iis->nonblock) {
3412 return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->fd, 0);
3414 else {
3415 return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->fd, RB_WAITFD_IN);
3419 static long
3420 io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3422 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3425 #define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3427 static VALUE
3428 io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3430 rb_io_t *fptr;
3431 VALUE length, str;
3432 long n, len;
3433 struct io_internal_read_struct iis;
3434 int shrinkable;
3436 rb_scan_args(argc, argv, "11", &length, &str);
3438 if ((len = NUM2LONG(length)) < 0) {
3439 rb_raise(rb_eArgError, "negative length %ld given", len);
3442 shrinkable = io_setstrbuf(&str, len);
3444 GetOpenFile(io, fptr);
3445 rb_io_check_byte_readable(fptr);
3447 if (len == 0) {
3448 io_set_read_length(str, 0, shrinkable);
3449 return str;
3452 if (!nonblock)
3453 READ_CHECK(fptr);
3454 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3455 if (n <= 0) {
3456 again:
3457 if (nonblock) {
3458 rb_io_set_nonblock(fptr);
3460 io_setstrbuf(&str, len);
3461 iis.th = rb_thread_current();
3462 iis.fptr = fptr;
3463 iis.nonblock = nonblock;
3464 iis.fd = fptr->fd;
3465 iis.buf = RSTRING_PTR(str);
3466 iis.capa = len;
3467 iis.timeout = NULL;
3468 n = io_read_memory_locktmp(str, &iis);
3469 if (n < 0) {
3470 int e = errno;
3471 if (!nonblock && fptr_wait_readable(fptr))
3472 goto again;
3473 if (nonblock && (io_again_p(e))) {
3474 if (no_exception)
3475 return sym_wait_readable;
3476 else
3477 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3478 e, "read would block");
3480 rb_syserr_fail_path(e, fptr->pathv);
3483 io_set_read_length(str, n, shrinkable);
3485 if (n == 0)
3486 return Qnil;
3487 else
3488 return str;
3492 * call-seq:
3493 * readpartial(maxlen) -> string
3494 * readpartial(maxlen, out_string) -> out_string
3496 * Reads up to +maxlen+ bytes from the stream;
3497 * returns a string (either a new string or the given +out_string+).
3498 * Its encoding is:
3500 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3501 * - ASCII-8BIT, otherwise.
3503 * - Contains +maxlen+ bytes from the stream, if available.
3504 * - Otherwise contains all available bytes, if any available.
3505 * - Otherwise is an empty string.
3507 * With the single non-negative integer argument +maxlen+ given,
3508 * returns a new string:
3510 * f = File.new('t.txt')
3511 * f.readpartial(20) # => "First line\nSecond l"
3512 * f.readpartial(20) # => "ine\n\nFourth line\n"
3513 * f.readpartial(20) # => "Fifth line\n"
3514 * f.readpartial(20) # Raises EOFError.
3515 * f.close
3517 * With both argument +maxlen+ and string argument +out_string+ given,
3518 * returns modified +out_string+:
3520 * f = File.new('t.txt')
3521 * s = 'foo'
3522 * f.readpartial(20, s) # => "First line\nSecond l"
3523 * s = 'bar'
3524 * f.readpartial(0, s) # => ""
3525 * f.close
3527 * This method is useful for a stream such as a pipe, a socket, or a tty.
3528 * It blocks only when no data is immediately available.
3529 * This means that it blocks only when _all_ of the following are true:
3531 * - The byte buffer in the stream is empty.
3532 * - The content of the stream is empty.
3533 * - The stream is not at EOF.
3535 * When blocked, the method waits for either more data or EOF on the stream:
3537 * - If more data is read, the method returns the data.
3538 * - If EOF is reached, the method raises EOFError.
3540 * When not blocked, the method responds immediately:
3542 * - Returns data from the buffer if there is any.
3543 * - Otherwise returns data from the stream if there is any.
3544 * - Otherwise raises EOFError if the stream has reached EOF.
3546 * Note that this method is similar to sysread. The differences are:
3548 * - If the byte buffer is not empty, read from the byte buffer
3549 * instead of "sysread for buffered IO (IOError)".
3550 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3551 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3552 * readpartial retries the system call.
3554 * The latter means that readpartial is non-blocking-flag insensitive.
3555 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3556 * if the fd is blocking mode.
3558 * Examples:
3560 * # # Returned Buffer Content Pipe Content
3561 * r, w = IO.pipe #
3562 * w << 'abc' # "" "abc".
3563 * r.readpartial(4096) # => "abc" "" ""
3564 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3566 * # # Returned Buffer Content Pipe Content
3567 * r, w = IO.pipe #
3568 * w << 'abc' # "" "abc"
3569 * w.close # "" "abc" EOF
3570 * r.readpartial(4096) # => "abc" "" EOF
3571 * r.readpartial(4096) # raises EOFError
3573 * # # Returned Buffer Content Pipe Content
3574 * r, w = IO.pipe #
3575 * w << "abc\ndef\n" # "" "abc\ndef\n"
3576 * r.gets # => "abc\n" "def\n" ""
3577 * w << "ghi\n" # "def\n" "ghi\n"
3578 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3579 * r.readpartial(4096) # => "ghi\n" "" ""
3583 static VALUE
3584 io_readpartial(int argc, VALUE *argv, VALUE io)
3586 VALUE ret;
3588 ret = io_getpartial(argc, argv, io, Qnil, 0);
3589 if (NIL_P(ret))
3590 rb_eof_error();
3591 return ret;
3594 static VALUE
3595 io_nonblock_eof(int no_exception)
3597 if (!no_exception) {
3598 rb_eof_error();
3600 return Qnil;
3603 /* :nodoc: */
3604 static VALUE
3605 io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3607 rb_io_t *fptr;
3608 long n, len;
3609 struct io_internal_read_struct iis;
3610 int shrinkable;
3612 if ((len = NUM2LONG(length)) < 0) {
3613 rb_raise(rb_eArgError, "negative length %ld given", len);
3616 shrinkable = io_setstrbuf(&str, len);
3617 rb_bool_expected(ex, "exception", TRUE);
3619 GetOpenFile(io, fptr);
3620 rb_io_check_byte_readable(fptr);
3622 if (len == 0) {
3623 io_set_read_length(str, 0, shrinkable);
3624 return str;
3627 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3628 if (n <= 0) {
3629 rb_fd_set_nonblock(fptr->fd);
3630 shrinkable |= io_setstrbuf(&str, len);
3631 iis.fptr = fptr;
3632 iis.nonblock = 1;
3633 iis.fd = fptr->fd;
3634 iis.buf = RSTRING_PTR(str);
3635 iis.capa = len;
3636 iis.timeout = NULL;
3637 n = io_read_memory_locktmp(str, &iis);
3638 if (n < 0) {
3639 int e = errno;
3640 if (io_again_p(e)) {
3641 if (!ex) return sym_wait_readable;
3642 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3643 e, "read would block");
3645 rb_syserr_fail_path(e, fptr->pathv);
3648 io_set_read_length(str, n, shrinkable);
3650 if (n == 0) {
3651 if (!ex) return Qnil;
3652 rb_eof_error();
3655 return str;
3658 /* :nodoc: */
3659 static VALUE
3660 io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3662 rb_io_t *fptr;
3663 long n;
3665 if (!RB_TYPE_P(str, T_STRING))
3666 str = rb_obj_as_string(str);
3667 rb_bool_expected(ex, "exception", TRUE);
3669 io = GetWriteIO(io);
3670 GetOpenFile(io, fptr);
3671 rb_io_check_writable(fptr);
3673 if (io_fflush(fptr) < 0)
3674 rb_sys_fail_on_write(fptr);
3676 rb_fd_set_nonblock(fptr->fd);
3677 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3678 RB_GC_GUARD(str);
3680 if (n < 0) {
3681 int e = errno;
3682 if (io_again_p(e)) {
3683 if (!ex) {
3684 return sym_wait_writable;
3686 else {
3687 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3690 rb_syserr_fail_path(e, fptr->pathv);
3693 return LONG2FIX(n);
3697 * call-seq:
3698 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3700 * Reads bytes from the stream; the stream must be opened for reading
3701 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3703 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3704 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3706 * Returns a string (either a new string or the given +out_string+)
3707 * containing the bytes read.
3708 * The encoding of the string depends on both +maxLen+ and +out_string+:
3710 * - +maxlen+ is +nil+: uses internal encoding of +self+
3711 * (regardless of whether +out_string+ was given).
3712 * - +maxlen+ not +nil+:
3714 * - +out_string+ given: encoding of +out_string+ not modified.
3715 * - +out_string+ not given: ASCII-8BIT is used.
3717 * <b>Without Argument +out_string+</b>
3719 * When argument +out_string+ is omitted,
3720 * the returned value is a new string:
3722 * f = File.new('t.txt')
3723 * f.read
3724 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3725 * f.rewind
3726 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3727 * f.read(30) # => "rth line\r\nFifth line\r\n"
3728 * f.read(30) # => nil
3729 * f.close
3731 * If +maxlen+ is zero, returns an empty string.
3733 * <b> With Argument +out_string+</b>
3735 * When argument +out_string+ is given,
3736 * the returned value is +out_string+, whose content is replaced:
3738 * f = File.new('t.txt')
3739 * s = 'foo' # => "foo"
3740 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3741 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3742 * f.rewind
3743 * s = 'bar'
3744 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3745 * s # => "First line\r\nSecond line\r\n\r\nFou"
3746 * s = 'baz'
3747 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3748 * s # => "rth line\r\nFifth line\r\n"
3749 * s = 'bat'
3750 * f.read(30, s) # => nil
3751 * s # => ""
3752 * f.close
3754 * Note that this method behaves like the fread() function in C.
3755 * This means it retries to invoke read(2) system calls to read data
3756 * with the specified maxlen (or until EOF).
3758 * This behavior is preserved even if the stream is in non-blocking mode.
3759 * (This method is non-blocking-flag insensitive as other methods.)
3761 * If you need the behavior like a single read(2) system call,
3762 * consider #readpartial, #read_nonblock, and #sysread.
3764 * Related: IO#write.
3767 static VALUE
3768 io_read(int argc, VALUE *argv, VALUE io)
3770 rb_io_t *fptr;
3771 long n, len;
3772 VALUE length, str;
3773 int shrinkable;
3774 #if RUBY_CRLF_ENVIRONMENT
3775 int previous_mode;
3776 #endif
3778 rb_scan_args(argc, argv, "02", &length, &str);
3780 if (NIL_P(length)) {
3781 GetOpenFile(io, fptr);
3782 rb_io_check_char_readable(fptr);
3783 return read_all(fptr, remain_size(fptr), str);
3785 len = NUM2LONG(length);
3786 if (len < 0) {
3787 rb_raise(rb_eArgError, "negative length %ld given", len);
3790 shrinkable = io_setstrbuf(&str,len);
3792 GetOpenFile(io, fptr);
3793 rb_io_check_byte_readable(fptr);
3794 if (len == 0) {
3795 io_set_read_length(str, 0, shrinkable);
3796 return str;
3799 READ_CHECK(fptr);
3800 #if RUBY_CRLF_ENVIRONMENT
3801 previous_mode = set_binary_mode_with_seek_cur(fptr);
3802 #endif
3803 n = io_fread(str, 0, len, fptr);
3804 io_set_read_length(str, n, shrinkable);
3805 #if RUBY_CRLF_ENVIRONMENT
3806 if (previous_mode == O_TEXT) {
3807 setmode(fptr->fd, O_TEXT);
3809 #endif
3810 if (n == 0) return Qnil;
3812 return str;
3815 static void
3816 rscheck(const char *rsptr, long rslen, VALUE rs)
3818 if (!rs) return;
3819 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3820 rb_raise(rb_eRuntimeError, "rs modified");
3823 static int
3824 appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
3826 VALUE str = *strp;
3827 long limit = *lp;
3829 if (NEED_READCONV(fptr)) {
3830 SET_BINARY_MODE(fptr);
3831 make_readconv(fptr, 0);
3832 do {
3833 const char *p, *e;
3834 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3835 if (searchlen) {
3836 p = READ_CHAR_PENDING_PTR(fptr);
3837 if (0 < limit && limit < searchlen)
3838 searchlen = (int)limit;
3839 e = memchr(p, delim, searchlen);
3840 if (e) {
3841 int len = (int)(e-p+1);
3842 if (NIL_P(str))
3843 *strp = str = rb_str_new(p, len);
3844 else
3845 rb_str_buf_cat(str, p, len);
3846 fptr->cbuf.off += len;
3847 fptr->cbuf.len -= len;
3848 limit -= len;
3849 *lp = limit;
3850 return delim;
3853 if (NIL_P(str))
3854 *strp = str = rb_str_new(p, searchlen);
3855 else
3856 rb_str_buf_cat(str, p, searchlen);
3857 fptr->cbuf.off += searchlen;
3858 fptr->cbuf.len -= searchlen;
3859 limit -= searchlen;
3861 if (limit == 0) {
3862 *lp = limit;
3863 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3866 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3867 clear_readconv(fptr);
3868 *lp = limit;
3869 return EOF;
3872 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3873 do {
3874 long pending = READ_DATA_PENDING_COUNT(fptr);
3875 if (pending > 0) {
3876 const char *p = READ_DATA_PENDING_PTR(fptr);
3877 const char *e;
3878 long last;
3880 if (limit > 0 && pending > limit) pending = limit;
3881 e = memchr(p, delim, pending);
3882 if (e) pending = e - p + 1;
3883 if (!NIL_P(str)) {
3884 last = RSTRING_LEN(str);
3885 rb_str_resize(str, last + pending);
3887 else {
3888 last = 0;
3889 *strp = str = rb_str_buf_new(pending);
3890 rb_str_set_len(str, pending);
3892 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3893 limit -= pending;
3894 *lp = limit;
3895 if (e) return delim;
3896 if (limit == 0)
3897 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3899 READ_CHECK(fptr);
3900 } while (io_fillbuf(fptr) >= 0);
3901 *lp = limit;
3902 return EOF;
3905 static inline int
3906 swallow(rb_io_t *fptr, int term)
3908 if (NEED_READCONV(fptr)) {
3909 rb_encoding *enc = io_read_encoding(fptr);
3910 int needconv = rb_enc_mbminlen(enc) != 1;
3911 SET_BINARY_MODE(fptr);
3912 make_readconv(fptr, 0);
3913 do {
3914 size_t cnt;
3915 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3916 const char *p = READ_CHAR_PENDING_PTR(fptr);
3917 int i;
3918 if (!needconv) {
3919 if (*p != term) return TRUE;
3920 i = (int)cnt;
3921 while (--i && *++p == term);
3923 else {
3924 const char *e = p + cnt;
3925 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3926 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3927 i = (int)(e - p);
3929 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3931 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3932 return FALSE;
3935 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3936 do {
3937 size_t cnt;
3938 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3939 char buf[1024];
3940 const char *p = READ_DATA_PENDING_PTR(fptr);
3941 int i;
3942 if (cnt > sizeof buf) cnt = sizeof buf;
3943 if (*p != term) return TRUE;
3944 i = (int)cnt;
3945 while (--i && *++p == term);
3946 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
3947 rb_sys_fail_path(fptr->pathv);
3949 READ_CHECK(fptr);
3950 } while (io_fillbuf(fptr) == 0);
3951 return FALSE;
3954 static VALUE
3955 rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
3957 VALUE str = Qnil;
3958 int len = 0;
3959 long pos = 0;
3960 int cr = 0;
3962 do {
3963 int pending = READ_DATA_PENDING_COUNT(fptr);
3965 if (pending > 0) {
3966 const char *p = READ_DATA_PENDING_PTR(fptr);
3967 const char *e;
3968 int chomplen = 0;
3970 e = memchr(p, '\n', pending);
3971 if (e) {
3972 pending = (int)(e - p + 1);
3973 if (chomp) {
3974 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
3977 if (NIL_P(str)) {
3978 str = rb_str_new(p, pending - chomplen);
3979 fptr->rbuf.off += pending;
3980 fptr->rbuf.len -= pending;
3982 else {
3983 rb_str_resize(str, len + pending - chomplen);
3984 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
3985 fptr->rbuf.off += chomplen;
3986 fptr->rbuf.len -= chomplen;
3987 if (pending == 1 && chomplen == 1 && len > 0) {
3988 if (RSTRING_PTR(str)[len-1] == '\r') {
3989 rb_str_resize(str, --len);
3990 break;
3994 len += pending - chomplen;
3995 if (cr != ENC_CODERANGE_BROKEN)
3996 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
3997 if (e) break;
3999 READ_CHECK(fptr);
4000 } while (io_fillbuf(fptr) >= 0);
4001 if (NIL_P(str)) return Qnil;
4003 str = io_enc_str(str, fptr);
4004 ENC_CODERANGE_SET(str, cr);
4005 fptr->lineno++;
4007 return str;
4010 struct getline_arg {
4011 VALUE io;
4012 VALUE rs;
4013 long limit;
4014 unsigned int chomp: 1;
4017 static void
4018 extract_getline_opts(VALUE opts, struct getline_arg *args)
4020 int chomp = FALSE;
4021 if (!NIL_P(opts)) {
4022 static ID kwds[1];
4023 VALUE vchomp;
4024 if (!kwds[0]) {
4025 kwds[0] = rb_intern_const("chomp");
4027 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4028 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4030 args->chomp = chomp;
4033 static void
4034 extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4036 VALUE rs = rb_rs, lim = Qnil;
4038 if (argc == 1) {
4039 VALUE tmp = Qnil;
4041 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4042 rs = tmp;
4044 else {
4045 lim = argv[0];
4048 else if (2 <= argc) {
4049 rs = argv[0], lim = argv[1];
4050 if (!NIL_P(rs))
4051 StringValue(rs);
4053 args->rs = rs;
4054 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4057 static void
4058 check_getline_args(VALUE *rsp, long *limit, VALUE io)
4060 rb_io_t *fptr;
4061 VALUE rs = *rsp;
4063 if (!NIL_P(rs)) {
4064 rb_encoding *enc_rs, *enc_io;
4066 GetOpenFile(io, fptr);
4067 enc_rs = rb_enc_get(rs);
4068 enc_io = io_read_encoding(fptr);
4069 if (enc_io != enc_rs &&
4070 (!is_ascii_string(rs) ||
4071 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4072 if (rs == rb_default_rs) {
4073 rs = rb_enc_str_new(0, 0, enc_io);
4074 rb_str_buf_cat_ascii(rs, "\n");
4075 *rsp = rs;
4077 else {
4078 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4079 rb_enc_name(enc_io),
4080 rb_enc_name(enc_rs));
4086 static void
4087 prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4089 VALUE opts;
4090 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4091 extract_getline_args(argc, argv, args);
4092 extract_getline_opts(opts, args);
4093 check_getline_args(&args->rs, &args->limit, io);
4096 static VALUE
4097 rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4099 VALUE str = Qnil;
4100 int nolimit = 0;
4101 rb_encoding *enc;
4103 rb_io_check_char_readable(fptr);
4104 if (NIL_P(rs) && limit < 0) {
4105 str = read_all(fptr, 0, Qnil);
4106 if (RSTRING_LEN(str) == 0) return Qnil;
4108 else if (limit == 0) {
4109 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4111 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4112 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4113 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4114 return rb_io_getline_fast(fptr, enc, chomp);
4116 else {
4117 int c, newline = -1;
4118 const char *rsptr = 0;
4119 long rslen = 0;
4120 int rspara = 0;
4121 int extra_limit = 16;
4122 int chomp_cr = chomp;
4124 SET_BINARY_MODE(fptr);
4125 enc = io_read_encoding(fptr);
4127 if (!NIL_P(rs)) {
4128 rslen = RSTRING_LEN(rs);
4129 if (rslen == 0) {
4130 rsptr = "\n\n";
4131 rslen = 2;
4132 rspara = 1;
4133 swallow(fptr, '\n');
4134 rs = 0;
4135 if (!rb_enc_asciicompat(enc)) {
4136 rs = rb_usascii_str_new(rsptr, rslen);
4137 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
4138 OBJ_FREEZE(rs);
4139 rsptr = RSTRING_PTR(rs);
4140 rslen = RSTRING_LEN(rs);
4143 else {
4144 rsptr = RSTRING_PTR(rs);
4146 newline = (unsigned char)rsptr[rslen - 1];
4147 chomp_cr = chomp && rslen == 1 && newline == '\n';
4150 /* MS - Optimization */
4151 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
4152 const char *s, *p, *pp, *e;
4154 if (c == newline) {
4155 if (RSTRING_LEN(str) < rslen) continue;
4156 s = RSTRING_PTR(str);
4157 e = RSTRING_END(str);
4158 p = e - rslen;
4159 if (!at_char_boundary(s, p, e, enc)) continue;
4160 if (!rspara) rscheck(rsptr, rslen, rs);
4161 if (memcmp(p, rsptr, rslen) == 0) {
4162 if (chomp) {
4163 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4164 rb_str_set_len(str, p - s);
4166 break;
4169 if (limit == 0) {
4170 s = RSTRING_PTR(str);
4171 p = RSTRING_END(str);
4172 pp = rb_enc_left_char_head(s, p-1, p, enc);
4173 if (extra_limit &&
4174 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4175 /* relax the limit while incomplete character.
4176 * extra_limit limits the relax length */
4177 limit = 1;
4178 extra_limit--;
4180 else {
4181 nolimit = 1;
4182 break;
4187 if (rspara && c != EOF)
4188 swallow(fptr, '\n');
4189 if (!NIL_P(str))
4190 str = io_enc_str(str, fptr);
4193 if (!NIL_P(str) && !nolimit) {
4194 fptr->lineno++;
4197 return str;
4200 static VALUE
4201 rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4203 rb_io_t *fptr;
4204 int old_lineno, new_lineno;
4205 VALUE str;
4207 GetOpenFile(io, fptr);
4208 old_lineno = fptr->lineno;
4209 str = rb_io_getline_0(rs, limit, chomp, fptr);
4210 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4211 if (io == ARGF.current_file) {
4212 ARGF.lineno += new_lineno - old_lineno;
4213 ARGF.last_lineno = ARGF.lineno;
4215 else {
4216 ARGF.last_lineno = new_lineno;
4220 return str;
4223 static VALUE
4224 rb_io_getline(int argc, VALUE *argv, VALUE io)
4226 struct getline_arg args;
4228 prepare_getline_args(argc, argv, &args, io);
4229 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4232 VALUE
4233 rb_io_gets(VALUE io)
4235 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4238 VALUE
4239 rb_io_gets_internal(VALUE io)
4241 rb_io_t *fptr;
4242 GetOpenFile(io, fptr);
4243 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4247 * call-seq:
4248 * gets(sep = $/, chomp: false) -> string or nil
4249 * gets(limit, chomp: false) -> string or nil
4250 * gets(sep, limit, chomp: false) -> string or nil
4252 * Reads and returns a line from the stream;
4253 * assigns the return value to <tt>$_</tt>.
4254 * See {Line IO}[rdoc-ref:IO@Line+IO].
4256 * With no arguments given, returns the next line
4257 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4259 * f = File.open('t.txt')
4260 * f.gets # => "First line\n"
4261 * $_ # => "First line\n"
4262 * f.gets # => "\n"
4263 * f.gets # => "Fourth line\n"
4264 * f.gets # => "Fifth line\n"
4265 * f.gets # => nil
4266 * f.close
4268 * With only string argument +sep+ given,
4269 * returns the next line as determined by line separator +sep+,
4270 * or +nil+ if none;
4271 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4273 * f = File.new('t.txt')
4274 * f.gets('l') # => "First l"
4275 * f.gets('li') # => "ine\nSecond li"
4276 * f.gets('lin') # => "ne\n\nFourth lin"
4277 * f.gets # => "e\n"
4278 * f.close
4280 * The two special values for +sep+ are honored:
4282 * f = File.new('t.txt')
4283 * # Get all.
4284 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4285 * f.rewind
4286 * # Get paragraph (up to two line separators).
4287 * f.gets('') # => "First line\nSecond line\n\n"
4288 * f.close
4290 * With only integer argument +limit+ given,
4291 * limits the number of bytes in the line;
4292 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4294 * # No more than one line.
4295 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4296 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4297 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4299 * With arguments +sep+ and +limit+ given,
4300 * combines the two behaviors
4301 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4303 * Optional keyword argument +chomp+ specifies whether line separators
4304 * are to be omitted:
4306 * f = File.open('t.txt')
4307 * # Chomp the lines.
4308 * f.gets(chomp: true) # => "First line"
4309 * f.gets(chomp: true) # => "Second line"
4310 * f.gets(chomp: true) # => ""
4311 * f.gets(chomp: true) # => "Fourth line"
4312 * f.gets(chomp: true) # => "Fifth line"
4313 * f.gets(chomp: true) # => nil
4314 * f.close
4318 static VALUE
4319 rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4321 VALUE str;
4323 str = rb_io_getline(argc, argv, io);
4324 rb_lastline_set(str);
4326 return str;
4330 * call-seq:
4331 * lineno -> integer
4333 * Returns the current line number for the stream;
4334 * see {Line Number}[rdoc-ref:IO@Line+Number].
4338 static VALUE
4339 rb_io_lineno(VALUE io)
4341 rb_io_t *fptr;
4343 GetOpenFile(io, fptr);
4344 rb_io_check_char_readable(fptr);
4345 return INT2NUM(fptr->lineno);
4349 * call-seq:
4350 * lineno = integer -> integer
4352 * Sets and returns the line number for the stream;
4353 * see {Line Number}[rdoc-ref:IO@Line+Number].
4357 static VALUE
4358 rb_io_set_lineno(VALUE io, VALUE lineno)
4360 rb_io_t *fptr;
4362 GetOpenFile(io, fptr);
4363 rb_io_check_char_readable(fptr);
4364 fptr->lineno = NUM2INT(lineno);
4365 return lineno;
4368 /* :nodoc: */
4369 static VALUE
4370 io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4372 if (NIL_P(lim)) {
4373 // If sep is specified, but it's not a string and not nil, then assume
4374 // it's the limit (it should be an integer)
4375 if (!NIL_P(sep) && NIL_P(rb_check_string_type(sep))) {
4376 // If the user has specified a non-nil / non-string value
4377 // for the separator, we assume it's the limit and set the
4378 // separator to default: rb_rs.
4379 lim = sep;
4380 sep = rb_rs;
4384 if (!NIL_P(sep)) {
4385 StringValue(sep);
4388 VALUE line = rb_io_getline_1(sep, NIL_P(lim) ? -1L : NUM2LONG(lim), RTEST(chomp), io);
4389 rb_lastline_set_up(line, 1);
4391 if (NIL_P(line)) {
4392 rb_eof_error();
4394 return line;
4397 static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4400 * call-seq:
4401 * readlines(sep = $/, chomp: false) -> array
4402 * readlines(limit, chomp: false) -> array
4403 * readlines(sep, limit, chomp: false) -> array
4405 * Reads and returns all remaining line from the stream;
4406 * does not modify <tt>$_</tt>.
4407 * See {Line IO}[rdoc-ref:IO@Line+IO].
4409 * With no arguments given, returns lines
4410 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4412 * f = File.new('t.txt')
4413 * f.readlines
4414 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4415 * f.readlines # => []
4416 * f.close
4418 * With only string argument +sep+ given,
4419 * returns lines as determined by line separator +sep+,
4420 * or +nil+ if none;
4421 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4423 * f = File.new('t.txt')
4424 * f.readlines('li')
4425 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4426 * f.close
4428 * The two special values for +sep+ are honored:
4430 * f = File.new('t.txt')
4431 * # Get all into one string.
4432 * f.readlines(nil)
4433 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4434 * # Get paragraphs (up to two line separators).
4435 * f.rewind
4436 * f.readlines('')
4437 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4438 * f.close
4440 * With only integer argument +limit+ given,
4441 * limits the number of bytes in each line;
4442 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4444 * f = File.new('t.txt')
4445 * f.readlines(8)
4446 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4447 * f.close
4449 * With arguments +sep+ and +limit+ given,
4450 * combines the two behaviors
4451 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4453 * Optional keyword argument +chomp+ specifies whether line separators
4454 * are to be omitted:
4456 * f = File.new('t.txt')
4457 * f.readlines(chomp: true)
4458 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4459 * f.close
4463 static VALUE
4464 rb_io_readlines(int argc, VALUE *argv, VALUE io)
4466 struct getline_arg args;
4468 prepare_getline_args(argc, argv, &args, io);
4469 return io_readlines(&args, io);
4472 static VALUE
4473 io_readlines(const struct getline_arg *arg, VALUE io)
4475 VALUE line, ary;
4477 if (arg->limit == 0)
4478 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4479 ary = rb_ary_new();
4480 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4481 rb_ary_push(ary, line);
4483 return ary;
4487 * call-seq:
4488 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4489 * each_line(limit, chomp: false) {|line| ... } -> self
4490 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4491 * each_line -> enumerator
4493 * Calls the block with each remaining line read from the stream;
4494 * returns +self+.
4495 * Does nothing if already at end-of-stream;
4496 * See {Line IO}[rdoc-ref:IO@Line+IO].
4498 * With no arguments given, reads lines
4499 * as determined by line separator <tt>$/</tt>:
4501 * f = File.new('t.txt')
4502 * f.each_line {|line| p line }
4503 * f.each_line {|line| fail 'Cannot happen' }
4504 * f.close
4506 * Output:
4508 * "First line\n"
4509 * "Second line\n"
4510 * "\n"
4511 * "Fourth line\n"
4512 * "Fifth line\n"
4514 * With only string argument +sep+ given,
4515 * reads lines as determined by line separator +sep+;
4516 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4518 * f = File.new('t.txt')
4519 * f.each_line('li') {|line| p line }
4520 * f.close
4522 * Output:
4524 * "First li"
4525 * "ne\nSecond li"
4526 * "ne\n\nFourth li"
4527 * "ne\nFifth li"
4528 * "ne\n"
4530 * The two special values for +sep+ are honored:
4532 * f = File.new('t.txt')
4533 * # Get all into one string.
4534 * f.each_line(nil) {|line| p line }
4535 * f.close
4537 * Output:
4539 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4541 * f.rewind
4542 * # Get paragraphs (up to two line separators).
4543 * f.each_line('') {|line| p line }
4545 * Output:
4547 * "First line\nSecond line\n\n"
4548 * "Fourth line\nFifth line\n"
4550 * With only integer argument +limit+ given,
4551 * limits the number of bytes in each line;
4552 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4554 * f = File.new('t.txt')
4555 * f.each_line(8) {|line| p line }
4556 * f.close
4558 * Output:
4560 * "First li"
4561 * "ne\n"
4562 * "Second l"
4563 * "ine\n"
4564 * "\n"
4565 * "Fourth l"
4566 * "ine\n"
4567 * "Fifth li"
4568 * "ne\n"
4570 * With arguments +sep+ and +limit+ given,
4571 * combines the two behaviors
4572 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4574 * Optional keyword argument +chomp+ specifies whether line separators
4575 * are to be omitted:
4577 * f = File.new('t.txt')
4578 * f.each_line(chomp: true) {|line| p line }
4579 * f.close
4581 * Output:
4583 * "First line"
4584 * "Second line"
4585 * ""
4586 * "Fourth line"
4587 * "Fifth line"
4589 * Returns an Enumerator if no block is given.
4592 static VALUE
4593 rb_io_each_line(int argc, VALUE *argv, VALUE io)
4595 VALUE str;
4596 struct getline_arg args;
4598 RETURN_ENUMERATOR(io, argc, argv);
4599 prepare_getline_args(argc, argv, &args, io);
4600 if (args.limit == 0)
4601 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4602 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4603 rb_yield(str);
4605 return io;
4609 * call-seq:
4610 * each_byte {|byte| ... } -> self
4611 * each_byte -> enumerator
4613 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4614 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4616 * f = File.new('t.rus')
4617 * a = []
4618 * f.each_byte {|b| a << b }
4619 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4620 * f.close
4622 * Returns an Enumerator if no block is given.
4624 * Related: IO#each_char, IO#each_codepoint.
4628 static VALUE
4629 rb_io_each_byte(VALUE io)
4631 rb_io_t *fptr;
4633 RETURN_ENUMERATOR(io, 0, 0);
4634 GetOpenFile(io, fptr);
4636 do {
4637 while (fptr->rbuf.len > 0) {
4638 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4639 fptr->rbuf.len--;
4640 rb_yield(INT2FIX(*p & 0xff));
4641 rb_io_check_byte_readable(fptr);
4642 errno = 0;
4644 READ_CHECK(fptr);
4645 } while (io_fillbuf(fptr) >= 0);
4646 return io;
4649 static VALUE
4650 io_getc(rb_io_t *fptr, rb_encoding *enc)
4652 int r, n, cr = 0;
4653 VALUE str;
4655 if (NEED_READCONV(fptr)) {
4656 rb_encoding *read_enc = io_read_encoding(fptr);
4658 str = Qnil;
4659 SET_BINARY_MODE(fptr);
4660 make_readconv(fptr, 0);
4662 while (1) {
4663 if (fptr->cbuf.len) {
4664 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4665 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4666 read_enc);
4667 if (!MBCLEN_NEEDMORE_P(r))
4668 break;
4669 if (fptr->cbuf.len == fptr->cbuf.capa) {
4670 rb_raise(rb_eIOError, "too long character");
4674 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4675 if (fptr->cbuf.len == 0) {
4676 clear_readconv(fptr);
4677 return Qnil;
4679 /* return an unit of an incomplete character just before EOF */
4680 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4681 fptr->cbuf.off += 1;
4682 fptr->cbuf.len -= 1;
4683 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4684 ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
4685 return str;
4688 if (MBCLEN_INVALID_P(r)) {
4689 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4690 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4691 read_enc);
4692 io_shift_cbuf(fptr, r, &str);
4693 cr = ENC_CODERANGE_BROKEN;
4695 else {
4696 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4697 cr = ENC_CODERANGE_VALID;
4698 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4699 ISASCII(RSTRING_PTR(str)[0])) {
4700 cr = ENC_CODERANGE_7BIT;
4703 str = io_enc_str(str, fptr);
4704 ENC_CODERANGE_SET(str, cr);
4705 return str;
4708 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4709 if (io_fillbuf(fptr) < 0) {
4710 return Qnil;
4712 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4713 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4714 fptr->rbuf.off += 1;
4715 fptr->rbuf.len -= 1;
4716 cr = ENC_CODERANGE_7BIT;
4718 else {
4719 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4720 if (MBCLEN_CHARFOUND_P(r) &&
4721 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4722 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4723 fptr->rbuf.off += n;
4724 fptr->rbuf.len -= n;
4725 cr = ENC_CODERANGE_VALID;
4727 else if (MBCLEN_NEEDMORE_P(r)) {
4728 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4729 fptr->rbuf.len = 0;
4730 getc_needmore:
4731 if (io_fillbuf(fptr) != -1) {
4732 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4733 fptr->rbuf.off++;
4734 fptr->rbuf.len--;
4735 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4736 if (MBCLEN_NEEDMORE_P(r)) {
4737 goto getc_needmore;
4739 else if (MBCLEN_CHARFOUND_P(r)) {
4740 cr = ENC_CODERANGE_VALID;
4744 else {
4745 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4746 fptr->rbuf.off++;
4747 fptr->rbuf.len--;
4750 if (!cr) cr = ENC_CODERANGE_BROKEN;
4751 str = io_enc_str(str, fptr);
4752 ENC_CODERANGE_SET(str, cr);
4753 return str;
4757 * call-seq:
4758 * each_char {|c| ... } -> self
4759 * each_char -> enumerator
4761 * Calls the given block with each character in the stream; returns +self+.
4762 * See {Character IO}[rdoc-ref:IO@Character+IO].
4764 * f = File.new('t.rus')
4765 * a = []
4766 * f.each_char {|c| a << c.ord }
4767 * a # => [1090, 1077, 1089, 1090]
4768 * f.close
4770 * Returns an Enumerator if no block is given.
4772 * Related: IO#each_byte, IO#each_codepoint.
4776 static VALUE
4777 rb_io_each_char(VALUE io)
4779 rb_io_t *fptr;
4780 rb_encoding *enc;
4781 VALUE c;
4783 RETURN_ENUMERATOR(io, 0, 0);
4784 GetOpenFile(io, fptr);
4785 rb_io_check_char_readable(fptr);
4787 enc = io_input_encoding(fptr);
4788 READ_CHECK(fptr);
4789 while (!NIL_P(c = io_getc(fptr, enc))) {
4790 rb_yield(c);
4792 return io;
4796 * call-seq:
4797 * each_codepoint {|c| ... } -> self
4798 * each_codepoint -> enumerator
4800 * Calls the given block with each codepoint in the stream; returns +self+:
4802 * f = File.new('t.rus')
4803 * a = []
4804 * f.each_codepoint {|c| a << c }
4805 * a # => [1090, 1077, 1089, 1090]
4806 * f.close
4808 * Returns an Enumerator if no block is given.
4810 * Related: IO#each_byte, IO#each_char.
4814 static VALUE
4815 rb_io_each_codepoint(VALUE io)
4817 rb_io_t *fptr;
4818 rb_encoding *enc;
4819 unsigned int c;
4820 int r, n;
4822 RETURN_ENUMERATOR(io, 0, 0);
4823 GetOpenFile(io, fptr);
4824 rb_io_check_char_readable(fptr);
4826 READ_CHECK(fptr);
4827 if (NEED_READCONV(fptr)) {
4828 SET_BINARY_MODE(fptr);
4829 r = 1; /* no invalid char yet */
4830 for (;;) {
4831 make_readconv(fptr, 0);
4832 for (;;) {
4833 if (fptr->cbuf.len) {
4834 if (fptr->encs.enc)
4835 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4836 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4837 fptr->encs.enc);
4838 else
4839 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4840 if (!MBCLEN_NEEDMORE_P(r))
4841 break;
4842 if (fptr->cbuf.len == fptr->cbuf.capa) {
4843 rb_raise(rb_eIOError, "too long character");
4846 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4847 clear_readconv(fptr);
4848 if (!MBCLEN_CHARFOUND_P(r)) {
4849 enc = fptr->encs.enc;
4850 goto invalid;
4852 return io;
4855 if (MBCLEN_INVALID_P(r)) {
4856 enc = fptr->encs.enc;
4857 goto invalid;
4859 n = MBCLEN_CHARFOUND_LEN(r);
4860 if (fptr->encs.enc) {
4861 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4862 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4863 fptr->encs.enc);
4865 else {
4866 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4868 fptr->cbuf.off += n;
4869 fptr->cbuf.len -= n;
4870 rb_yield(UINT2NUM(c));
4871 rb_io_check_byte_readable(fptr);
4874 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4875 enc = io_input_encoding(fptr);
4876 while (io_fillbuf(fptr) >= 0) {
4877 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4878 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4879 if (MBCLEN_CHARFOUND_P(r) &&
4880 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4881 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4882 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4883 fptr->rbuf.off += n;
4884 fptr->rbuf.len -= n;
4885 rb_yield(UINT2NUM(c));
4887 else if (MBCLEN_INVALID_P(r)) {
4888 goto invalid;
4890 else if (MBCLEN_NEEDMORE_P(r)) {
4891 char cbuf[8], *p = cbuf;
4892 int more = MBCLEN_NEEDMORE_LEN(r);
4893 if (more > numberof(cbuf)) goto invalid;
4894 more += n = fptr->rbuf.len;
4895 if (more > numberof(cbuf)) goto invalid;
4896 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4897 (p += n, (more -= n) > 0)) {
4898 if (io_fillbuf(fptr) < 0) goto invalid;
4899 if ((n = fptr->rbuf.len) > more) n = more;
4901 r = rb_enc_precise_mbclen(cbuf, p, enc);
4902 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4903 c = rb_enc_codepoint(cbuf, p, enc);
4904 rb_yield(UINT2NUM(c));
4906 else {
4907 continue;
4909 rb_io_check_byte_readable(fptr);
4911 return io;
4913 invalid:
4914 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4915 UNREACHABLE_RETURN(Qundef);
4919 * call-seq:
4920 * getc -> character or nil
4922 * Reads and returns the next 1-character string from the stream;
4923 * returns +nil+ if already at end-of-stream.
4924 * See {Character IO}[rdoc-ref:IO@Character+IO].
4926 * f = File.open('t.txt')
4927 * f.getc # => "F"
4928 * f.close
4929 * f = File.open('t.rus')
4930 * f.getc.ord # => 1090
4931 * f.close
4933 * Related: IO#readchar (may raise EOFError).
4937 static VALUE
4938 rb_io_getc(VALUE io)
4940 rb_io_t *fptr;
4941 rb_encoding *enc;
4943 GetOpenFile(io, fptr);
4944 rb_io_check_char_readable(fptr);
4946 enc = io_input_encoding(fptr);
4947 READ_CHECK(fptr);
4948 return io_getc(fptr, enc);
4952 * call-seq:
4953 * readchar -> string
4955 * Reads and returns the next 1-character string from the stream;
4956 * raises EOFError if already at end-of-stream.
4957 * See {Character IO}[rdoc-ref:IO@Character+IO].
4959 * f = File.open('t.txt')
4960 * f.readchar # => "F"
4961 * f.close
4962 * f = File.open('t.rus')
4963 * f.readchar.ord # => 1090
4964 * f.close
4966 * Related: IO#getc (will not raise EOFError).
4970 static VALUE
4971 rb_io_readchar(VALUE io)
4973 VALUE c = rb_io_getc(io);
4975 if (NIL_P(c)) {
4976 rb_eof_error();
4978 return c;
4982 * call-seq:
4983 * getbyte -> integer or nil
4985 * Reads and returns the next byte (in range 0..255) from the stream;
4986 * returns +nil+ if already at end-of-stream.
4987 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4989 * f = File.open('t.txt')
4990 * f.getbyte # => 70
4991 * f.close
4992 * f = File.open('t.rus')
4993 * f.getbyte # => 209
4994 * f.close
4996 * Related: IO#readbyte (may raise EOFError).
4999 VALUE
5000 rb_io_getbyte(VALUE io)
5002 rb_io_t *fptr;
5003 int c;
5005 GetOpenFile(io, fptr);
5006 rb_io_check_byte_readable(fptr);
5007 READ_CHECK(fptr);
5008 VALUE r_stdout = rb_ractor_stdout();
5009 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5010 rb_io_t *ofp;
5011 GetOpenFile(r_stdout, ofp);
5012 if (ofp->mode & FMODE_TTY) {
5013 rb_io_flush(r_stdout);
5016 if (io_fillbuf(fptr) < 0) {
5017 return Qnil;
5019 fptr->rbuf.off++;
5020 fptr->rbuf.len--;
5021 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5022 return INT2FIX(c & 0xff);
5026 * call-seq:
5027 * readbyte -> integer
5029 * Reads and returns the next byte (in range 0..255) from the stream;
5030 * raises EOFError if already at end-of-stream.
5031 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5033 * f = File.open('t.txt')
5034 * f.readbyte # => 70
5035 * f.close
5036 * f = File.open('t.rus')
5037 * f.readbyte # => 209
5038 * f.close
5040 * Related: IO#getbyte (will not raise EOFError).
5044 static VALUE
5045 rb_io_readbyte(VALUE io)
5047 VALUE c = rb_io_getbyte(io);
5049 if (NIL_P(c)) {
5050 rb_eof_error();
5052 return c;
5056 * call-seq:
5057 * ungetbyte(integer) -> nil
5058 * ungetbyte(string) -> nil
5060 * Pushes back ("unshifts") the given data onto the stream's buffer,
5061 * placing the data so that it is next to be read; returns +nil+.
5062 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5064 * Note that:
5066 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5067 * - Calling #rewind on the stream discards the pushed-back data.
5069 * When argument +integer+ is given, uses only its low-order byte:
5071 * File.write('t.tmp', '012')
5072 * f = File.open('t.tmp')
5073 * f.ungetbyte(0x41) # => nil
5074 * f.read # => "A012"
5075 * f.rewind
5076 * f.ungetbyte(0x4243) # => nil
5077 * f.read # => "C012"
5078 * f.close
5080 * When argument +string+ is given, uses all bytes:
5082 * File.write('t.tmp', '012')
5083 * f = File.open('t.tmp')
5084 * f.ungetbyte('A') # => nil
5085 * f.read # => "A012"
5086 * f.rewind
5087 * f.ungetbyte('BCDE') # => nil
5088 * f.read # => "BCDE012"
5089 * f.close
5093 VALUE
5094 rb_io_ungetbyte(VALUE io, VALUE b)
5096 rb_io_t *fptr;
5098 GetOpenFile(io, fptr);
5099 rb_io_check_byte_readable(fptr);
5100 switch (TYPE(b)) {
5101 case T_NIL:
5102 return Qnil;
5103 case T_FIXNUM:
5104 case T_BIGNUM: ;
5105 VALUE v = rb_int_modulo(b, INT2FIX(256));
5106 unsigned char c = NUM2INT(v) & 0xFF;
5107 b = rb_str_new((const char *)&c, 1);
5108 break;
5109 default:
5110 StringValue(b);
5112 io_ungetbyte(b, fptr);
5113 return Qnil;
5117 * call-seq:
5118 * ungetc(integer) -> nil
5119 * ungetc(string) -> nil
5121 * Pushes back ("unshifts") the given data onto the stream's buffer,
5122 * placing the data so that it is next to be read; returns +nil+.
5123 * See {Character IO}[rdoc-ref:IO@Character+IO].
5125 * Note that:
5127 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5128 * - Calling #rewind on the stream discards the pushed-back data.
5130 * When argument +integer+ is given, interprets the integer as a character:
5132 * File.write('t.tmp', '012')
5133 * f = File.open('t.tmp')
5134 * f.ungetc(0x41) # => nil
5135 * f.read # => "A012"
5136 * f.rewind
5137 * f.ungetc(0x0442) # => nil
5138 * f.getc.ord # => 1090
5139 * f.close
5141 * When argument +string+ is given, uses all characters:
5143 * File.write('t.tmp', '012')
5144 * f = File.open('t.tmp')
5145 * f.ungetc('A') # => nil
5146 * f.read # => "A012"
5147 * f.rewind
5148 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5149 * f.getc.ord # => 1090
5150 * f.getc.ord # => 1077
5151 * f.getc.ord # => 1089
5152 * f.getc.ord # => 1090
5153 * f.close
5157 VALUE
5158 rb_io_ungetc(VALUE io, VALUE c)
5160 rb_io_t *fptr;
5161 long len;
5163 GetOpenFile(io, fptr);
5164 rb_io_check_char_readable(fptr);
5165 if (FIXNUM_P(c)) {
5166 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5168 else if (RB_BIGNUM_TYPE_P(c)) {
5169 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5171 else {
5172 StringValue(c);
5174 if (NEED_READCONV(fptr)) {
5175 SET_BINARY_MODE(fptr);
5176 len = RSTRING_LEN(c);
5177 #if SIZEOF_LONG > SIZEOF_INT
5178 if (len > INT_MAX)
5179 rb_raise(rb_eIOError, "ungetc failed");
5180 #endif
5181 make_readconv(fptr, (int)len);
5182 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5183 rb_raise(rb_eIOError, "ungetc failed");
5184 if (fptr->cbuf.off < len) {
5185 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5186 fptr->cbuf.ptr+fptr->cbuf.off,
5187 char, fptr->cbuf.len);
5188 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5190 fptr->cbuf.off -= (int)len;
5191 fptr->cbuf.len += (int)len;
5192 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5194 else {
5195 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5196 io_ungetbyte(c, fptr);
5198 return Qnil;
5202 * call-seq:
5203 * isatty -> true or false
5205 * Returns +true+ if the stream is associated with a terminal device (tty),
5206 * +false+ otherwise:
5208 * f = File.new('t.txt').isatty #=> false
5209 * f.close
5210 * f = File.new('/dev/tty').isatty #=> true
5211 * f.close
5215 static VALUE
5216 rb_io_isatty(VALUE io)
5218 rb_io_t *fptr;
5220 GetOpenFile(io, fptr);
5221 return RBOOL(isatty(fptr->fd) != 0);
5224 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5226 * call-seq:
5227 * close_on_exec? -> true or false
5229 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5231 * f = File.open('t.txt')
5232 * f.close_on_exec? # => true
5233 * f.close_on_exec = false
5234 * f.close_on_exec? # => false
5235 * f.close
5239 static VALUE
5240 rb_io_close_on_exec_p(VALUE io)
5242 rb_io_t *fptr;
5243 VALUE write_io;
5244 int fd, ret;
5246 write_io = GetWriteIO(io);
5247 if (io != write_io) {
5248 GetOpenFile(write_io, fptr);
5249 if (fptr && 0 <= (fd = fptr->fd)) {
5250 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5251 if (!(ret & FD_CLOEXEC)) return Qfalse;
5255 GetOpenFile(io, fptr);
5256 if (fptr && 0 <= (fd = fptr->fd)) {
5257 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5258 if (!(ret & FD_CLOEXEC)) return Qfalse;
5260 return Qtrue;
5262 #else
5263 #define rb_io_close_on_exec_p rb_f_notimplement
5264 #endif
5266 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5268 * call-seq:
5269 * self.close_on_exec = bool -> true or false
5271 * Sets a close-on-exec flag.
5273 * f = File.open(File::NULL)
5274 * f.close_on_exec = true
5275 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5276 * f.closed? #=> false
5278 * Ruby sets close-on-exec flags of all file descriptors by default
5279 * since Ruby 2.0.0.
5280 * So you don't need to set by yourself.
5281 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5282 * if another thread use fork() and exec() (via system() method for example).
5283 * If you really needs file descriptor inheritance to child process,
5284 * use spawn()'s argument such as fd=>fd.
5287 static VALUE
5288 rb_io_set_close_on_exec(VALUE io, VALUE arg)
5290 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5291 rb_io_t *fptr;
5292 VALUE write_io;
5293 int fd, ret;
5295 write_io = GetWriteIO(io);
5296 if (io != write_io) {
5297 GetOpenFile(write_io, fptr);
5298 if (fptr && 0 <= (fd = fptr->fd)) {
5299 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5300 if ((ret & FD_CLOEXEC) != flag) {
5301 ret = (ret & ~FD_CLOEXEC) | flag;
5302 ret = fcntl(fd, F_SETFD, ret);
5303 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5309 GetOpenFile(io, fptr);
5310 if (fptr && 0 <= (fd = fptr->fd)) {
5311 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5312 if ((ret & FD_CLOEXEC) != flag) {
5313 ret = (ret & ~FD_CLOEXEC) | flag;
5314 ret = fcntl(fd, F_SETFD, ret);
5315 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5318 return Qnil;
5320 #else
5321 #define rb_io_set_close_on_exec rb_f_notimplement
5322 #endif
5324 #define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5325 #define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5327 static VALUE
5328 finish_writeconv(rb_io_t *fptr, int noalloc)
5330 unsigned char *ds, *dp, *de;
5331 rb_econv_result_t res;
5333 if (!fptr->wbuf.ptr) {
5334 unsigned char buf[1024];
5336 res = econv_destination_buffer_full;
5337 while (res == econv_destination_buffer_full) {
5338 ds = dp = buf;
5339 de = buf + sizeof(buf);
5340 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5341 while (dp-ds) {
5342 size_t remaining = dp-ds;
5343 long result = rb_io_write_memory(fptr, ds, remaining);
5345 if (result > 0) {
5346 ds += result;
5347 if ((size_t)result == remaining) break;
5349 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5350 if (fptr->fd < 0)
5351 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5353 else {
5354 return noalloc ? Qtrue : INT2NUM(errno);
5357 if (res == econv_invalid_byte_sequence ||
5358 res == econv_incomplete_input ||
5359 res == econv_undefined_conversion) {
5360 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5364 return Qnil;
5367 res = econv_destination_buffer_full;
5368 while (res == econv_destination_buffer_full) {
5369 if (fptr->wbuf.len == fptr->wbuf.capa) {
5370 if (io_fflush(fptr) < 0) {
5371 return noalloc ? Qtrue : INT2NUM(errno);
5375 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5376 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5377 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5378 fptr->wbuf.len += (int)(dp - ds);
5379 if (res == econv_invalid_byte_sequence ||
5380 res == econv_incomplete_input ||
5381 res == econv_undefined_conversion) {
5382 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5385 return Qnil;
5388 struct finish_writeconv_arg {
5389 rb_io_t *fptr;
5390 int noalloc;
5393 static VALUE
5394 finish_writeconv_sync(VALUE arg)
5396 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5397 return finish_writeconv(p->fptr, p->noalloc);
5400 static void*
5401 nogvl_close(void *ptr)
5403 int *fd = ptr;
5405 return (void*)(intptr_t)close(*fd);
5408 static int
5409 maygvl_close(int fd, int keepgvl)
5411 if (keepgvl)
5412 return close(fd);
5415 * close() may block for certain file types (NFS, SO_LINGER sockets,
5416 * inotify), so let other threads run.
5418 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5421 static void*
5422 nogvl_fclose(void *ptr)
5424 FILE *file = ptr;
5426 return (void*)(intptr_t)fclose(file);
5429 static int
5430 maygvl_fclose(FILE *file, int keepgvl)
5432 if (keepgvl)
5433 return fclose(file);
5435 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5438 static void free_io_buffer(rb_io_buffer_t *buf);
5439 static void clear_codeconv(rb_io_t *fptr);
5441 static void
5442 fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5443 struct rb_io_close_wait_list *busy)
5445 VALUE error = Qnil;
5446 int fd = fptr->fd;
5447 FILE *stdio_file = fptr->stdio_file;
5448 int mode = fptr->mode;
5450 if (fptr->writeconv) {
5451 if (!NIL_P(fptr->write_lock) && !noraise) {
5452 struct finish_writeconv_arg arg;
5453 arg.fptr = fptr;
5454 arg.noalloc = noraise;
5455 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5457 else {
5458 error = finish_writeconv(fptr, noraise);
5461 if (fptr->wbuf.len) {
5462 if (noraise) {
5463 io_flush_buffer_sync(fptr);
5465 else {
5466 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5467 error = INT2NUM(errno);
5472 int done = 0;
5474 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5475 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5476 done = 1;
5479 fptr->fd = -1;
5480 fptr->stdio_file = 0;
5481 fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
5483 // Ensure waiting_fd users do not hit EBADF.
5484 if (busy) {
5485 // Wait for them to exit before we call close().
5486 rb_notify_fd_close_wait(busy);
5489 // Disable for now.
5490 // if (!done && fd >= 0) {
5491 // VALUE scheduler = rb_fiber_scheduler_current();
5492 // if (scheduler != Qnil) {
5493 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5494 // if (!UNDEF_P(result)) done = 1;
5495 // }
5496 // }
5498 if (!done && stdio_file) {
5499 // stdio_file is deallocated anyway even if fclose failed.
5500 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5501 if (!noraise) {
5502 error = INT2NUM(errno);
5506 done = 1;
5509 if (!done && fd >= 0) {
5510 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5511 // We assumes it is closed.
5513 keepgvl |= !(mode & FMODE_WRITABLE);
5514 keepgvl |= noraise;
5515 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5516 if (!noraise) {
5517 error = INT2NUM(errno);
5521 done = 1;
5524 if (!NIL_P(error) && !noraise) {
5525 if (RB_INTEGER_TYPE_P(error))
5526 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5527 else
5528 rb_exc_raise(error);
5532 static void
5533 fptr_finalize(rb_io_t *fptr, int noraise)
5535 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5536 free_io_buffer(&fptr->rbuf);
5537 free_io_buffer(&fptr->wbuf);
5538 clear_codeconv(fptr);
5541 static void
5542 rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5544 if (fptr->finalize) {
5545 (*fptr->finalize)(fptr, noraise);
5547 else {
5548 fptr_finalize(fptr, noraise);
5552 static void
5553 free_io_buffer(rb_io_buffer_t *buf)
5555 if (buf->ptr) {
5556 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5557 buf->ptr = NULL;
5561 static void
5562 clear_readconv(rb_io_t *fptr)
5564 if (fptr->readconv) {
5565 rb_econv_close(fptr->readconv);
5566 fptr->readconv = NULL;
5568 free_io_buffer(&fptr->cbuf);
5571 static void
5572 clear_writeconv(rb_io_t *fptr)
5574 if (fptr->writeconv) {
5575 rb_econv_close(fptr->writeconv);
5576 fptr->writeconv = NULL;
5578 fptr->writeconv_initialized = 0;
5581 static void
5582 clear_codeconv(rb_io_t *fptr)
5584 clear_readconv(fptr);
5585 clear_writeconv(fptr);
5588 static void
5589 rb_io_fptr_cleanup_all(rb_io_t *fptr)
5591 fptr->pathv = Qnil;
5592 if (0 <= fptr->fd)
5593 rb_io_fptr_cleanup(fptr, TRUE);
5594 fptr->write_lock = Qnil;
5595 free_io_buffer(&fptr->rbuf);
5596 free_io_buffer(&fptr->wbuf);
5597 clear_codeconv(fptr);
5600 void
5601 rb_io_fptr_finalize_internal(void *ptr)
5603 if (!ptr) return;
5604 rb_io_fptr_cleanup_all(ptr);
5605 free(ptr);
5608 #undef rb_io_fptr_finalize
5610 rb_io_fptr_finalize(rb_io_t *fptr)
5612 if (!fptr) {
5613 return 0;
5615 else {
5616 rb_io_fptr_finalize_internal(fptr);
5617 return 1;
5620 #define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5622 size_t
5623 rb_io_memsize(const rb_io_t *fptr)
5625 size_t size = sizeof(rb_io_t);
5626 size += fptr->rbuf.capa;
5627 size += fptr->wbuf.capa;
5628 size += fptr->cbuf.capa;
5629 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5630 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5631 return size;
5634 #ifdef _WIN32
5635 /* keep GVL while closing to prevent crash on Windows */
5636 # define KEEPGVL TRUE
5637 #else
5638 # define KEEPGVL FALSE
5639 #endif
5641 static rb_io_t *
5642 io_close_fptr(VALUE io)
5644 rb_io_t *fptr;
5645 VALUE write_io;
5646 rb_io_t *write_fptr;
5647 struct rb_io_close_wait_list busy;
5649 write_io = GetWriteIO(io);
5650 if (io != write_io) {
5651 write_fptr = RFILE(write_io)->fptr;
5652 if (write_fptr && 0 <= write_fptr->fd) {
5653 rb_io_fptr_cleanup(write_fptr, TRUE);
5657 fptr = RFILE(io)->fptr;
5658 if (!fptr) return 0;
5659 if (fptr->fd < 0) return 0;
5661 if (rb_notify_fd_close(fptr->fd, &busy)) {
5662 /* calls close(fptr->fd): */
5663 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5665 rb_io_fptr_cleanup(fptr, FALSE);
5666 return fptr;
5669 static void
5670 fptr_waitpid(rb_io_t *fptr, int nohang)
5672 int status;
5673 if (fptr->pid) {
5674 rb_last_status_clear();
5675 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5676 fptr->pid = 0;
5680 VALUE
5681 rb_io_close(VALUE io)
5683 rb_io_t *fptr = io_close_fptr(io);
5684 if (fptr) fptr_waitpid(fptr, 0);
5685 return Qnil;
5689 * call-seq:
5690 * close -> nil
5692 * Closes the stream for both reading and writing
5693 * if open for either or both; returns +nil+.
5694 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5696 * If the stream is open for writing, flushes any buffered writes
5697 * to the operating system before closing.
5699 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5700 * (child exit status).
5702 * Example:
5704 * IO.popen('ruby', 'r+') do |pipe|
5705 * puts pipe.closed?
5706 * pipe.close
5707 * puts $?
5708 * puts pipe.closed?
5709 * end
5711 * Output:
5713 * false
5714 * pid 13760 exit 0
5715 * true
5717 * Related: IO#close_read, IO#close_write, IO#closed?.
5720 static VALUE
5721 rb_io_close_m(VALUE io)
5723 rb_io_t *fptr = rb_io_get_fptr(io);
5724 if (fptr->fd < 0) {
5725 return Qnil;
5727 rb_io_close(io);
5728 return Qnil;
5731 static VALUE
5732 io_call_close(VALUE io)
5734 rb_check_funcall(io, rb_intern("close"), 0, 0);
5735 return io;
5738 static VALUE
5739 ignore_closed_stream(VALUE io, VALUE exc)
5741 enum {mesg_len = sizeof(closed_stream)-1};
5742 VALUE mesg = rb_attr_get(exc, idMesg);
5743 if (!RB_TYPE_P(mesg, T_STRING) ||
5744 RSTRING_LEN(mesg) != mesg_len ||
5745 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5746 rb_exc_raise(exc);
5748 return io;
5751 static VALUE
5752 io_close(VALUE io)
5754 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5755 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5756 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5757 rb_eIOError, (VALUE)0);
5758 return io;
5762 * call-seq:
5763 * closed? -> true or false
5765 * Returns +true+ if the stream is closed for both reading and writing,
5766 * +false+ otherwise.
5767 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5769 * IO.popen('ruby', 'r+') do |pipe|
5770 * puts pipe.closed?
5771 * pipe.close_read
5772 * puts pipe.closed?
5773 * pipe.close_write
5774 * puts pipe.closed?
5775 * end
5777 * Output:
5779 * false
5780 * false
5781 * true
5783 * Related: IO#close_read, IO#close_write, IO#close.
5785 VALUE
5786 rb_io_closed_p(VALUE io)
5788 rb_io_t *fptr;
5789 VALUE write_io;
5790 rb_io_t *write_fptr;
5792 write_io = GetWriteIO(io);
5793 if (io != write_io) {
5794 write_fptr = RFILE(write_io)->fptr;
5795 if (write_fptr && 0 <= write_fptr->fd) {
5796 return Qfalse;
5800 fptr = rb_io_get_fptr(io);
5801 return RBOOL(0 > fptr->fd);
5805 * call-seq:
5806 * close_read -> nil
5808 * Closes the stream for reading if open for reading;
5809 * returns +nil+.
5810 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5812 * If the stream was opened by IO.popen and is also closed for writing,
5813 * sets global variable <tt>$?</tt> (child exit status).
5815 * Example:
5817 * IO.popen('ruby', 'r+') do |pipe|
5818 * puts pipe.closed?
5819 * pipe.close_write
5820 * puts pipe.closed?
5821 * pipe.close_read
5822 * puts $?
5823 * puts pipe.closed?
5824 * end
5826 * Output:
5828 * false
5829 * false
5830 * pid 14748 exit 0
5831 * true
5833 * Related: IO#close, IO#close_write, IO#closed?.
5836 static VALUE
5837 rb_io_close_read(VALUE io)
5839 rb_io_t *fptr;
5840 VALUE write_io;
5842 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5843 if (fptr->fd < 0) return Qnil;
5844 if (is_socket(fptr->fd, fptr->pathv)) {
5845 #ifndef SHUT_RD
5846 # define SHUT_RD 0
5847 #endif
5848 if (shutdown(fptr->fd, SHUT_RD) < 0)
5849 rb_sys_fail_path(fptr->pathv);
5850 fptr->mode &= ~FMODE_READABLE;
5851 if (!(fptr->mode & FMODE_WRITABLE))
5852 return rb_io_close(io);
5853 return Qnil;
5856 write_io = GetWriteIO(io);
5857 if (io != write_io) {
5858 rb_io_t *wfptr;
5859 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5860 wfptr->pid = fptr->pid;
5861 fptr->pid = 0;
5862 RFILE(io)->fptr = wfptr;
5863 /* bind to write_io temporarily to get rid of memory/fd leak */
5864 fptr->tied_io_for_writing = 0;
5865 RFILE(write_io)->fptr = fptr;
5866 rb_io_fptr_cleanup(fptr, FALSE);
5867 /* should not finalize fptr because another thread may be reading it */
5868 return Qnil;
5871 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5872 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5874 return rb_io_close(io);
5878 * call-seq:
5879 * close_write -> nil
5881 * Closes the stream for writing if open for writing;
5882 * returns +nil+.
5883 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5885 * Flushes any buffered writes to the operating system before closing.
5887 * If the stream was opened by IO.popen and is also closed for reading,
5888 * sets global variable <tt>$?</tt> (child exit status).
5890 * IO.popen('ruby', 'r+') do |pipe|
5891 * puts pipe.closed?
5892 * pipe.close_read
5893 * puts pipe.closed?
5894 * pipe.close_write
5895 * puts $?
5896 * puts pipe.closed?
5897 * end
5899 * Output:
5901 * false
5902 * false
5903 * pid 15044 exit 0
5904 * true
5906 * Related: IO#close, IO#close_read, IO#closed?.
5909 static VALUE
5910 rb_io_close_write(VALUE io)
5912 rb_io_t *fptr;
5913 VALUE write_io;
5915 write_io = GetWriteIO(io);
5916 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5917 if (fptr->fd < 0) return Qnil;
5918 if (is_socket(fptr->fd, fptr->pathv)) {
5919 #ifndef SHUT_WR
5920 # define SHUT_WR 1
5921 #endif
5922 if (shutdown(fptr->fd, SHUT_WR) < 0)
5923 rb_sys_fail_path(fptr->pathv);
5924 fptr->mode &= ~FMODE_WRITABLE;
5925 if (!(fptr->mode & FMODE_READABLE))
5926 return rb_io_close(write_io);
5927 return Qnil;
5930 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
5931 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
5934 if (io != write_io) {
5935 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5936 fptr->tied_io_for_writing = 0;
5938 rb_io_close(write_io);
5939 return Qnil;
5943 * call-seq:
5944 * sysseek(offset, whence = IO::SEEK_SET) -> integer
5946 * Behaves like IO#seek, except that it:
5948 * - Uses low-level system functions.
5949 * - Returns the new position.
5953 static VALUE
5954 rb_io_sysseek(int argc, VALUE *argv, VALUE io)
5956 VALUE offset, ptrname;
5957 int whence = SEEK_SET;
5958 rb_io_t *fptr;
5959 rb_off_t pos;
5961 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
5962 whence = interpret_seek_whence(ptrname);
5964 pos = NUM2OFFT(offset);
5965 GetOpenFile(io, fptr);
5966 if ((fptr->mode & FMODE_READABLE) &&
5967 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5968 rb_raise(rb_eIOError, "sysseek for buffered IO");
5970 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
5971 rb_warn("sysseek for buffered IO");
5973 errno = 0;
5974 pos = lseek(fptr->fd, pos, whence);
5975 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
5977 return OFFT2NUM(pos);
5981 * call-seq:
5982 * syswrite(object) -> integer
5984 * Writes the given +object+ to self, which must be opened for writing (see Modes);
5985 * returns the number bytes written.
5986 * If +object+ is not a string is converted via method to_s:
5988 * f = File.new('t.tmp', 'w')
5989 * f.syswrite('foo') # => 3
5990 * f.syswrite(30) # => 2
5991 * f.syswrite(:foo) # => 3
5992 * f.close
5994 * This methods should not be used with other stream-writer methods.
5998 static VALUE
5999 rb_io_syswrite(VALUE io, VALUE str)
6001 VALUE tmp;
6002 rb_io_t *fptr;
6003 long n, len;
6004 const char *ptr;
6006 if (!RB_TYPE_P(str, T_STRING))
6007 str = rb_obj_as_string(str);
6009 io = GetWriteIO(io);
6010 GetOpenFile(io, fptr);
6011 rb_io_check_writable(fptr);
6013 if (fptr->wbuf.len) {
6014 rb_warn("syswrite for buffered IO");
6017 tmp = rb_str_tmp_frozen_acquire(str);
6018 RSTRING_GETMEM(tmp, ptr, len);
6019 n = rb_io_write_memory(fptr, ptr, len);
6020 if (n < 0) rb_sys_fail_path(fptr->pathv);
6021 rb_str_tmp_frozen_release(str, tmp);
6023 return LONG2FIX(n);
6027 * call-seq:
6028 * sysread(maxlen) -> string
6029 * sysread(maxlen, out_string) -> string
6031 * Behaves like IO#readpartial, except that it uses low-level system functions.
6033 * This method should not be used with other stream-reader methods.
6037 static VALUE
6038 rb_io_sysread(int argc, VALUE *argv, VALUE io)
6040 VALUE len, str;
6041 rb_io_t *fptr;
6042 long n, ilen;
6043 struct io_internal_read_struct iis;
6044 int shrinkable;
6046 rb_scan_args(argc, argv, "11", &len, &str);
6047 ilen = NUM2LONG(len);
6049 shrinkable = io_setstrbuf(&str, ilen);
6050 if (ilen == 0) return str;
6052 GetOpenFile(io, fptr);
6053 rb_io_check_byte_readable(fptr);
6055 if (READ_DATA_BUFFERED(fptr)) {
6056 rb_raise(rb_eIOError, "sysread for buffered IO");
6059 rb_io_check_closed(fptr);
6061 io_setstrbuf(&str, ilen);
6062 iis.th = rb_thread_current();
6063 iis.fptr = fptr;
6064 iis.nonblock = 0;
6065 iis.fd = fptr->fd;
6066 iis.buf = RSTRING_PTR(str);
6067 iis.capa = ilen;
6068 iis.timeout = NULL;
6069 n = io_read_memory_locktmp(str, &iis);
6071 if (n < 0) {
6072 rb_sys_fail_path(fptr->pathv);
6075 io_set_read_length(str, n, shrinkable);
6077 if (n == 0 && ilen > 0) {
6078 rb_eof_error();
6081 return str;
6084 struct prdwr_internal_arg {
6085 VALUE io;
6086 int fd;
6087 void *buf;
6088 size_t count;
6089 rb_off_t offset;
6092 static VALUE
6093 internal_pread_func(void *_arg)
6095 struct prdwr_internal_arg *arg = _arg;
6097 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6100 static VALUE
6101 pread_internal_call(VALUE _arg)
6103 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6105 VALUE scheduler = rb_fiber_scheduler_current();
6106 if (scheduler != Qnil) {
6107 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io, arg->offset, arg->buf, arg->count, 0);
6109 if (!UNDEF_P(result)) {
6110 return rb_fiber_scheduler_io_result_apply(result);
6114 return rb_thread_io_blocking_call(internal_pread_func, arg, arg->fd, RB_WAITFD_IN);
6118 * call-seq:
6119 * pread(maxlen, offset) -> string
6120 * pread(maxlen, offset, out_string) -> string
6122 * Behaves like IO#readpartial, except that it:
6124 * - Reads at the given +offset+ (in bytes).
6125 * - Disregards, and does not modify, the stream's position
6126 * (see {Position}[rdoc-ref:IO@Position]).
6127 * - Bypasses any user space buffering in the stream.
6129 * Because this method does not disturb the stream's state
6130 * (its position, in particular), +pread+ allows multiple threads and processes
6131 * to use the same \IO object for reading at various offsets.
6133 * f = File.open('t.txt')
6134 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6135 * f.pos # => 52
6136 * # Read 12 bytes at offset 0.
6137 * f.pread(12, 0) # => "First line\n"
6138 * # Read 9 bytes at offset 8.
6139 * f.pread(9, 8) # => "ne\nSecon"
6140 * f.close
6142 * Not available on some platforms.
6145 static VALUE
6146 rb_io_pread(int argc, VALUE *argv, VALUE io)
6148 VALUE len, offset, str;
6149 rb_io_t *fptr;
6150 ssize_t n;
6151 struct prdwr_internal_arg arg = {.io = io};
6152 int shrinkable;
6154 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6155 arg.count = NUM2SIZET(len);
6156 arg.offset = NUM2OFFT(offset);
6158 shrinkable = io_setstrbuf(&str, (long)arg.count);
6159 if (arg.count == 0) return str;
6160 arg.buf = RSTRING_PTR(str);
6162 GetOpenFile(io, fptr);
6163 rb_io_check_byte_readable(fptr);
6165 arg.fd = fptr->fd;
6166 rb_io_check_closed(fptr);
6168 rb_str_locktmp(str);
6169 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6171 if (n < 0) {
6172 rb_sys_fail_path(fptr->pathv);
6174 io_set_read_length(str, n, shrinkable);
6175 if (n == 0 && arg.count > 0) {
6176 rb_eof_error();
6179 return str;
6182 static VALUE
6183 internal_pwrite_func(void *_arg)
6185 struct prdwr_internal_arg *arg = _arg;
6187 VALUE scheduler = rb_fiber_scheduler_current();
6188 if (scheduler != Qnil) {
6189 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io, arg->offset, arg->buf, arg->count, 0);
6191 if (!UNDEF_P(result)) {
6192 return rb_fiber_scheduler_io_result_apply(result);
6197 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6201 * call-seq:
6202 * pwrite(object, offset) -> integer
6204 * Behaves like IO#write, except that it:
6206 * - Writes at the given +offset+ (in bytes).
6207 * - Disregards, and does not modify, the stream's position
6208 * (see {Position}[rdoc-ref:IO@Position]).
6209 * - Bypasses any user space buffering in the stream.
6211 * Because this method does not disturb the stream's state
6212 * (its position, in particular), +pwrite+ allows multiple threads and processes
6213 * to use the same \IO object for writing at various offsets.
6215 * f = File.open('t.tmp', 'w+')
6216 * # Write 6 bytes at offset 3.
6217 * f.pwrite('ABCDEF', 3) # => 6
6218 * f.rewind
6219 * f.read # => "\u0000\u0000\u0000ABCDEF"
6220 * f.close
6222 * Not available on some platforms.
6225 static VALUE
6226 rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6228 rb_io_t *fptr;
6229 ssize_t n;
6230 struct prdwr_internal_arg arg = {.io = io};
6231 VALUE tmp;
6233 if (!RB_TYPE_P(str, T_STRING))
6234 str = rb_obj_as_string(str);
6236 arg.offset = NUM2OFFT(offset);
6238 io = GetWriteIO(io);
6239 GetOpenFile(io, fptr);
6240 rb_io_check_writable(fptr);
6241 arg.fd = fptr->fd;
6243 tmp = rb_str_tmp_frozen_acquire(str);
6244 arg.buf = RSTRING_PTR(tmp);
6245 arg.count = (size_t)RSTRING_LEN(tmp);
6247 n = (ssize_t)rb_thread_io_blocking_call(internal_pwrite_func, &arg, fptr->fd, RB_WAITFD_OUT);
6248 if (n < 0) rb_sys_fail_path(fptr->pathv);
6249 rb_str_tmp_frozen_release(str, tmp);
6251 return SSIZET2NUM(n);
6254 VALUE
6255 rb_io_binmode(VALUE io)
6257 rb_io_t *fptr;
6259 GetOpenFile(io, fptr);
6260 if (fptr->readconv)
6261 rb_econv_binmode(fptr->readconv);
6262 if (fptr->writeconv)
6263 rb_econv_binmode(fptr->writeconv);
6264 fptr->mode |= FMODE_BINMODE;
6265 fptr->mode &= ~FMODE_TEXTMODE;
6266 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6267 #ifdef O_BINARY
6268 if (!fptr->readconv) {
6269 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6271 else {
6272 setmode(fptr->fd, O_BINARY);
6274 #endif
6275 return io;
6278 static void
6279 io_ascii8bit_binmode(rb_io_t *fptr)
6281 if (fptr->readconv) {
6282 rb_econv_close(fptr->readconv);
6283 fptr->readconv = NULL;
6285 if (fptr->writeconv) {
6286 rb_econv_close(fptr->writeconv);
6287 fptr->writeconv = NULL;
6289 fptr->mode |= FMODE_BINMODE;
6290 fptr->mode &= ~FMODE_TEXTMODE;
6291 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6293 fptr->encs.enc = rb_ascii8bit_encoding();
6294 fptr->encs.enc2 = NULL;
6295 fptr->encs.ecflags = 0;
6296 fptr->encs.ecopts = Qnil;
6297 clear_codeconv(fptr);
6300 VALUE
6301 rb_io_ascii8bit_binmode(VALUE io)
6303 rb_io_t *fptr;
6305 GetOpenFile(io, fptr);
6306 io_ascii8bit_binmode(fptr);
6308 return io;
6312 * call-seq:
6313 * binmode -> self
6315 * Sets the stream's data mode as binary
6316 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6318 * A stream's data mode may not be changed from binary to text.
6322 static VALUE
6323 rb_io_binmode_m(VALUE io)
6325 VALUE write_io;
6327 rb_io_ascii8bit_binmode(io);
6329 write_io = GetWriteIO(io);
6330 if (write_io != io)
6331 rb_io_ascii8bit_binmode(write_io);
6332 return io;
6336 * call-seq:
6337 * binmode? -> true or false
6339 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6340 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6343 static VALUE
6344 rb_io_binmode_p(VALUE io)
6346 rb_io_t *fptr;
6347 GetOpenFile(io, fptr);
6348 return RBOOL(fptr->mode & FMODE_BINMODE);
6351 static const char*
6352 rb_io_fmode_modestr(int fmode)
6354 if (fmode & FMODE_APPEND) {
6355 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6356 return MODE_BTMODE("a+", "ab+", "at+");
6358 return MODE_BTMODE("a", "ab", "at");
6360 switch (fmode & FMODE_READWRITE) {
6361 default:
6362 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6363 case FMODE_READABLE:
6364 return MODE_BTMODE("r", "rb", "rt");
6365 case FMODE_WRITABLE:
6366 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6367 case FMODE_READWRITE:
6368 if (fmode & FMODE_CREATE) {
6369 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6371 return MODE_BTMODE("r+", "rb+", "rt+");
6375 static const char bom_prefix[] = "bom|";
6376 static const char utf_prefix[] = "utf-";
6377 enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6378 enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6380 static int
6381 io_encname_bom_p(const char *name, long len)
6383 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6387 rb_io_modestr_fmode(const char *modestr)
6389 int fmode = 0;
6390 const char *m = modestr, *p = NULL;
6392 switch (*m++) {
6393 case 'r':
6394 fmode |= FMODE_READABLE;
6395 break;
6396 case 'w':
6397 fmode |= FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE;
6398 break;
6399 case 'a':
6400 fmode |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
6401 break;
6402 default:
6403 goto error;
6406 while (*m) {
6407 switch (*m++) {
6408 case 'b':
6409 fmode |= FMODE_BINMODE;
6410 break;
6411 case 't':
6412 fmode |= FMODE_TEXTMODE;
6413 break;
6414 case '+':
6415 fmode |= FMODE_READWRITE;
6416 break;
6417 case 'x':
6418 if (modestr[0] != 'w')
6419 goto error;
6420 fmode |= FMODE_EXCL;
6421 break;
6422 default:
6423 goto error;
6424 case ':':
6425 p = strchr(m, ':');
6426 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6427 fmode |= FMODE_SETENC_BY_BOM;
6428 goto finished;
6432 finished:
6433 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6434 goto error;
6436 return fmode;
6438 error:
6439 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6440 UNREACHABLE_RETURN(Qundef);
6444 rb_io_oflags_fmode(int oflags)
6446 int fmode = 0;
6448 switch (oflags & O_ACCMODE) {
6449 case O_RDONLY:
6450 fmode = FMODE_READABLE;
6451 break;
6452 case O_WRONLY:
6453 fmode = FMODE_WRITABLE;
6454 break;
6455 case O_RDWR:
6456 fmode = FMODE_READWRITE;
6457 break;
6460 if (oflags & O_APPEND) {
6461 fmode |= FMODE_APPEND;
6463 if (oflags & O_TRUNC) {
6464 fmode |= FMODE_TRUNC;
6466 if (oflags & O_CREAT) {
6467 fmode |= FMODE_CREATE;
6469 if (oflags & O_EXCL) {
6470 fmode |= FMODE_EXCL;
6472 #ifdef O_BINARY
6473 if (oflags & O_BINARY) {
6474 fmode |= FMODE_BINMODE;
6476 #endif
6478 return fmode;
6481 static int
6482 rb_io_fmode_oflags(int fmode)
6484 int oflags = 0;
6486 switch (fmode & FMODE_READWRITE) {
6487 case FMODE_READABLE:
6488 oflags |= O_RDONLY;
6489 break;
6490 case FMODE_WRITABLE:
6491 oflags |= O_WRONLY;
6492 break;
6493 case FMODE_READWRITE:
6494 oflags |= O_RDWR;
6495 break;
6498 if (fmode & FMODE_APPEND) {
6499 oflags |= O_APPEND;
6501 if (fmode & FMODE_TRUNC) {
6502 oflags |= O_TRUNC;
6504 if (fmode & FMODE_CREATE) {
6505 oflags |= O_CREAT;
6507 if (fmode & FMODE_EXCL) {
6508 oflags |= O_EXCL;
6510 #ifdef O_BINARY
6511 if (fmode & FMODE_BINMODE) {
6512 oflags |= O_BINARY;
6514 #endif
6516 return oflags;
6520 rb_io_modestr_oflags(const char *modestr)
6522 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6525 static const char*
6526 rb_io_oflags_modestr(int oflags)
6528 #ifdef O_BINARY
6529 # define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6530 #else
6531 # define MODE_BINARY(a,b) (a)
6532 #endif
6533 int accmode;
6534 if (oflags & O_EXCL) {
6535 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6537 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6538 if (oflags & O_APPEND) {
6539 if (accmode == O_WRONLY) {
6540 return MODE_BINARY("a", "ab");
6542 if (accmode == O_RDWR) {
6543 return MODE_BINARY("a+", "ab+");
6546 switch (accmode) {
6547 default:
6548 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6549 case O_RDONLY:
6550 return MODE_BINARY("r", "rb");
6551 case O_WRONLY:
6552 return MODE_BINARY("w", "wb");
6553 case O_RDWR:
6554 if (oflags & O_TRUNC) {
6555 return MODE_BINARY("w+", "wb+");
6557 return MODE_BINARY("r+", "rb+");
6562 * Convert external/internal encodings to enc/enc2
6563 * NULL => use default encoding
6564 * Qnil => no encoding specified (internal only)
6566 static void
6567 rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6569 int default_ext = 0;
6571 if (ext == NULL) {
6572 ext = rb_default_external_encoding();
6573 default_ext = 1;
6575 if (rb_is_ascii8bit_enc(ext)) {
6576 /* If external is ASCII-8BIT, no transcoding */
6577 intern = NULL;
6579 else if (intern == NULL) {
6580 intern = rb_default_internal_encoding();
6582 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6583 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6584 /* No internal encoding => use external + no transcoding */
6585 *enc = (default_ext && intern != ext) ? NULL : ext;
6586 *enc2 = NULL;
6588 else {
6589 *enc = intern;
6590 *enc2 = ext;
6594 static void
6595 unsupported_encoding(const char *name, rb_encoding *enc)
6597 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6600 static void
6601 parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6602 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6604 const char *p;
6605 char encname[ENCODING_MAXNAMELEN+1];
6606 int idx, idx2;
6607 int fmode = fmode_p ? *fmode_p : 0;
6608 rb_encoding *ext_enc, *int_enc;
6609 long len;
6611 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6613 p = strrchr(estr, ':');
6614 len = p ? (p++ - estr) : (long)strlen(estr);
6615 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6616 estr += bom_prefix_len;
6617 len -= bom_prefix_len;
6618 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6619 fmode |= FMODE_SETENC_BY_BOM;
6621 else {
6622 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6623 fmode &= ~FMODE_SETENC_BY_BOM;
6626 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6627 idx = -1;
6629 else {
6630 if (p) {
6631 memcpy(encname, estr, len);
6632 encname[len] = '\0';
6633 estr = encname;
6635 idx = rb_enc_find_index(estr);
6637 if (fmode_p) *fmode_p = fmode;
6639 if (idx >= 0)
6640 ext_enc = rb_enc_from_index(idx);
6641 else {
6642 if (idx != -2)
6643 unsupported_encoding(estr, estr_enc);
6644 ext_enc = NULL;
6647 int_enc = NULL;
6648 if (p) {
6649 if (*p == '-' && *(p+1) == '\0') {
6650 /* Special case - "-" => no transcoding */
6651 int_enc = (rb_encoding *)Qnil;
6653 else {
6654 idx2 = rb_enc_find_index(p);
6655 if (idx2 < 0)
6656 unsupported_encoding(p, estr_enc);
6657 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6658 int_enc = (rb_encoding *)Qnil;
6660 else
6661 int_enc = rb_enc_from_index(idx2);
6665 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6669 rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6671 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6672 int extracted = 0;
6673 rb_encoding *extencoding = NULL;
6674 rb_encoding *intencoding = NULL;
6676 if (!NIL_P(opt)) {
6677 VALUE v;
6678 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6679 if (v != Qnil) encoding = v;
6680 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6681 if (v != Qnil) extenc = v;
6682 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6683 if (!UNDEF_P(v)) intenc = v;
6685 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6686 if (!NIL_P(ruby_verbose)) {
6687 int idx = rb_to_encoding_index(encoding);
6688 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6689 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6690 encoding, UNDEF_P(extenc) ? "internal" : "external");
6692 encoding = Qnil;
6694 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6695 extencoding = rb_to_encoding(extenc);
6697 if (!UNDEF_P(intenc)) {
6698 if (NIL_P(intenc)) {
6699 /* internal_encoding: nil => no transcoding */
6700 intencoding = (rb_encoding *)Qnil;
6702 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6703 char *p = StringValueCStr(tmp);
6705 if (*p == '-' && *(p+1) == '\0') {
6706 /* Special case - "-" => no transcoding */
6707 intencoding = (rb_encoding *)Qnil;
6709 else {
6710 intencoding = rb_to_encoding(intenc);
6713 else {
6714 intencoding = rb_to_encoding(intenc);
6716 if (extencoding == intencoding) {
6717 intencoding = (rb_encoding *)Qnil;
6720 if (!NIL_P(encoding)) {
6721 extracted = 1;
6722 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6723 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6724 enc_p, enc2_p, fmode_p);
6726 else {
6727 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6730 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6731 extracted = 1;
6732 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6734 return extracted;
6737 static void
6738 validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6740 int fmode = *fmode_p;
6742 if ((fmode & FMODE_READABLE) &&
6743 !enc2 &&
6744 !(fmode & FMODE_BINMODE) &&
6745 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6746 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6748 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6749 rb_raise(rb_eArgError, "newline decorator with binary mode");
6751 if (!(fmode & FMODE_BINMODE) &&
6752 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6753 fmode |= FMODE_TEXTMODE;
6754 *fmode_p = fmode;
6756 #if !DEFAULT_TEXTMODE
6757 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6758 fmode &= ~FMODE_TEXTMODE;
6759 *fmode_p = fmode;
6761 #endif
6764 static void
6765 extract_binmode(VALUE opthash, int *fmode)
6767 if (!NIL_P(opthash)) {
6768 VALUE v;
6769 v = rb_hash_aref(opthash, sym_textmode);
6770 if (!NIL_P(v)) {
6771 if (*fmode & FMODE_TEXTMODE)
6772 rb_raise(rb_eArgError, "textmode specified twice");
6773 if (*fmode & FMODE_BINMODE)
6774 rb_raise(rb_eArgError, "both textmode and binmode specified");
6775 if (RTEST(v))
6776 *fmode |= FMODE_TEXTMODE;
6778 v = rb_hash_aref(opthash, sym_binmode);
6779 if (!NIL_P(v)) {
6780 if (*fmode & FMODE_BINMODE)
6781 rb_raise(rb_eArgError, "binmode specified twice");
6782 if (*fmode & FMODE_TEXTMODE)
6783 rb_raise(rb_eArgError, "both textmode and binmode specified");
6784 if (RTEST(v))
6785 *fmode |= FMODE_BINMODE;
6788 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6789 rb_raise(rb_eArgError, "both textmode and binmode specified");
6793 void
6794 rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6795 int *oflags_p, int *fmode_p, struct rb_io_encoding *convconfig_p)
6797 VALUE vmode;
6798 int oflags, fmode;
6799 rb_encoding *enc, *enc2;
6800 int ecflags;
6801 VALUE ecopts;
6802 int has_enc = 0, has_vmode = 0;
6803 VALUE intmode;
6805 vmode = *vmode_p;
6807 /* Set to defaults */
6808 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6810 vmode_handle:
6811 if (NIL_P(vmode)) {
6812 fmode = FMODE_READABLE;
6813 oflags = O_RDONLY;
6815 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6816 vmode = intmode;
6817 oflags = NUM2INT(intmode);
6818 fmode = rb_io_oflags_fmode(oflags);
6820 else {
6821 const char *p;
6823 StringValue(vmode);
6824 p = StringValueCStr(vmode);
6825 fmode = rb_io_modestr_fmode(p);
6826 oflags = rb_io_fmode_oflags(fmode);
6827 p = strchr(p, ':');
6828 if (p) {
6829 has_enc = 1;
6830 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6832 else {
6833 rb_encoding *e;
6835 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6836 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6840 if (NIL_P(opthash)) {
6841 ecflags = (fmode & FMODE_READABLE) ?
6842 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6843 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6844 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6845 ecflags |= (fmode & FMODE_WRITABLE) ?
6846 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6847 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6848 #endif
6849 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6850 ecopts = Qnil;
6851 if (fmode & FMODE_BINMODE) {
6852 #ifdef O_BINARY
6853 oflags |= O_BINARY;
6854 #endif
6855 if (!has_enc)
6856 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6858 #if DEFAULT_TEXTMODE
6859 else if (NIL_P(vmode)) {
6860 fmode |= DEFAULT_TEXTMODE;
6862 #endif
6864 else {
6865 VALUE v;
6866 if (!has_vmode) {
6867 v = rb_hash_aref(opthash, sym_mode);
6868 if (!NIL_P(v)) {
6869 if (!NIL_P(vmode)) {
6870 rb_raise(rb_eArgError, "mode specified twice");
6872 has_vmode = 1;
6873 vmode = v;
6874 goto vmode_handle;
6877 v = rb_hash_aref(opthash, sym_flags);
6878 if (!NIL_P(v)) {
6879 v = rb_to_int(v);
6880 oflags |= NUM2INT(v);
6881 vmode = INT2NUM(oflags);
6882 fmode = rb_io_oflags_fmode(oflags);
6884 extract_binmode(opthash, &fmode);
6885 if (fmode & FMODE_BINMODE) {
6886 #ifdef O_BINARY
6887 oflags |= O_BINARY;
6888 #endif
6889 if (!has_enc)
6890 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6892 #if DEFAULT_TEXTMODE
6893 else if (NIL_P(vmode)) {
6894 fmode |= DEFAULT_TEXTMODE;
6896 #endif
6897 v = rb_hash_aref(opthash, sym_perm);
6898 if (!NIL_P(v)) {
6899 if (vperm_p) {
6900 if (!NIL_P(*vperm_p)) {
6901 rb_raise(rb_eArgError, "perm specified twice");
6903 *vperm_p = v;
6905 else {
6906 /* perm no use, just ignore */
6909 ecflags = (fmode & FMODE_READABLE) ?
6910 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6911 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6912 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6913 ecflags |= (fmode & FMODE_WRITABLE) ?
6914 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6915 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6916 #endif
6918 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6919 if (has_enc) {
6920 rb_raise(rb_eArgError, "encoding specified twice");
6923 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6924 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
6927 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6929 *vmode_p = vmode;
6931 *oflags_p = oflags;
6932 *fmode_p = fmode;
6933 convconfig_p->enc = enc;
6934 convconfig_p->enc2 = enc2;
6935 convconfig_p->ecflags = ecflags;
6936 convconfig_p->ecopts = ecopts;
6939 struct sysopen_struct {
6940 VALUE fname;
6941 int oflags;
6942 mode_t perm;
6945 static void *
6946 sysopen_func(void *ptr)
6948 const struct sysopen_struct *data = ptr;
6949 const char *fname = RSTRING_PTR(data->fname);
6950 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
6953 static inline int
6954 rb_sysopen_internal(struct sysopen_struct *data)
6956 int fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
6957 if (0 <= fd)
6958 rb_update_max_fd(fd);
6959 return fd;
6962 static int
6963 rb_sysopen(VALUE fname, int oflags, mode_t perm)
6965 int fd = -1;
6966 struct sysopen_struct data;
6968 data.fname = rb_str_encode_ospath(fname);
6969 StringValueCStr(data.fname);
6970 data.oflags = oflags;
6971 data.perm = perm;
6973 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
6974 rb_syserr_fail_path(first_errno, fname);
6976 return fd;
6979 static inline FILE *
6980 fdopen_internal(int fd, const char *modestr)
6982 FILE *file;
6984 #if defined(__sun)
6985 errno = 0;
6986 #endif
6987 file = fdopen(fd, modestr);
6988 if (!file) {
6989 #ifdef _WIN32
6990 if (errno == 0) errno = EINVAL;
6991 #elif defined(__sun)
6992 if (errno == 0) errno = EMFILE;
6993 #endif
6995 return file;
6998 FILE *
6999 rb_fdopen(int fd, const char *modestr)
7001 FILE *file = 0;
7003 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7004 rb_syserr_fail(first_errno, 0);
7007 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7008 #ifdef USE_SETVBUF
7009 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7010 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7011 #endif
7012 return file;
7015 static int
7016 io_check_tty(rb_io_t *fptr)
7018 int t = isatty(fptr->fd);
7019 if (t)
7020 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7021 return t;
7024 static VALUE rb_io_internal_encoding(VALUE);
7025 static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7027 static int
7028 io_strip_bom(VALUE io)
7030 VALUE b1, b2, b3, b4;
7031 rb_io_t *fptr;
7033 GetOpenFile(io, fptr);
7034 if (!(fptr->mode & FMODE_READABLE)) return 0;
7035 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7036 switch (b1) {
7037 case INT2FIX(0xEF):
7038 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7039 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7040 if (b3 == INT2FIX(0xBF)) {
7041 return rb_utf8_encindex();
7043 rb_io_ungetbyte(io, b3);
7045 rb_io_ungetbyte(io, b2);
7046 break;
7048 case INT2FIX(0xFE):
7049 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7050 if (b2 == INT2FIX(0xFF)) {
7051 return ENCINDEX_UTF_16BE;
7053 rb_io_ungetbyte(io, b2);
7054 break;
7056 case INT2FIX(0xFF):
7057 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7058 if (b2 == INT2FIX(0xFE)) {
7059 b3 = rb_io_getbyte(io);
7060 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7061 if (b4 == INT2FIX(0)) {
7062 return ENCINDEX_UTF_32LE;
7064 rb_io_ungetbyte(io, b4);
7066 rb_io_ungetbyte(io, b3);
7067 return ENCINDEX_UTF_16LE;
7069 rb_io_ungetbyte(io, b2);
7070 break;
7072 case INT2FIX(0):
7073 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7074 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7075 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7076 if (b4 == INT2FIX(0xFF)) {
7077 return ENCINDEX_UTF_32BE;
7079 rb_io_ungetbyte(io, b4);
7081 rb_io_ungetbyte(io, b3);
7083 rb_io_ungetbyte(io, b2);
7084 break;
7086 rb_io_ungetbyte(io, b1);
7087 return 0;
7090 static rb_encoding *
7091 io_set_encoding_by_bom(VALUE io)
7093 int idx = io_strip_bom(io);
7094 rb_io_t *fptr;
7095 rb_encoding *extenc = NULL;
7097 GetOpenFile(io, fptr);
7098 if (idx) {
7099 extenc = rb_enc_from_index(idx);
7100 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7101 rb_io_internal_encoding(io), Qnil);
7103 else {
7104 fptr->encs.enc2 = NULL;
7106 return extenc;
7109 static VALUE
7110 rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7111 const struct rb_io_encoding *convconfig, mode_t perm)
7113 VALUE pathv;
7114 rb_io_t *fptr;
7115 struct rb_io_encoding cc;
7116 if (!convconfig) {
7117 /* Set to default encodings */
7118 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7119 cc.ecflags = 0;
7120 cc.ecopts = Qnil;
7121 convconfig = &cc;
7123 validate_enc_binmode(&fmode, convconfig->ecflags,
7124 convconfig->enc, convconfig->enc2);
7126 MakeOpenFile(io, fptr);
7127 fptr->mode = fmode;
7128 fptr->encs = *convconfig;
7129 pathv = rb_str_new_frozen(filename);
7130 #ifdef O_TMPFILE
7131 if (!(oflags & O_TMPFILE)) {
7132 fptr->pathv = pathv;
7134 #else
7135 fptr->pathv = pathv;
7136 #endif
7137 fptr->fd = rb_sysopen(pathv, oflags, perm);
7138 io_check_tty(fptr);
7139 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7141 return io;
7144 static VALUE
7145 rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7147 int fmode = rb_io_modestr_fmode(modestr);
7148 const char *p = strchr(modestr, ':');
7149 struct rb_io_encoding convconfig;
7151 if (p) {
7152 parse_mode_enc(p+1, rb_usascii_encoding(),
7153 &convconfig.enc, &convconfig.enc2, &fmode);
7155 else {
7156 rb_encoding *e;
7157 /* Set to default encodings */
7159 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7160 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7163 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7164 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
7165 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
7166 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7167 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7168 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7169 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7170 #endif
7171 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7172 convconfig.ecopts = Qnil;
7174 return rb_file_open_generic(io, filename,
7175 rb_io_fmode_oflags(fmode),
7176 fmode,
7177 &convconfig,
7178 0666);
7181 VALUE
7182 rb_file_open_str(VALUE fname, const char *modestr)
7184 FilePathValue(fname);
7185 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7188 VALUE
7189 rb_file_open(const char *fname, const char *modestr)
7191 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7194 #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7195 static struct pipe_list {
7196 rb_io_t *fptr;
7197 struct pipe_list *next;
7198 } *pipe_list;
7200 static void
7201 pipe_add_fptr(rb_io_t *fptr)
7203 struct pipe_list *list;
7205 list = ALLOC(struct pipe_list);
7206 list->fptr = fptr;
7207 list->next = pipe_list;
7208 pipe_list = list;
7211 static void
7212 pipe_del_fptr(rb_io_t *fptr)
7214 struct pipe_list **prev = &pipe_list;
7215 struct pipe_list *tmp;
7217 while ((tmp = *prev) != 0) {
7218 if (tmp->fptr == fptr) {
7219 *prev = tmp->next;
7220 free(tmp);
7221 return;
7223 prev = &tmp->next;
7227 #if defined (_WIN32) || defined(__CYGWIN__)
7228 static void
7229 pipe_atexit(void)
7231 struct pipe_list *list = pipe_list;
7232 struct pipe_list *tmp;
7234 while (list) {
7235 tmp = list->next;
7236 rb_io_fptr_finalize(list->fptr);
7237 list = tmp;
7240 #endif
7242 static void
7243 pipe_finalize(rb_io_t *fptr, int noraise)
7245 #if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7246 int status = 0;
7247 if (fptr->stdio_file) {
7248 status = pclose(fptr->stdio_file);
7250 fptr->fd = -1;
7251 fptr->stdio_file = 0;
7252 rb_last_status_set(status, fptr->pid);
7253 #else
7254 fptr_finalize(fptr, noraise);
7255 #endif
7256 pipe_del_fptr(fptr);
7258 #endif
7260 static void
7261 fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7263 #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7264 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7266 if (old_finalize == orig->finalize) return;
7267 #endif
7269 fptr->finalize = orig->finalize;
7271 #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7272 if (old_finalize != pipe_finalize) {
7273 struct pipe_list *list;
7274 for (list = pipe_list; list; list = list->next) {
7275 if (list->fptr == fptr) break;
7277 if (!list) pipe_add_fptr(fptr);
7279 else {
7280 pipe_del_fptr(fptr);
7282 #endif
7285 void
7286 rb_io_synchronized(rb_io_t *fptr)
7288 rb_io_check_initialized(fptr);
7289 fptr->mode |= FMODE_SYNC;
7292 void
7293 rb_io_unbuffered(rb_io_t *fptr)
7295 rb_io_synchronized(fptr);
7299 rb_pipe(int *pipes)
7301 int ret;
7302 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7303 if (ret == 0) {
7304 rb_update_max_fd(pipes[0]);
7305 rb_update_max_fd(pipes[1]);
7307 return ret;
7310 #ifdef _WIN32
7311 #define HAVE_SPAWNV 1
7312 #define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7313 #define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7314 #endif
7316 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7317 struct popen_arg {
7318 VALUE execarg_obj;
7319 struct rb_execarg *eargp;
7320 int modef;
7321 int pair[2];
7322 int write_pair[2];
7324 #endif
7326 #ifdef HAVE_WORKING_FORK
7327 # ifndef __EMSCRIPTEN__
7328 static void
7329 popen_redirect(struct popen_arg *p)
7331 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7332 close(p->write_pair[1]);
7333 if (p->write_pair[0] != 0) {
7334 dup2(p->write_pair[0], 0);
7335 close(p->write_pair[0]);
7337 close(p->pair[0]);
7338 if (p->pair[1] != 1) {
7339 dup2(p->pair[1], 1);
7340 close(p->pair[1]);
7343 else if (p->modef & FMODE_READABLE) {
7344 close(p->pair[0]);
7345 if (p->pair[1] != 1) {
7346 dup2(p->pair[1], 1);
7347 close(p->pair[1]);
7350 else {
7351 close(p->pair[1]);
7352 if (p->pair[0] != 0) {
7353 dup2(p->pair[0], 0);
7354 close(p->pair[0]);
7358 # endif
7360 #if defined(__linux__)
7361 /* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7362 * Since /proc may not be available, linux_get_maxfd is just a hint.
7363 * This function, linux_get_maxfd, must be async-signal-safe.
7364 * I.e. opendir() is not usable.
7366 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7367 * However they are easy to re-implement in async-signal-safe manner.
7368 * (Also note that there is missing/memcmp.c.)
7370 static int
7371 linux_get_maxfd(void)
7373 int fd;
7374 char buf[4096], *p, *np, *e;
7375 ssize_t ss;
7376 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7377 if (fd < 0) return fd;
7378 ss = read(fd, buf, sizeof(buf));
7379 if (ss < 0) goto err;
7380 p = buf;
7381 e = buf + ss;
7382 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7383 (np = memchr(p, '\n', e-p)) != NULL) {
7384 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7385 int fdsize;
7386 p += sizeof("FDSize:")-1;
7387 *np = '\0';
7388 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7389 close(fd);
7390 return fdsize;
7392 p = np+1;
7394 /* fall through */
7396 err:
7397 close(fd);
7398 return (int)ss;
7400 #endif
7402 /* This function should be async-signal-safe. */
7403 void
7404 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7406 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7407 int fd, ret;
7408 int max = (int)max_file_descriptor;
7409 # ifdef F_MAXFD
7410 /* F_MAXFD is available since NetBSD 2.0. */
7411 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7412 if (ret != -1)
7413 maxhint = max = ret;
7414 # elif defined(__linux__)
7415 ret = linux_get_maxfd();
7416 if (maxhint < ret)
7417 maxhint = ret;
7418 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7419 # endif
7420 if (max < maxhint)
7421 max = maxhint;
7422 for (fd = lowfd; fd <= max; fd++) {
7423 if (!NIL_P(noclose_fds) &&
7424 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7425 continue;
7426 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7427 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7428 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7430 # define CONTIGUOUS_CLOSED_FDS 20
7431 if (ret != -1) {
7432 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7433 max = fd + CONTIGUOUS_CLOSED_FDS;
7436 #endif
7439 # ifndef __EMSCRIPTEN__
7440 static int
7441 popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7443 struct popen_arg *p = (struct popen_arg*)pp;
7445 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7447 # endif
7448 #endif
7450 #if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7451 static VALUE
7452 rb_execarg_fixup_v(VALUE execarg_obj)
7454 rb_execarg_parent_start(execarg_obj);
7455 return Qnil;
7457 #else
7458 char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7459 #endif
7461 #ifndef __EMSCRIPTEN__
7462 static VALUE
7463 pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7464 const struct rb_io_encoding *convconfig)
7466 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7467 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7468 rb_pid_t pid = 0;
7469 rb_io_t *fptr;
7470 VALUE port;
7471 rb_io_t *write_fptr;
7472 VALUE write_port;
7473 #if defined(HAVE_WORKING_FORK)
7474 int status;
7475 char errmsg[80] = { '\0' };
7476 #endif
7477 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7478 int state;
7479 struct popen_arg arg;
7480 #endif
7481 int e = 0;
7482 #if defined(HAVE_SPAWNV)
7483 # if defined(HAVE_SPAWNVE)
7484 # define DO_SPAWN(cmd, args, envp) ((args) ? \
7485 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7486 spawne(P_NOWAIT, (cmd), (envp)))
7487 # else
7488 # define DO_SPAWN(cmd, args, envp) ((args) ? \
7489 spawnv(P_NOWAIT, (cmd), (args)) : \
7490 spawn(P_NOWAIT, (cmd)))
7491 # endif
7492 # if !defined(HAVE_WORKING_FORK)
7493 char **args = NULL;
7494 # if defined(HAVE_SPAWNVE)
7495 char **envp = NULL;
7496 # endif
7497 # endif
7498 #endif
7499 #if !defined(HAVE_WORKING_FORK)
7500 struct rb_execarg sarg, *sargp = &sarg;
7501 #endif
7502 FILE *fp = 0;
7503 int fd = -1;
7504 int write_fd = -1;
7505 #if !defined(HAVE_WORKING_FORK)
7506 const char *cmd = 0;
7508 if (prog)
7509 cmd = StringValueCStr(prog);
7510 #endif
7512 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7513 arg.execarg_obj = execarg_obj;
7514 arg.eargp = eargp;
7515 arg.modef = fmode;
7516 arg.pair[0] = arg.pair[1] = -1;
7517 arg.write_pair[0] = arg.write_pair[1] = -1;
7518 # if !defined(HAVE_WORKING_FORK)
7519 if (eargp && !eargp->use_shell) {
7520 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7522 # endif
7523 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7524 case FMODE_READABLE|FMODE_WRITABLE:
7525 if (rb_pipe(arg.write_pair) < 0)
7526 rb_sys_fail_str(prog);
7527 if (rb_pipe(arg.pair) < 0) {
7528 e = errno;
7529 close(arg.write_pair[0]);
7530 close(arg.write_pair[1]);
7531 rb_syserr_fail_str(e, prog);
7533 if (eargp) {
7534 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7535 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7537 break;
7538 case FMODE_READABLE:
7539 if (rb_pipe(arg.pair) < 0)
7540 rb_sys_fail_str(prog);
7541 if (eargp)
7542 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7543 break;
7544 case FMODE_WRITABLE:
7545 if (rb_pipe(arg.pair) < 0)
7546 rb_sys_fail_str(prog);
7547 if (eargp)
7548 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7549 break;
7550 default:
7551 rb_sys_fail_str(prog);
7553 if (!NIL_P(execarg_obj)) {
7554 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7555 if (state) {
7556 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7557 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7558 if (0 <= arg.pair[0]) close(arg.pair[0]);
7559 if (0 <= arg.pair[1]) close(arg.pair[1]);
7560 rb_execarg_parent_end(execarg_obj);
7561 rb_jump_tag(state);
7564 # if defined(HAVE_WORKING_FORK)
7565 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7566 # else
7567 rb_execarg_run_options(eargp, sargp, NULL, 0);
7568 # if defined(HAVE_SPAWNVE)
7569 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7570 # endif
7571 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7572 /* exec failed */
7573 switch (e = errno) {
7574 case EAGAIN:
7575 # if EWOULDBLOCK != EAGAIN
7576 case EWOULDBLOCK:
7577 # endif
7578 rb_thread_sleep(1);
7579 continue;
7581 break;
7583 if (eargp)
7584 rb_execarg_run_options(sargp, NULL, NULL, 0);
7585 # endif
7586 rb_execarg_parent_end(execarg_obj);
7588 else {
7589 # if defined(HAVE_WORKING_FORK)
7590 pid = rb_call_proc__fork();
7591 if (pid == 0) { /* child */
7592 popen_redirect(&arg);
7593 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7594 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7595 return Qnil;
7597 # else
7598 rb_notimplement();
7599 # endif
7602 /* parent */
7603 if (pid < 0) {
7604 # if defined(HAVE_WORKING_FORK)
7605 e = errno;
7606 # endif
7607 close(arg.pair[0]);
7608 close(arg.pair[1]);
7609 if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) {
7610 close(arg.write_pair[0]);
7611 close(arg.write_pair[1]);
7613 # if defined(HAVE_WORKING_FORK)
7614 if (errmsg[0])
7615 rb_syserr_fail(e, errmsg);
7616 # endif
7617 rb_syserr_fail_str(e, prog);
7619 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7620 close(arg.pair[1]);
7621 fd = arg.pair[0];
7622 close(arg.write_pair[0]);
7623 write_fd = arg.write_pair[1];
7625 else if (fmode & FMODE_READABLE) {
7626 close(arg.pair[1]);
7627 fd = arg.pair[0];
7629 else {
7630 close(arg.pair[0]);
7631 fd = arg.pair[1];
7633 #else
7634 cmd = rb_execarg_commandline(eargp, &prog);
7635 if (!NIL_P(execarg_obj)) {
7636 rb_execarg_parent_start(execarg_obj);
7637 rb_execarg_run_options(eargp, sargp, NULL, 0);
7639 fp = popen(cmd, modestr);
7640 e = errno;
7641 if (eargp) {
7642 rb_execarg_parent_end(execarg_obj);
7643 rb_execarg_run_options(sargp, NULL, NULL, 0);
7645 if (!fp) rb_syserr_fail_path(e, prog);
7646 fd = fileno(fp);
7647 #endif
7649 port = io_alloc(rb_cIO);
7650 MakeOpenFile(port, fptr);
7651 fptr->fd = fd;
7652 fptr->stdio_file = fp;
7653 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7654 if (convconfig) {
7655 fptr->encs = *convconfig;
7656 #if RUBY_CRLF_ENVIRONMENT
7657 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
7658 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7660 #endif
7662 else {
7663 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7664 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7666 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7667 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7668 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7670 #endif
7672 fptr->pid = pid;
7674 if (0 <= write_fd) {
7675 write_port = io_alloc(rb_cIO);
7676 MakeOpenFile(write_port, write_fptr);
7677 write_fptr->fd = write_fd;
7678 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7679 fptr->mode &= ~FMODE_WRITABLE;
7680 fptr->tied_io_for_writing = write_port;
7681 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7684 #if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7685 fptr->finalize = pipe_finalize;
7686 pipe_add_fptr(fptr);
7687 #endif
7688 return port;
7690 #else
7691 static VALUE
7692 pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7693 const struct rb_io_encoding *convconfig)
7695 rb_raise(rb_eNotImpError, "popen() is not available");
7697 #endif
7699 static int
7700 is_popen_fork(VALUE prog)
7702 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7703 #if !defined(HAVE_WORKING_FORK)
7704 rb_raise(rb_eNotImpError,
7705 "fork() function is unimplemented on this machine");
7706 #else
7707 return TRUE;
7708 #endif
7710 return FALSE;
7713 static VALUE
7714 pipe_open_s(VALUE prog, const char *modestr, int fmode,
7715 const struct rb_io_encoding *convconfig)
7717 int argc = 1;
7718 VALUE *argv = &prog;
7719 VALUE execarg_obj = Qnil;
7721 if (!is_popen_fork(prog))
7722 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7723 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7726 static VALUE
7727 pipe_close(VALUE io)
7729 rb_io_t *fptr = io_close_fptr(io);
7730 if (fptr) {
7731 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7733 return Qnil;
7736 static VALUE popen_finish(VALUE port, VALUE klass);
7739 * call-seq:
7740 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7741 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7743 * Executes the given command +cmd+ as a subprocess
7744 * whose $stdin and $stdout are connected to a new stream +io+.
7746 * This method has potential security vulnerabilities if called with untrusted input;
7747 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7749 * If no block is given, returns the new stream,
7750 * which depending on given +mode+ may be open for reading, writing, or both.
7751 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7753 * If a block is given, the stream is passed to the block
7754 * (again, open for reading, writing, or both);
7755 * when the block exits, the stream is closed,
7756 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7758 * Optional argument +mode+ may be any valid \IO mode.
7759 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7761 * Required argument +cmd+ determines which of the following occurs:
7763 * - The process forks.
7764 * - A specified program runs in a shell.
7765 * - A specified program runs with specified arguments.
7766 * - A specified program runs with specified arguments and a specified +argv0+.
7768 * Each of these is detailed below.
7770 * The optional hash argument +env+ specifies name/value pairs that are to be added
7771 * to the environment variables for the subprocess:
7773 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7774 * pipe.puts 'puts ENV["FOO"]'
7775 * pipe.close_write
7776 * pipe.gets
7777 * end => "bar\n"
7779 * Optional keyword arguments +opts+ specify:
7781 * - {Open options}[rdoc-ref:IO@Open+Options].
7782 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7783 * - Options for Kernel#spawn.
7785 * <b>Forked \Process</b>
7787 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7788 * IO.popen('-') do |pipe|
7789 * if pipe
7790 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7791 * else
7792 * $stderr.puts "In child, pid is #{$$}\n"
7793 * end
7794 * end
7796 * Output:
7798 * In parent, child pid is 26253
7799 * In child, pid is 26253
7801 * Note that this is not supported on all platforms.
7803 * <b>Shell Subprocess</b>
7805 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7806 * the program named +cmd+ is run as a shell command:
7808 * IO.popen('uname') do |pipe|
7809 * pipe.readlines
7810 * end
7812 * Output:
7814 * ["Linux\n"]
7816 * Another example:
7818 * IO.popen('/bin/sh', 'r+') do |pipe|
7819 * pipe.puts('ls')
7820 * pipe.close_write
7821 * $stderr.puts pipe.readlines.size
7822 * end
7824 * Output:
7826 * 213
7828 * <b>Program Subprocess</b>
7830 * When argument +cmd+ is an array of strings,
7831 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7833 * IO.popen(['du', '..', '.']) do |pipe|
7834 * $stderr.puts pipe.readlines.size
7835 * end
7837 * Output:
7839 * 1111
7841 * <b>Program Subprocess with <tt>argv0</tt></b>
7843 * When argument +cmd+ is an array whose first element is a 2-element string array
7844 * and whose remaining elements (if any) are strings:
7846 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7847 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7848 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7850 * Example (sets <tt>$0</tt> to 'foo'):
7852 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7854 * <b>Some Special Examples</b>
7856 * # Set IO encoding.
7857 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7858 * euc_jp_string = nkf_io.read
7861 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7862 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7863 * ls_result_with_error = io.read
7864 * end
7866 * # Use mixture of spawn options and IO options.
7867 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7868 * ls_result_with_error = io.read
7869 * end
7871 * f = IO.popen("uname")
7872 * p f.readlines
7873 * f.close
7874 * puts "Parent is #{Process.pid}"
7875 * IO.popen("date") {|f| puts f.gets }
7876 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7877 * p $?
7878 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7879 * f.puts "bar"; f.close_write; puts f.gets
7882 * Output (from last section):
7884 * ["Linux\n"]
7885 * Parent is 21346
7886 * Thu Jan 15 22:41:19 JST 2009
7887 * 21346 is here, f is #<IO:fd 3>
7888 * 21352 is here, f is nil
7889 * #<Process::Status: pid 21352 exit 0>
7890 * <foo>bar;zot;
7892 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7896 static VALUE
7897 rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7899 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7901 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7902 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7903 switch (argc) {
7904 case 2:
7905 pmode = argv[1];
7906 case 1:
7907 pname = argv[0];
7908 break;
7909 default:
7911 int ex = !NIL_P(opt);
7912 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7915 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7918 VALUE
7919 rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7921 const char *modestr;
7922 VALUE tmp, execarg_obj = Qnil;
7923 int oflags, fmode;
7924 struct rb_io_encoding convconfig;
7926 tmp = rb_check_array_type(pname);
7927 if (!NIL_P(tmp)) {
7928 long len = RARRAY_LEN(tmp);
7929 #if SIZEOF_LONG > SIZEOF_INT
7930 if (len > INT_MAX) {
7931 rb_raise(rb_eArgError, "too many arguments");
7933 #endif
7934 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7935 RB_GC_GUARD(tmp);
7937 else {
7938 StringValue(pname);
7939 execarg_obj = Qnil;
7940 if (!is_popen_fork(pname))
7941 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7943 if (!NIL_P(execarg_obj)) {
7944 if (!NIL_P(opt))
7945 opt = rb_execarg_extract_options(execarg_obj, opt);
7946 if (!NIL_P(env))
7947 rb_execarg_setenv(execarg_obj, env);
7949 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
7950 modestr = rb_io_oflags_modestr(oflags);
7952 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7955 static VALUE
7956 popen_finish(VALUE port, VALUE klass)
7958 if (NIL_P(port)) {
7959 /* child */
7960 if (rb_block_given_p()) {
7961 rb_yield(Qnil);
7962 rb_io_flush(rb_ractor_stdout());
7963 rb_io_flush(rb_ractor_stderr());
7964 _exit(0);
7966 return Qnil;
7968 RBASIC_SET_CLASS(port, klass);
7969 if (rb_block_given_p()) {
7970 return rb_ensure(rb_yield, port, pipe_close, port);
7972 return port;
7975 #if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
7976 struct popen_writer_arg {
7977 char *const *argv;
7978 struct popen_arg popen;
7981 static int
7982 exec_popen_writer(void *arg, char *errmsg, size_t buflen)
7984 struct popen_writer_arg *pw = arg;
7985 pw->popen.modef = FMODE_WRITABLE;
7986 popen_redirect(&pw->popen);
7987 execv(pw->argv[0], pw->argv);
7988 strlcpy(errmsg, strerror(errno), buflen);
7989 return -1;
7991 #endif
7993 FILE *
7994 ruby_popen_writer(char *const *argv, rb_pid_t *pid)
7996 #if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
7997 # ifdef HAVE_WORKING_FORK
7998 struct popen_writer_arg pw;
7999 int *const write_pair = pw.popen.pair;
8000 # else
8001 int write_pair[2];
8002 # endif
8004 int result = rb_cloexec_pipe(write_pair);
8005 *pid = -1;
8006 if (result == 0) {
8007 # ifdef HAVE_WORKING_FORK
8008 pw.argv = argv;
8009 int status;
8010 char errmsg[80] = {'\0'};
8011 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8012 # else
8013 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8014 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8015 # endif
8016 close(write_pair[0]);
8017 if (*pid < 0) {
8018 close(write_pair[1]);
8019 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8021 else {
8022 return fdopen(write_pair[1], "w");
8025 #endif
8026 return NULL;
8029 static void
8030 rb_scan_open_args(int argc, const VALUE *argv,
8031 VALUE *fname_p, int *oflags_p, int *fmode_p,
8032 struct rb_io_encoding *convconfig_p, mode_t *perm_p)
8034 VALUE opt, fname, vmode, vperm;
8035 int oflags, fmode;
8036 mode_t perm;
8038 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
8039 FilePathValue(fname);
8041 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
8043 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8045 *fname_p = fname;
8046 *oflags_p = oflags;
8047 *fmode_p = fmode;
8048 *perm_p = perm;
8051 static VALUE
8052 rb_open_file(int argc, const VALUE *argv, VALUE io)
8054 VALUE fname;
8055 int oflags, fmode;
8056 struct rb_io_encoding convconfig;
8057 mode_t perm;
8059 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
8060 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8062 return io;
8066 * Document-method: File::open
8068 * call-seq:
8069 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8070 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8072 * Creates a new File object, via File.new with the given arguments.
8074 * With no block given, returns the File object.
8076 * With a block given, calls the block with the File object
8077 * and returns the block's value.
8082 * Document-method: IO::open
8084 * call-seq:
8085 * IO.open(fd, mode = 'r', **opts) -> io
8086 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8088 * Creates a new \IO object, via IO.new with the given arguments.
8090 * With no block given, returns the \IO object.
8092 * With a block given, calls the block with the \IO object
8093 * and returns the block's value.
8097 static VALUE
8098 rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8100 VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
8102 if (rb_block_given_p()) {
8103 return rb_ensure(rb_yield, io, io_close, io);
8106 return io;
8110 * call-seq:
8111 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8113 * Opens the file at the given path with the given mode and permissions;
8114 * returns the integer file descriptor.
8116 * If the file is to be readable, it must exist;
8117 * if the file is to be writable and does not exist,
8118 * it is created with the given permissions:
8120 * File.write('t.tmp', '') # => 0
8121 * IO.sysopen('t.tmp') # => 8
8122 * IO.sysopen('t.tmp', 'w') # => 9
8127 static VALUE
8128 rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8130 VALUE fname, vmode, vperm;
8131 VALUE intmode;
8132 int oflags, fd;
8133 mode_t perm;
8135 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8136 FilePathValue(fname);
8138 if (NIL_P(vmode))
8139 oflags = O_RDONLY;
8140 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8141 oflags = NUM2INT(intmode);
8142 else {
8143 StringValue(vmode);
8144 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8146 if (NIL_P(vperm)) perm = 0666;
8147 else perm = NUM2MODET(vperm);
8149 RB_GC_GUARD(fname) = rb_str_new4(fname);
8150 fd = rb_sysopen(fname, oflags, perm);
8151 return INT2NUM(fd);
8154 static VALUE
8155 check_pipe_command(VALUE filename_or_command)
8157 char *s = RSTRING_PTR(filename_or_command);
8158 long l = RSTRING_LEN(filename_or_command);
8159 char *e = s + l;
8160 int chlen;
8162 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8163 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8164 return cmd;
8166 return Qnil;
8170 * call-seq:
8171 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8172 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8174 * Creates an IO object connected to the given file.
8176 * This method has potential security vulnerabilities if called with untrusted input;
8177 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8179 * With no block given, file stream is returned:
8181 * open('t.txt') # => #<File:t.txt>
8183 * With a block given, calls the block with the open file stream,
8184 * then closes the stream:
8186 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8188 * Output:
8190 * #<File:t.txt>
8192 * See File.open for details.
8196 static VALUE
8197 rb_f_open(int argc, VALUE *argv, VALUE _)
8199 ID to_open = 0;
8200 int redirect = FALSE;
8202 if (argc >= 1) {
8203 CONST_ID(to_open, "to_open");
8204 if (rb_respond_to(argv[0], to_open)) {
8205 redirect = TRUE;
8207 else {
8208 VALUE tmp = argv[0];
8209 FilePathValue(tmp);
8210 if (NIL_P(tmp)) {
8211 redirect = TRUE;
8213 else {
8214 VALUE cmd = check_pipe_command(tmp);
8215 if (!NIL_P(cmd)) {
8216 // TODO: when removed in 4.0, update command_injection.rdoc
8217 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8218 argv[0] = cmd;
8219 return rb_io_s_popen(argc, argv, rb_cIO);
8224 if (redirect) {
8225 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8227 if (rb_block_given_p()) {
8228 return rb_ensure(rb_yield, io, io_close, io);
8230 return io;
8232 return rb_io_s_open(argc, argv, rb_cFile);
8235 static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const struct rb_io_encoding *, mode_t);
8237 static VALUE
8238 rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8240 int oflags, fmode;
8241 struct rb_io_encoding convconfig;
8242 mode_t perm;
8244 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8245 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8246 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8249 static VALUE
8250 rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8251 const struct rb_io_encoding *convconfig, mode_t perm)
8253 VALUE cmd;
8254 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8255 // TODO: when removed in 4.0, update command_injection.rdoc
8256 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8257 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8259 else {
8260 return rb_file_open_generic(io_alloc(klass), filename,
8261 oflags, fmode, convconfig, perm);
8265 static VALUE
8266 io_reopen(VALUE io, VALUE nfile)
8268 rb_io_t *fptr, *orig;
8269 int fd, fd2;
8270 rb_off_t pos = 0;
8272 nfile = rb_io_get_io(nfile);
8273 GetOpenFile(io, fptr);
8274 GetOpenFile(nfile, orig);
8276 if (fptr == orig) return io;
8277 if (RUBY_IO_EXTERNAL_P(fptr)) {
8278 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8279 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8280 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8281 rb_raise(rb_eArgError,
8282 "%s can't change access mode from \"%s\" to \"%s\"",
8283 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8284 rb_io_fmode_modestr(orig->mode));
8287 if (fptr->mode & FMODE_WRITABLE) {
8288 if (io_fflush(fptr) < 0)
8289 rb_sys_fail_on_write(fptr);
8291 else {
8292 flush_before_seek(fptr);
8294 if (orig->mode & FMODE_READABLE) {
8295 pos = io_tell(orig);
8297 if (orig->mode & FMODE_WRITABLE) {
8298 if (io_fflush(orig) < 0)
8299 rb_sys_fail_on_write(fptr);
8302 /* copy rb_io_t structure */
8303 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8304 fptr->pid = orig->pid;
8305 fptr->lineno = orig->lineno;
8306 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8307 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8308 fptr_copy_finalizer(fptr, orig);
8310 fd = fptr->fd;
8311 fd2 = orig->fd;
8312 if (fd != fd2) {
8313 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8314 /* need to keep FILE objects of stdin, stdout and stderr */
8315 if (rb_cloexec_dup2(fd2, fd) < 0)
8316 rb_sys_fail_path(orig->pathv);
8317 rb_update_max_fd(fd);
8319 else {
8320 fclose(fptr->stdio_file);
8321 fptr->stdio_file = 0;
8322 fptr->fd = -1;
8323 if (rb_cloexec_dup2(fd2, fd) < 0)
8324 rb_sys_fail_path(orig->pathv);
8325 rb_update_max_fd(fd);
8326 fptr->fd = fd;
8328 rb_thread_fd_close(fd);
8329 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8330 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8331 rb_sys_fail_path(fptr->pathv);
8333 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8334 rb_sys_fail_path(orig->pathv);
8339 if (fptr->mode & FMODE_BINMODE) {
8340 rb_io_binmode(io);
8343 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8344 return io;
8347 #ifdef _WIN32
8348 int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8349 #else
8350 static int
8351 rb_freopen(VALUE fname, const char *mode, FILE *fp)
8353 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8354 RB_GC_GUARD(fname);
8355 return errno;
8357 return 0;
8359 #endif
8362 * call-seq:
8363 * reopen(other_io) -> self
8364 * reopen(path, mode = 'r', **opts) -> self
8366 * Reassociates the stream with another stream,
8367 * which may be of a different class.
8368 * This method may be used to redirect an existing stream
8369 * to a new destination.
8371 * With argument +other_io+ given, reassociates with that stream:
8373 * # Redirect $stdin from a file.
8374 * f = File.open('t.txt')
8375 * $stdin.reopen(f)
8376 * f.close
8378 * # Redirect $stdout to a file.
8379 * f = File.open('t.tmp', 'w')
8380 * $stdout.reopen(f)
8381 * f.close
8383 * With argument +path+ given, reassociates with a new stream to that file path:
8385 * $stdin.reopen('t.txt')
8386 * $stdout.reopen('t.tmp', 'w')
8388 * Optional keyword arguments +opts+ specify:
8390 * - {Open Options}[rdoc-ref:IO@Open+Options].
8391 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8395 static VALUE
8396 rb_io_reopen(int argc, VALUE *argv, VALUE file)
8398 VALUE fname, nmode, opt;
8399 int oflags;
8400 rb_io_t *fptr;
8402 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8403 VALUE tmp = rb_io_check_io(fname);
8404 if (!NIL_P(tmp)) {
8405 return io_reopen(file, tmp);
8409 FilePathValue(fname);
8410 rb_io_taint_check(file);
8411 fptr = RFILE(file)->fptr;
8412 if (!fptr) {
8413 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8416 if (!NIL_P(nmode) || !NIL_P(opt)) {
8417 int fmode;
8418 struct rb_io_encoding convconfig;
8420 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8421 if (RUBY_IO_EXTERNAL_P(fptr) &&
8422 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8423 (fptr->mode & FMODE_READWRITE)) {
8424 rb_raise(rb_eArgError,
8425 "%s can't change access mode from \"%s\" to \"%s\"",
8426 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8427 rb_io_fmode_modestr(fmode));
8429 fptr->mode = fmode;
8430 fptr->encs = convconfig;
8432 else {
8433 oflags = rb_io_fmode_oflags(fptr->mode);
8436 fptr->pathv = fname;
8437 if (fptr->fd < 0) {
8438 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8439 fptr->stdio_file = 0;
8440 return file;
8443 if (fptr->mode & FMODE_WRITABLE) {
8444 if (io_fflush(fptr) < 0)
8445 rb_sys_fail_on_write(fptr);
8447 fptr->rbuf.off = fptr->rbuf.len = 0;
8449 if (fptr->stdio_file) {
8450 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8451 rb_io_oflags_modestr(oflags),
8452 fptr->stdio_file);
8453 if (e) rb_syserr_fail_path(e, fptr->pathv);
8454 fptr->fd = fileno(fptr->stdio_file);
8455 rb_fd_fix_cloexec(fptr->fd);
8456 #ifdef USE_SETVBUF
8457 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8458 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8459 #endif
8460 if (fptr->stdio_file == stderr) {
8461 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8462 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8464 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8465 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8466 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8469 else {
8470 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8471 int err = 0;
8472 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8473 err = errno;
8474 (void)close(tmpfd);
8475 if (err) {
8476 rb_syserr_fail_path(err, fptr->pathv);
8480 return file;
8483 /* :nodoc: */
8484 static VALUE
8485 rb_io_init_copy(VALUE dest, VALUE io)
8487 rb_io_t *fptr, *orig;
8488 int fd;
8489 VALUE write_io;
8490 rb_off_t pos;
8492 io = rb_io_get_io(io);
8493 if (!OBJ_INIT_COPY(dest, io)) return dest;
8494 GetOpenFile(io, orig);
8495 MakeOpenFile(dest, fptr);
8497 rb_io_flush(io);
8499 /* copy rb_io_t structure */
8500 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8501 fptr->encs = orig->encs;
8502 fptr->pid = orig->pid;
8503 fptr->lineno = orig->lineno;
8504 fptr->timeout = orig->timeout;
8505 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8506 fptr_copy_finalizer(fptr, orig);
8508 fd = ruby_dup(orig->fd);
8509 fptr->fd = fd;
8510 pos = io_tell(orig);
8511 if (0 <= pos)
8512 io_seek(fptr, pos, SEEK_SET);
8513 if (fptr->mode & FMODE_BINMODE) {
8514 rb_io_binmode(dest);
8517 write_io = GetWriteIO(io);
8518 if (io != write_io) {
8519 write_io = rb_obj_dup(write_io);
8520 fptr->tied_io_for_writing = write_io;
8521 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8524 return dest;
8528 * call-seq:
8529 * printf(format_string, *objects) -> nil
8531 * Formats and writes +objects+ to the stream.
8533 * For details on +format_string+, see
8534 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8538 VALUE
8539 rb_io_printf(int argc, const VALUE *argv, VALUE out)
8541 rb_io_write(out, rb_f_sprintf(argc, argv));
8542 return Qnil;
8546 * call-seq:
8547 * printf(format_string, *objects) -> nil
8548 * printf(io, format_string, *objects) -> nil
8550 * Equivalent to:
8552 * io.write(sprintf(format_string, *objects))
8554 * For details on +format_string+, see
8555 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8557 * With the single argument +format_string+, formats +objects+ into the string,
8558 * then writes the formatted string to $stdout:
8560 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8562 * Output (on $stdout):
8564 * 0024 24 24.00#
8566 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8567 * then writes the formatted string to +io+:
8569 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8571 * Output (on $stderr):
8573 * 0024 24 24.00# => nil
8575 * With no arguments, does nothing.
8579 static VALUE
8580 rb_f_printf(int argc, VALUE *argv, VALUE _)
8582 VALUE out;
8584 if (argc == 0) return Qnil;
8585 if (RB_TYPE_P(argv[0], T_STRING)) {
8586 out = rb_ractor_stdout();
8588 else {
8589 out = argv[0];
8590 argv++;
8591 argc--;
8593 rb_io_write(out, rb_f_sprintf(argc, argv));
8595 return Qnil;
8598 static void
8599 deprecated_str_setter(VALUE val, ID id, VALUE *var)
8601 rb_str_setter(val, id, &val);
8602 if (!NIL_P(val)) {
8603 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8605 *var = val;
8609 * call-seq:
8610 * print(*objects) -> nil
8612 * Writes the given objects to the stream; returns +nil+.
8613 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8614 * (<tt>$\\</tt>), if it is not +nil+.
8615 * See {Line IO}[rdoc-ref:IO@Line+IO].
8617 * With argument +objects+ given, for each object:
8619 * - Converts via its method +to_s+ if not a string.
8620 * - Writes to the stream.
8621 * - If not the last object, writes the output field separator
8622 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8624 * With default separators:
8626 * f = File.open('t.tmp', 'w+')
8627 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8628 * p $OUTPUT_RECORD_SEPARATOR
8629 * p $OUTPUT_FIELD_SEPARATOR
8630 * f.print(*objects)
8631 * f.rewind
8632 * p f.read
8633 * f.close
8635 * Output:
8637 * nil
8638 * nil
8639 * "00.00/10+0izerozero"
8641 * With specified separators:
8643 * $\ = "\n"
8644 * $, = ','
8645 * f.rewind
8646 * f.print(*objects)
8647 * f.rewind
8648 * p f.read
8650 * Output:
8652 * "0,0.0,0/1,0+0i,zero,zero\n"
8654 * With no argument given, writes the content of <tt>$_</tt>
8655 * (which is usually the most recent user input):
8657 * f = File.open('t.tmp', 'w+')
8658 * gets # Sets $_ to the most recent user input.
8659 * f.print
8660 * f.close
8664 VALUE
8665 rb_io_print(int argc, const VALUE *argv, VALUE out)
8667 int i;
8668 VALUE line;
8670 /* if no argument given, print `$_' */
8671 if (argc == 0) {
8672 argc = 1;
8673 line = rb_lastline_get();
8674 argv = &line;
8676 if (argc > 1 && !NIL_P(rb_output_fs)) {
8677 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8679 for (i=0; i<argc; i++) {
8680 if (!NIL_P(rb_output_fs) && i>0) {
8681 rb_io_write(out, rb_output_fs);
8683 rb_io_write(out, argv[i]);
8685 if (argc > 0 && !NIL_P(rb_output_rs)) {
8686 rb_io_write(out, rb_output_rs);
8689 return Qnil;
8693 * call-seq:
8694 * print(*objects) -> nil
8696 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8697 * this method is the straightforward way to write to <tt>$stdout</tt>.
8699 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8700 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8701 * <tt>$\\</tt>), if it is not +nil+.
8703 * With argument +objects+ given, for each object:
8705 * - Converts via its method +to_s+ if not a string.
8706 * - Writes to <tt>stdout</tt>.
8707 * - If not the last object, writes the output field separator
8708 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8710 * With default separators:
8712 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8713 * $OUTPUT_RECORD_SEPARATOR
8714 * $OUTPUT_FIELD_SEPARATOR
8715 * print(*objects)
8717 * Output:
8719 * nil
8720 * nil
8721 * 00.00/10+0izerozero
8723 * With specified separators:
8725 * $OUTPUT_RECORD_SEPARATOR = "\n"
8726 * $OUTPUT_FIELD_SEPARATOR = ','
8727 * print(*objects)
8729 * Output:
8731 * 0,0.0,0/1,0+0i,zero,zero
8733 * With no argument given, writes the content of <tt>$_</tt>
8734 * (which is usually the most recent user input):
8736 * gets # Sets $_ to the most recent user input.
8737 * print # Prints $_.
8741 static VALUE
8742 rb_f_print(int argc, const VALUE *argv, VALUE _)
8744 rb_io_print(argc, argv, rb_ractor_stdout());
8745 return Qnil;
8749 * call-seq:
8750 * putc(object) -> object
8752 * Writes a character to the stream.
8753 * See {Character IO}[rdoc-ref:IO@Character+IO].
8755 * If +object+ is numeric, converts to integer if necessary,
8756 * then writes the character whose code is the
8757 * least significant byte;
8758 * if +object+ is a string, writes the first character:
8760 * $stdout.putc "A"
8761 * $stdout.putc 65
8763 * Output:
8765 * AA
8769 static VALUE
8770 rb_io_putc(VALUE io, VALUE ch)
8772 VALUE str;
8773 if (RB_TYPE_P(ch, T_STRING)) {
8774 str = rb_str_substr(ch, 0, 1);
8776 else {
8777 char c = NUM2CHR(ch);
8778 str = rb_str_new(&c, 1);
8780 rb_io_write(io, str);
8781 return ch;
8784 #define forward(obj, id, argc, argv) \
8785 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8786 #define forward_public(obj, id, argc, argv) \
8787 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8788 #define forward_current(id, argc, argv) \
8789 forward_public(ARGF.current_file, id, argc, argv)
8792 * call-seq:
8793 * putc(int) -> int
8795 * Equivalent to:
8797 * $stdout.putc(int)
8799 * See IO#putc for important information regarding multi-byte characters.
8803 static VALUE
8804 rb_f_putc(VALUE recv, VALUE ch)
8806 VALUE r_stdout = rb_ractor_stdout();
8807 if (recv == r_stdout) {
8808 return rb_io_putc(recv, ch);
8810 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8815 rb_str_end_with_asciichar(VALUE str, int c)
8817 long len = RSTRING_LEN(str);
8818 const char *ptr = RSTRING_PTR(str);
8819 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8820 int n;
8822 if (len == 0) return 0;
8823 if ((n = rb_enc_mbminlen(enc)) == 1) {
8824 return ptr[len - 1] == c;
8826 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8829 static VALUE
8830 io_puts_ary(VALUE ary, VALUE out, int recur)
8832 VALUE tmp;
8833 long i;
8835 if (recur) {
8836 tmp = rb_str_new2("[...]");
8837 rb_io_puts(1, &tmp, out);
8838 return Qtrue;
8840 ary = rb_check_array_type(ary);
8841 if (NIL_P(ary)) return Qfalse;
8842 for (i=0; i<RARRAY_LEN(ary); i++) {
8843 tmp = RARRAY_AREF(ary, i);
8844 rb_io_puts(1, &tmp, out);
8846 return Qtrue;
8850 * call-seq:
8851 * puts(*objects) -> nil
8853 * Writes the given +objects+ to the stream, which must be open for writing;
8854 * returns +nil+.\
8855 * Writes a newline after each that does not already end with a newline sequence.
8856 * If called without arguments, writes a newline.
8857 * See {Line IO}[rdoc-ref:IO@Line+IO].
8859 * Note that each added newline is the character <tt>"\n"<//tt>,
8860 * not the output record separator (<tt>$\\</tt>).
8862 * Treatment for each object:
8864 * - String: writes the string.
8865 * - Neither string nor array: writes <tt>object.to_s</tt>.
8866 * - Array: writes each element of the array; arrays may be nested.
8868 * To keep these examples brief, we define this helper method:
8870 * def show(*objects)
8871 * # Puts objects to file.
8872 * f = File.new('t.tmp', 'w+')
8873 * f.puts(objects)
8874 * # Return file content.
8875 * f.rewind
8876 * p f.read
8877 * f.close
8878 * end
8880 * # Strings without newlines.
8881 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8882 * # Strings, some with newlines.
8883 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8885 * # Neither strings nor arrays:
8886 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8887 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8889 * # Array of strings.
8890 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8891 * # Nested arrays.
8892 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8896 VALUE
8897 rb_io_puts(int argc, const VALUE *argv, VALUE out)
8899 VALUE line, args[2];
8901 /* if no argument given, print newline. */
8902 if (argc == 0) {
8903 rb_io_write(out, rb_default_rs);
8904 return Qnil;
8906 for (int i = 0; i < argc; i++) {
8907 // Convert the argument to a string:
8908 if (RB_TYPE_P(argv[i], T_STRING)) {
8909 line = argv[i];
8911 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8912 continue;
8914 else {
8915 line = rb_obj_as_string(argv[i]);
8918 // Write the line:
8919 int n = 0;
8920 if (RSTRING_LEN(line) == 0) {
8921 args[n++] = rb_default_rs;
8923 else {
8924 args[n++] = line;
8925 if (!rb_str_end_with_asciichar(line, '\n')) {
8926 args[n++] = rb_default_rs;
8930 rb_io_writev(out, n, args);
8933 return Qnil;
8937 * call-seq:
8938 * puts(*objects) -> nil
8940 * Equivalent to
8942 * $stdout.puts(objects)
8945 static VALUE
8946 rb_f_puts(int argc, VALUE *argv, VALUE recv)
8948 VALUE r_stdout = rb_ractor_stdout();
8949 if (recv == r_stdout) {
8950 return rb_io_puts(argc, argv, recv);
8952 return forward(r_stdout, rb_intern("puts"), argc, argv);
8955 static VALUE
8956 rb_p_write(VALUE str)
8958 VALUE args[2];
8959 args[0] = str;
8960 args[1] = rb_default_rs;
8961 VALUE r_stdout = rb_ractor_stdout();
8962 if (RB_TYPE_P(r_stdout, T_FILE) &&
8963 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
8964 io_writev(2, args, r_stdout);
8966 else {
8967 rb_io_writev(r_stdout, 2, args);
8969 return Qnil;
8972 void
8973 rb_p(VALUE obj) /* for debug print within C code */
8975 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
8978 static VALUE
8979 rb_p_result(int argc, const VALUE *argv)
8981 VALUE ret = Qnil;
8983 if (argc == 1) {
8984 ret = argv[0];
8986 else if (argc > 1) {
8987 ret = rb_ary_new4(argc, argv);
8989 VALUE r_stdout = rb_ractor_stdout();
8990 if (RB_TYPE_P(r_stdout, T_FILE)) {
8991 rb_uninterruptible(rb_io_flush, r_stdout);
8993 return ret;
8997 * call-seq:
8998 * p(object) -> obj
8999 * p(*objects) -> array of objects
9000 * p -> nil
9002 * For each object +obj+, executes:
9004 * $stdout.write(obj.inspect, "\n")
9006 * With one object given, returns the object;
9007 * with multiple objects given, returns an array containing the objects;
9008 * with no object given, returns +nil+.
9010 * Examples:
9012 * r = Range.new(0, 4)
9013 * p r # => 0..4
9014 * p [r, r, r] # => [0..4, 0..4, 0..4]
9015 * p # => nil
9017 * Output:
9019 * 0..4
9020 * [0..4, 0..4, 0..4]
9022 * Kernel#p is designed for debugging purposes.
9023 * Ruby implementations may define Kernel#p to be uninterruptible
9024 * in whole or in part.
9025 * On CRuby, Kernel#p's writing of data is uninterruptible.
9028 static VALUE
9029 rb_f_p(int argc, VALUE *argv, VALUE self)
9031 int i;
9032 for (i=0; i<argc; i++) {
9033 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9034 rb_uninterruptible(rb_p_write, inspected);
9036 return rb_p_result(argc, argv);
9040 * call-seq:
9041 * display(port = $>) -> nil
9043 * Writes +self+ on the given port:
9045 * 1.display
9046 * "cat".display
9047 * [ 4, 5, 6 ].display
9048 * puts
9050 * Output:
9052 * 1cat[4, 5, 6]
9056 static VALUE
9057 rb_obj_display(int argc, VALUE *argv, VALUE self)
9059 VALUE out;
9061 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9062 rb_io_write(out, self);
9064 return Qnil;
9067 static int
9068 rb_stderr_to_original_p(VALUE err)
9070 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9073 void
9074 rb_write_error2(const char *mesg, long len)
9076 VALUE out = rb_ractor_stderr();
9077 if (rb_stderr_to_original_p(out)) {
9078 #ifdef _WIN32
9079 if (isatty(fileno(stderr))) {
9080 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9082 #endif
9083 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9084 /* failed to write to stderr, what can we do? */
9085 return;
9088 else {
9089 rb_io_write(out, rb_str_new(mesg, len));
9093 void
9094 rb_write_error(const char *mesg)
9096 rb_write_error2(mesg, strlen(mesg));
9099 void
9100 rb_write_error_str(VALUE mesg)
9102 VALUE out = rb_ractor_stderr();
9103 /* a stopgap measure for the time being */
9104 if (rb_stderr_to_original_p(out)) {
9105 size_t len = (size_t)RSTRING_LEN(mesg);
9106 #ifdef _WIN32
9107 if (isatty(fileno(stderr))) {
9108 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9110 #endif
9111 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9112 RB_GC_GUARD(mesg);
9113 return;
9116 else {
9117 /* may unlock GVL, and */
9118 rb_io_write(out, mesg);
9123 rb_stderr_tty_p(void)
9125 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9126 return isatty(fileno(stderr));
9127 return 0;
9130 static void
9131 must_respond_to(ID mid, VALUE val, ID id)
9133 if (!rb_respond_to(val, mid)) {
9134 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9135 rb_id2str(id), rb_id2str(mid),
9136 rb_obj_class(val));
9140 static void
9141 stdin_setter(VALUE val, ID id, VALUE *ptr)
9143 rb_ractor_stdin_set(val);
9146 static VALUE
9147 stdin_getter(ID id, VALUE *ptr)
9149 return rb_ractor_stdin();
9152 static void
9153 stdout_setter(VALUE val, ID id, VALUE *ptr)
9155 must_respond_to(id_write, val, id);
9156 rb_ractor_stdout_set(val);
9159 static VALUE
9160 stdout_getter(ID id, VALUE *ptr)
9162 return rb_ractor_stdout();
9165 static void
9166 stderr_setter(VALUE val, ID id, VALUE *ptr)
9168 must_respond_to(id_write, val, id);
9169 rb_ractor_stderr_set(val);
9172 static VALUE
9173 stderr_getter(ID id, VALUE *ptr)
9175 return rb_ractor_stderr();
9178 static VALUE
9179 allocate_and_open_new_file(VALUE klass)
9181 VALUE self = io_alloc(klass);
9182 rb_io_make_open_file(self);
9183 return self;
9186 VALUE
9187 rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9189 int state;
9190 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9191 if (state) {
9192 /* if we raised an exception allocating an IO object, but the caller
9193 intended to transfer ownership of this FD to us, close the fd before
9194 raising the exception. Otherwise, we would leak a FD - the caller
9195 expects GC to close the file, but we never got around to assigning
9196 it to a rb_io. */
9197 if (!(mode & FMODE_EXTERNAL)) {
9198 maygvl_close(descriptor, 0);
9200 rb_jump_tag(state);
9204 rb_io_t *io = RFILE(self)->fptr;
9205 io->self = self;
9206 io->fd = descriptor;
9207 io->mode = mode;
9209 /* At this point, Ruby fully owns the descriptor, and will close it when
9210 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9211 in the rest of this method. */
9213 if (NIL_P(path)) {
9214 io->pathv = Qnil;
9216 else {
9217 StringValue(path);
9218 io->pathv = rb_str_new_frozen(path);
9221 io->timeout = timeout;
9223 if (encoding) {
9224 io->encs = *encoding;
9227 rb_update_max_fd(descriptor);
9229 return self;
9232 static VALUE
9233 prep_io(int fd, int fmode, VALUE klass, const char *path)
9235 VALUE path_value = Qnil;
9236 rb_encoding *e;
9237 struct rb_io_encoding convconfig;
9239 if (path) {
9240 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9243 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9244 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9245 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9246 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
9247 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
9248 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9249 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9250 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9251 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9252 #endif
9253 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9254 convconfig.ecopts = Qnil;
9256 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9257 rb_io_t*io = RFILE(self)->fptr;
9259 if (!io_check_tty(io)) {
9260 #ifdef __CYGWIN__
9261 io->mode |= FMODE_BINMODE;
9262 setmode(fd, O_BINARY);
9263 #endif
9266 return self;
9269 VALUE
9270 rb_io_fdopen(int fd, int oflags, const char *path)
9272 VALUE klass = rb_cIO;
9274 if (path && strcmp(path, "-")) klass = rb_cFile;
9275 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9278 static VALUE
9279 prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9281 rb_io_t *fptr;
9282 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9284 GetOpenFile(io, fptr);
9285 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
9286 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9287 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9288 if (fmode & FMODE_READABLE) {
9289 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
9291 #endif
9292 fptr->stdio_file = f;
9294 return io;
9297 VALUE
9298 rb_io_prep_stdin(void)
9300 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9303 VALUE
9304 rb_io_prep_stdout(void)
9306 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9309 VALUE
9310 rb_io_prep_stderr(void)
9312 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9315 FILE *
9316 rb_io_stdio_file(rb_io_t *fptr)
9318 if (!fptr->stdio_file) {
9319 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9320 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9322 return fptr->stdio_file;
9325 static inline void
9326 rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9328 buf->ptr = NULL;
9329 buf->off = 0;
9330 buf->len = 0;
9331 buf->capa = 0;
9334 static inline rb_io_t *
9335 rb_io_fptr_new(void)
9337 rb_io_t *fp = ALLOC(rb_io_t);
9338 fp->self = Qnil;
9339 fp->fd = -1;
9340 fp->stdio_file = NULL;
9341 fp->mode = 0;
9342 fp->pid = 0;
9343 fp->lineno = 0;
9344 fp->pathv = Qnil;
9345 fp->finalize = 0;
9346 rb_io_buffer_init(&fp->wbuf);
9347 rb_io_buffer_init(&fp->rbuf);
9348 rb_io_buffer_init(&fp->cbuf);
9349 fp->readconv = NULL;
9350 fp->writeconv = NULL;
9351 fp->writeconv_asciicompat = Qnil;
9352 fp->writeconv_pre_ecflags = 0;
9353 fp->writeconv_pre_ecopts = Qnil;
9354 fp->writeconv_initialized = 0;
9355 fp->tied_io_for_writing = 0;
9356 fp->encs.enc = NULL;
9357 fp->encs.enc2 = NULL;
9358 fp->encs.ecflags = 0;
9359 fp->encs.ecopts = Qnil;
9360 fp->write_lock = Qnil;
9361 fp->timeout = Qnil;
9362 return fp;
9365 rb_io_t *
9366 rb_io_make_open_file(VALUE obj)
9368 rb_io_t *fp = 0;
9370 Check_Type(obj, T_FILE);
9371 if (RFILE(obj)->fptr) {
9372 rb_io_close(obj);
9373 rb_io_fptr_finalize(RFILE(obj)->fptr);
9374 RFILE(obj)->fptr = 0;
9376 fp = rb_io_fptr_new();
9377 fp->self = obj;
9378 RFILE(obj)->fptr = fp;
9379 return fp;
9383 * call-seq:
9384 * IO.new(fd, mode = 'r', **opts) -> io
9386 * Creates and returns a new \IO object (file stream) from a file descriptor.
9388 * \IO.new may be useful for interaction with low-level libraries.
9389 * For higher-level interactions, it may be simpler to create
9390 * the file stream using File.open.
9392 * Argument +fd+ must be a valid file descriptor (integer):
9394 * path = 't.tmp'
9395 * fd = IO.sysopen(path) # => 3
9396 * IO.new(fd) # => #<IO:fd 3>
9398 * The new \IO object does not inherit encoding
9399 * (because the integer file descriptor does not have an encoding):
9401 * fd = IO.sysopen('t.rus', 'rb')
9402 * io = IO.new(fd)
9403 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9405 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9406 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9408 * IO.new(fd, 'w') # => #<IO:fd 3>
9409 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9411 * Optional keyword arguments +opts+ specify:
9413 * - {Open Options}[rdoc-ref:IO@Open+Options].
9414 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9416 * Examples:
9418 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9419 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9423 static VALUE
9424 rb_io_initialize(int argc, VALUE *argv, VALUE io)
9426 VALUE fnum, vmode;
9427 rb_io_t *fp;
9428 int fd, fmode, oflags = O_RDONLY;
9429 struct rb_io_encoding convconfig;
9430 VALUE opt;
9431 #if defined(HAVE_FCNTL) && defined(F_GETFL)
9432 int ofmode;
9433 #else
9434 struct stat st;
9435 #endif
9438 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9439 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9441 fd = NUM2INT(fnum);
9442 if (rb_reserved_fd_p(fd)) {
9443 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9445 #if defined(HAVE_FCNTL) && defined(F_GETFL)
9446 oflags = fcntl(fd, F_GETFL);
9447 if (oflags == -1) rb_sys_fail(0);
9448 #else
9449 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9450 #endif
9451 rb_update_max_fd(fd);
9452 #if defined(HAVE_FCNTL) && defined(F_GETFL)
9453 ofmode = rb_io_oflags_fmode(oflags);
9454 if (NIL_P(vmode)) {
9455 fmode = ofmode;
9457 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9458 VALUE error = INT2FIX(EINVAL);
9459 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
9461 #endif
9462 VALUE path = Qnil;
9464 if (!NIL_P(opt)) {
9465 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9466 fmode |= FMODE_EXTERNAL;
9469 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9470 if (!NIL_P(path)) {
9471 StringValue(path);
9472 path = rb_str_new_frozen(path);
9476 MakeOpenFile(io, fp);
9477 fp->self = io;
9478 fp->fd = fd;
9479 fp->mode = fmode;
9480 fp->encs = convconfig;
9481 fp->pathv = path;
9482 fp->timeout = Qnil;
9483 clear_codeconv(fp);
9484 io_check_tty(fp);
9485 if (fileno(stdin) == fd)
9486 fp->stdio_file = stdin;
9487 else if (fileno(stdout) == fd)
9488 fp->stdio_file = stdout;
9489 else if (fileno(stderr) == fd)
9490 fp->stdio_file = stderr;
9492 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9493 return io;
9497 * call-seq:
9498 * set_encoding_by_bom -> encoding or nil
9500 * If the stream begins with a BOM
9501 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9502 * consumes the BOM and sets the external encoding accordingly;
9503 * returns the result encoding if found, or +nil+ otherwise:
9505 * File.write('t.tmp', "\u{FEFF}abc")
9506 * io = File.open('t.tmp', 'rb')
9507 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9508 * io.close
9510 * File.write('t.tmp', 'abc')
9511 * io = File.open('t.tmp', 'rb')
9512 * io.set_encoding_by_bom # => nil
9513 * io.close
9515 * Raises an exception if the stream is not binmode
9516 * or its encoding has already been set.
9520 static VALUE
9521 rb_io_set_encoding_by_bom(VALUE io)
9523 rb_io_t *fptr;
9525 GetOpenFile(io, fptr);
9526 if (!(fptr->mode & FMODE_BINMODE)) {
9527 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9529 if (fptr->encs.enc2) {
9530 rb_raise(rb_eArgError, "encoding conversion is set");
9532 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9533 rb_raise(rb_eArgError, "encoding is set to %s already",
9534 rb_enc_name(fptr->encs.enc));
9536 if (!io_set_encoding_by_bom(io)) return Qnil;
9537 return rb_enc_from_encoding(fptr->encs.enc);
9541 * call-seq:
9542 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9544 * Opens the file at the given +path+ according to the given +mode+;
9545 * creates and returns a new File object for that file.
9547 * The new File object is buffered mode (or non-sync mode), unless
9548 * +filename+ is a tty.
9549 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9551 * Argument +path+ must be a valid file path:
9553 * f = File.new('/etc/fstab')
9554 * f.close
9555 * f = File.new('t.txt')
9556 * f.close
9558 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9559 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9561 * f = File.new('t.tmp', 'w')
9562 * f.close
9563 * f = File.new('t.tmp', File::RDONLY)
9564 * f.close
9566 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9567 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9569 * f = File.new('t.tmp', File::CREAT, 0644)
9570 * f.close
9571 * f = File.new('t.tmp', File::CREAT, 0444)
9572 * f.close
9574 * Optional keyword arguments +opts+ specify:
9576 * - {Open Options}[rdoc-ref:IO@Open+Options].
9577 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9581 static VALUE
9582 rb_file_initialize(int argc, VALUE *argv, VALUE io)
9584 if (RFILE(io)->fptr) {
9585 rb_raise(rb_eRuntimeError, "reinitializing File");
9587 if (0 < argc && argc < 3) {
9588 VALUE fd = rb_check_to_int(argv[0]);
9590 if (!NIL_P(fd)) {
9591 argv[0] = fd;
9592 return rb_io_initialize(argc, argv, io);
9595 rb_open_file(argc, argv, io);
9597 return io;
9600 /* :nodoc: */
9601 static VALUE
9602 rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9604 if (rb_block_given_p()) {
9605 VALUE cname = rb_obj_as_string(klass);
9607 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9608 cname, cname);
9610 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9615 * call-seq:
9616 * IO.for_fd(fd, mode = 'r', **opts) -> io
9618 * Synonym for IO.new.
9622 static VALUE
9623 rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9625 VALUE io = rb_obj_alloc(klass);
9626 rb_io_initialize(argc, argv, io);
9627 return io;
9631 * call-seq:
9632 * ios.autoclose? -> true or false
9634 * Returns +true+ if the underlying file descriptor of _ios_ will be
9635 * closed at its finalization or at calling #close, otherwise +false+.
9638 static VALUE
9639 rb_io_autoclose_p(VALUE io)
9641 rb_io_t *fptr = RFILE(io)->fptr;
9642 rb_io_check_closed(fptr);
9643 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9647 * call-seq:
9648 * io.autoclose = bool -> true or false
9650 * Sets auto-close flag.
9652 * f = File.open(File::NULL)
9653 * IO.for_fd(f.fileno).close
9654 * f.gets # raises Errno::EBADF
9656 * f = File.open(File::NULL)
9657 * g = IO.for_fd(f.fileno)
9658 * g.autoclose = false
9659 * g.close
9660 * f.gets # won't cause Errno::EBADF
9663 static VALUE
9664 rb_io_set_autoclose(VALUE io, VALUE autoclose)
9666 rb_io_t *fptr;
9667 GetOpenFile(io, fptr);
9668 if (!RTEST(autoclose))
9669 fptr->mode |= FMODE_EXTERNAL;
9670 else
9671 fptr->mode &= ~FMODE_EXTERNAL;
9672 return autoclose;
9675 static VALUE
9676 io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9678 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9680 if (!RB_TEST(result)) {
9681 return Qnil;
9684 int mask = RB_NUM2INT(result);
9686 if (mask & event) {
9687 if (return_io)
9688 return io;
9689 else
9690 return result;
9692 else {
9693 return Qfalse;
9698 * call-seq:
9699 * io.wait_readable -> truthy or falsy
9700 * io.wait_readable(timeout) -> truthy or falsy
9702 * Waits until IO is readable and returns a truthy value, or a falsy
9703 * value when times out. Returns a truthy value immediately when
9704 * buffered data is available.
9707 static VALUE
9708 io_wait_readable(int argc, VALUE *argv, VALUE io)
9710 rb_io_t *fptr;
9712 RB_IO_POINTER(io, fptr);
9713 rb_io_check_readable(fptr);
9715 if (rb_io_read_pending(fptr)) return Qtrue;
9717 rb_check_arity(argc, 0, 1);
9718 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9720 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9724 * call-seq:
9725 * io.wait_writable -> truthy or falsy
9726 * io.wait_writable(timeout) -> truthy or falsy
9728 * Waits until IO is writable and returns a truthy value or a falsy
9729 * value when times out.
9731 static VALUE
9732 io_wait_writable(int argc, VALUE *argv, VALUE io)
9734 rb_io_t *fptr;
9736 RB_IO_POINTER(io, fptr);
9737 rb_io_check_writable(fptr);
9739 rb_check_arity(argc, 0, 1);
9740 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9742 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9746 * call-seq:
9747 * io.wait_priority -> truthy or falsy
9748 * io.wait_priority(timeout) -> truthy or falsy
9750 * Waits until IO is priority and returns a truthy value or a falsy
9751 * value when times out. Priority data is sent and received using
9752 * the Socket::MSG_OOB flag and is typically limited to streams.
9754 static VALUE
9755 io_wait_priority(int argc, VALUE *argv, VALUE io)
9757 rb_io_t *fptr = NULL;
9759 RB_IO_POINTER(io, fptr);
9760 rb_io_check_readable(fptr);
9762 if (rb_io_read_pending(fptr)) return Qtrue;
9764 rb_check_arity(argc, 0, 1);
9765 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9767 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9770 static int
9771 wait_mode_sym(VALUE mode)
9773 if (mode == ID2SYM(rb_intern("r"))) {
9774 return RB_WAITFD_IN;
9776 if (mode == ID2SYM(rb_intern("read"))) {
9777 return RB_WAITFD_IN;
9779 if (mode == ID2SYM(rb_intern("readable"))) {
9780 return RB_WAITFD_IN;
9782 if (mode == ID2SYM(rb_intern("w"))) {
9783 return RB_WAITFD_OUT;
9785 if (mode == ID2SYM(rb_intern("write"))) {
9786 return RB_WAITFD_OUT;
9788 if (mode == ID2SYM(rb_intern("writable"))) {
9789 return RB_WAITFD_OUT;
9791 if (mode == ID2SYM(rb_intern("rw"))) {
9792 return RB_WAITFD_IN|RB_WAITFD_OUT;
9794 if (mode == ID2SYM(rb_intern("read_write"))) {
9795 return RB_WAITFD_IN|RB_WAITFD_OUT;
9797 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9798 return RB_WAITFD_IN|RB_WAITFD_OUT;
9801 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9804 static inline enum rb_io_event
9805 io_event_from_value(VALUE value)
9807 int events = RB_NUM2INT(value);
9809 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9811 return events;
9815 * call-seq:
9816 * io.wait(events, timeout) -> event mask, false or nil
9817 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9819 * Waits until the IO becomes ready for the specified events and returns the
9820 * subset of events that become ready, or a falsy value when times out.
9822 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9823 * +IO::PRIORITY+.
9825 * Returns an event mask (truthy value) immediately when buffered data is available.
9827 * Optional parameter +mode+ is one of +:read+, +:write+, or
9828 * +:read_write+.
9831 static VALUE
9832 io_wait(int argc, VALUE *argv, VALUE io)
9834 VALUE timeout = Qundef;
9835 enum rb_io_event events = 0;
9836 int return_io = 0;
9838 // The documented signature for this method is actually incorrect.
9839 // A single timeout is allowed in any position, and multiple symbols can be given.
9840 // Whether this is intentional or not, I don't know, and as such I consider this to
9841 // be a legacy/slow path.
9842 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9843 // We'd prefer to return the actual mask, but this form would return the io itself:
9844 return_io = 1;
9846 // Slow/messy path:
9847 for (int i = 0; i < argc; i += 1) {
9848 if (RB_SYMBOL_P(argv[i])) {
9849 events |= wait_mode_sym(argv[i]);
9851 else if (UNDEF_P(timeout)) {
9852 rb_time_interval(timeout = argv[i]);
9854 else {
9855 rb_raise(rb_eArgError, "timeout given more than once");
9859 if (UNDEF_P(timeout)) timeout = Qnil;
9861 if (events == 0) {
9862 events = RUBY_IO_READABLE;
9865 else /* argc == 2 and neither are symbols */ {
9866 // This is the fast path:
9867 events = io_event_from_value(argv[0]);
9868 timeout = argv[1];
9871 if (events & RUBY_IO_READABLE) {
9872 rb_io_t *fptr = NULL;
9873 RB_IO_POINTER(io, fptr);
9875 if (rb_io_read_pending(fptr)) {
9876 // This was the original behaviour:
9877 if (return_io) return Qtrue;
9878 // New behaviour always returns an event mask:
9879 else return RB_INT2NUM(RUBY_IO_READABLE);
9883 return io_wait_event(io, events, timeout, return_io);
9886 static void
9887 argf_mark(void *ptr)
9889 struct argf *p = ptr;
9890 rb_gc_mark(p->filename);
9891 rb_gc_mark(p->current_file);
9892 rb_gc_mark(p->argv);
9893 rb_gc_mark(p->inplace);
9894 rb_gc_mark(p->encs.ecopts);
9897 static size_t
9898 argf_memsize(const void *ptr)
9900 const struct argf *p = ptr;
9901 size_t size = sizeof(*p);
9902 return size;
9905 static const rb_data_type_t argf_type = {
9906 "ARGF",
9907 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9908 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9911 static inline void
9912 argf_init(struct argf *p, VALUE v)
9914 p->filename = Qnil;
9915 p->current_file = Qnil;
9916 p->lineno = 0;
9917 p->argv = v;
9920 static VALUE
9921 argf_alloc(VALUE klass)
9923 struct argf *p;
9924 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9926 argf_init(p, Qnil);
9927 return argf;
9930 #undef rb_argv
9932 /* :nodoc: */
9933 static VALUE
9934 argf_initialize(VALUE argf, VALUE argv)
9936 memset(&ARGF, 0, sizeof(ARGF));
9937 argf_init(&ARGF, argv);
9939 return argf;
9942 /* :nodoc: */
9943 static VALUE
9944 argf_initialize_copy(VALUE argf, VALUE orig)
9946 if (!OBJ_INIT_COPY(argf, orig)) return argf;
9947 ARGF = argf_of(orig);
9948 ARGF.argv = rb_obj_dup(ARGF.argv);
9949 return argf;
9953 * call-seq:
9954 * ARGF.lineno = integer -> integer
9956 * Sets the line number of ARGF as a whole to the given Integer.
9958 * ARGF sets the line number automatically as you read data, so normally
9959 * you will not need to set it explicitly. To access the current line number
9960 * use ARGF.lineno.
9962 * For example:
9964 * ARGF.lineno #=> 0
9965 * ARGF.readline #=> "This is line 1\n"
9966 * ARGF.lineno #=> 1
9967 * ARGF.lineno = 0 #=> 0
9968 * ARGF.lineno #=> 0
9970 static VALUE
9971 argf_set_lineno(VALUE argf, VALUE val)
9973 ARGF.lineno = NUM2INT(val);
9974 ARGF.last_lineno = ARGF.lineno;
9975 return val;
9979 * call-seq:
9980 * ARGF.lineno -> integer
9982 * Returns the current line number of ARGF as a whole. This value
9983 * can be set manually with ARGF.lineno=.
9985 * For example:
9987 * ARGF.lineno #=> 0
9988 * ARGF.readline #=> "This is line 1\n"
9989 * ARGF.lineno #=> 1
9991 static VALUE
9992 argf_lineno(VALUE argf)
9994 return INT2FIX(ARGF.lineno);
9997 static VALUE
9998 argf_forward(int argc, VALUE *argv, VALUE argf)
10000 return forward_current(rb_frame_this_func(), argc, argv);
10003 #define next_argv() argf_next_argv(argf)
10004 #define ARGF_GENERIC_INPUT_P() \
10005 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10006 #define ARGF_FORWARD(argc, argv) do {\
10007 if (ARGF_GENERIC_INPUT_P())\
10008 return argf_forward((argc), (argv), argf);\
10009 } while (0)
10010 #define NEXT_ARGF_FORWARD(argc, argv) do {\
10011 if (!next_argv()) return Qnil;\
10012 ARGF_FORWARD((argc), (argv));\
10013 } while (0)
10015 static void
10016 argf_close(VALUE argf)
10018 VALUE file = ARGF.current_file;
10019 if (file == rb_stdin) return;
10020 if (RB_TYPE_P(file, T_FILE)) {
10021 rb_io_set_write_io(file, Qnil);
10023 io_close(file);
10024 ARGF.init_p = -1;
10027 static int
10028 argf_next_argv(VALUE argf)
10030 char *fn;
10031 rb_io_t *fptr;
10032 int stdout_binmode = 0;
10033 int fmode;
10035 VALUE r_stdout = rb_ractor_stdout();
10037 if (RB_TYPE_P(r_stdout, T_FILE)) {
10038 GetOpenFile(r_stdout, fptr);
10039 if (fptr->mode & FMODE_BINMODE)
10040 stdout_binmode = 1;
10043 if (ARGF.init_p == 0) {
10044 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10045 ARGF.next_p = 1;
10047 else {
10048 ARGF.next_p = -1;
10050 ARGF.init_p = 1;
10052 else {
10053 if (NIL_P(ARGF.argv)) {
10054 ARGF.next_p = -1;
10056 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10057 ARGF.next_p = 1;
10061 if (ARGF.next_p == 1) {
10062 if (ARGF.init_p == 1) argf_close(argf);
10063 retry:
10064 if (RARRAY_LEN(ARGF.argv) > 0) {
10065 VALUE filename = rb_ary_shift(ARGF.argv);
10066 FilePathValue(filename);
10067 ARGF.filename = filename;
10068 filename = rb_str_encode_ospath(filename);
10069 fn = StringValueCStr(filename);
10070 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10071 ARGF.current_file = rb_stdin;
10072 if (ARGF.inplace) {
10073 rb_warn("Can't do inplace edit for stdio; skipping");
10074 goto retry;
10077 else {
10078 VALUE write_io = Qnil;
10079 int fr = rb_sysopen(filename, O_RDONLY, 0);
10081 if (ARGF.inplace) {
10082 struct stat st;
10083 #ifndef NO_SAFE_RENAME
10084 struct stat st2;
10085 #endif
10086 VALUE str;
10087 int fw;
10089 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10090 rb_io_close(r_stdout);
10092 fstat(fr, &st);
10093 str = filename;
10094 if (!NIL_P(ARGF.inplace)) {
10095 VALUE suffix = ARGF.inplace;
10096 str = rb_str_dup(str);
10097 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10098 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10099 rb_enc_get(suffix), 0, Qnil))) {
10100 rb_str_append(str, suffix);
10102 #ifdef NO_SAFE_RENAME
10103 (void)close(fr);
10104 (void)unlink(RSTRING_PTR(str));
10105 if (rename(fn, RSTRING_PTR(str)) < 0) {
10106 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10107 filename, str, strerror(errno));
10108 goto retry;
10110 fr = rb_sysopen(str, O_RDONLY, 0);
10111 #else
10112 if (rename(fn, RSTRING_PTR(str)) < 0) {
10113 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10114 filename, str, strerror(errno));
10115 close(fr);
10116 goto retry;
10118 #endif
10120 else {
10121 #ifdef NO_SAFE_RENAME
10122 rb_fatal("Can't do inplace edit without backup");
10123 #else
10124 if (unlink(fn) < 0) {
10125 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10126 filename, strerror(errno));
10127 close(fr);
10128 goto retry;
10130 #endif
10132 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10133 #ifndef NO_SAFE_RENAME
10134 fstat(fw, &st2);
10135 #ifdef HAVE_FCHMOD
10136 fchmod(fw, st.st_mode);
10137 #else
10138 chmod(fn, st.st_mode);
10139 #endif
10140 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10141 int err;
10142 #ifdef HAVE_FCHOWN
10143 err = fchown(fw, st.st_uid, st.st_gid);
10144 #else
10145 err = chown(fn, st.st_uid, st.st_gid);
10146 #endif
10147 if (err && getuid() == 0 && st2.st_uid == 0) {
10148 const char *wkfn = RSTRING_PTR(filename);
10149 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10150 filename, str, strerror(errno));
10151 (void)close(fr);
10152 (void)close(fw);
10153 (void)unlink(wkfn);
10154 goto retry;
10157 #endif
10158 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10159 rb_ractor_stdout_set(write_io);
10160 if (stdout_binmode) rb_io_binmode(rb_stdout);
10162 fmode = FMODE_READABLE;
10163 if (!ARGF.binmode) {
10164 fmode |= DEFAULT_TEXTMODE;
10166 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10167 if (!NIL_P(write_io)) {
10168 rb_io_set_write_io(ARGF.current_file, write_io);
10170 RB_GC_GUARD(filename);
10172 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10173 GetOpenFile(ARGF.current_file, fptr);
10174 if (ARGF.encs.enc) {
10175 fptr->encs = ARGF.encs;
10176 clear_codeconv(fptr);
10178 else {
10179 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10180 if (!ARGF.binmode) {
10181 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
10182 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10183 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10184 #endif
10187 ARGF.next_p = 0;
10189 else {
10190 ARGF.next_p = 1;
10191 return FALSE;
10194 else if (ARGF.next_p == -1) {
10195 ARGF.current_file = rb_stdin;
10196 ARGF.filename = rb_str_new2("-");
10197 if (ARGF.inplace) {
10198 rb_warn("Can't do inplace edit for stdio");
10199 rb_ractor_stdout_set(orig_stdout);
10202 if (ARGF.init_p == -1) ARGF.init_p = 1;
10203 return TRUE;
10206 static VALUE
10207 argf_getline(int argc, VALUE *argv, VALUE argf)
10209 VALUE line;
10210 long lineno = ARGF.lineno;
10212 retry:
10213 if (!next_argv()) return Qnil;
10214 if (ARGF_GENERIC_INPUT_P()) {
10215 line = forward_current(idGets, argc, argv);
10217 else {
10218 if (argc == 0 && rb_rs == rb_default_rs) {
10219 line = rb_io_gets(ARGF.current_file);
10221 else {
10222 line = rb_io_getline(argc, argv, ARGF.current_file);
10224 if (NIL_P(line) && ARGF.next_p != -1) {
10225 argf_close(argf);
10226 ARGF.next_p = 1;
10227 goto retry;
10230 if (!NIL_P(line)) {
10231 ARGF.lineno = ++lineno;
10232 ARGF.last_lineno = ARGF.lineno;
10234 return line;
10237 static VALUE
10238 argf_lineno_getter(ID id, VALUE *var)
10240 VALUE argf = *var;
10241 return INT2FIX(ARGF.last_lineno);
10244 static void
10245 argf_lineno_setter(VALUE val, ID id, VALUE *var)
10247 VALUE argf = *var;
10248 int n = NUM2INT(val);
10249 ARGF.last_lineno = ARGF.lineno = n;
10252 void
10253 rb_reset_argf_lineno(long n)
10255 ARGF.last_lineno = ARGF.lineno = n;
10258 static VALUE argf_gets(int, VALUE *, VALUE);
10261 * call-seq:
10262 * gets(sep=$/ [, getline_args]) -> string or nil
10263 * gets(limit [, getline_args]) -> string or nil
10264 * gets(sep, limit [, getline_args]) -> string or nil
10266 * Returns (and assigns to <code>$_</code>) the next line from the list
10267 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10268 * no files are present on the command line. Returns +nil+ at end of
10269 * file. The optional argument specifies the record separator. The
10270 * separator is included with the contents of each record. A separator
10271 * of +nil+ reads the entire contents, and a zero-length separator
10272 * reads the input one paragraph at a time, where paragraphs are
10273 * divided by two consecutive newlines. If the first argument is an
10274 * integer, or optional second argument is given, the returning string
10275 * would not be longer than the given value in bytes. If multiple
10276 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10277 * the contents one file at a time.
10279 * ARGV << "testfile"
10280 * print while gets
10282 * <em>produces:</em>
10284 * This is line one
10285 * This is line two
10286 * This is line three
10287 * And so on...
10289 * The style of programming using <code>$_</code> as an implicit
10290 * parameter is gradually losing favor in the Ruby community.
10293 static VALUE
10294 rb_f_gets(int argc, VALUE *argv, VALUE recv)
10296 if (recv == argf) {
10297 return argf_gets(argc, argv, argf);
10299 return forward(argf, idGets, argc, argv);
10303 * call-seq:
10304 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10305 * ARGF.gets(limit [, getline_args]) -> string or nil
10306 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10308 * Returns the next line from the current file in ARGF.
10310 * By default lines are assumed to be separated by <code>$/</code>;
10311 * to use a different character as a separator, supply it as a String
10312 * for the _sep_ argument.
10314 * The optional _limit_ argument specifies how many characters of each line
10315 * to return. By default all characters are returned.
10317 * See IO.readlines for details about getline_args.
10320 static VALUE
10321 argf_gets(int argc, VALUE *argv, VALUE argf)
10323 VALUE line;
10325 line = argf_getline(argc, argv, argf);
10326 rb_lastline_set(line);
10328 return line;
10331 VALUE
10332 rb_gets(void)
10334 VALUE line;
10336 if (rb_rs != rb_default_rs) {
10337 return rb_f_gets(0, 0, argf);
10340 retry:
10341 if (!next_argv()) return Qnil;
10342 line = rb_io_gets(ARGF.current_file);
10343 if (NIL_P(line) && ARGF.next_p != -1) {
10344 rb_io_close(ARGF.current_file);
10345 ARGF.next_p = 1;
10346 goto retry;
10348 rb_lastline_set(line);
10349 if (!NIL_P(line)) {
10350 ARGF.lineno++;
10351 ARGF.last_lineno = ARGF.lineno;
10354 return line;
10357 static VALUE argf_readline(int, VALUE *, VALUE);
10360 * call-seq:
10361 * readline(sep = $/, chomp: false) -> string
10362 * readline(limit, chomp: false) -> string
10363 * readline(sep, limit, chomp: false) -> string
10365 * Equivalent to method Kernel#gets, except that it raises an exception
10366 * if called at end-of-stream:
10368 * $ cat t.txt | ruby -e "p readlines; readline"
10369 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10370 * in `readline': end of file reached (EOFError)
10372 * Optional keyword argument +chomp+ specifies whether line separators
10373 * are to be omitted.
10376 static VALUE
10377 rb_f_readline(int argc, VALUE *argv, VALUE recv)
10379 if (recv == argf) {
10380 return argf_readline(argc, argv, argf);
10382 return forward(argf, rb_intern("readline"), argc, argv);
10387 * call-seq:
10388 * ARGF.readline(sep=$/) -> string
10389 * ARGF.readline(limit) -> string
10390 * ARGF.readline(sep, limit) -> string
10392 * Returns the next line from the current file in ARGF.
10394 * By default lines are assumed to be separated by <code>$/</code>;
10395 * to use a different character as a separator, supply it as a String
10396 * for the _sep_ argument.
10398 * The optional _limit_ argument specifies how many characters of each line
10399 * to return. By default all characters are returned.
10401 * An EOFError is raised at the end of the file.
10403 static VALUE
10404 argf_readline(int argc, VALUE *argv, VALUE argf)
10406 VALUE line;
10408 if (!next_argv()) rb_eof_error();
10409 ARGF_FORWARD(argc, argv);
10410 line = argf_gets(argc, argv, argf);
10411 if (NIL_P(line)) {
10412 rb_eof_error();
10415 return line;
10418 static VALUE argf_readlines(int, VALUE *, VALUE);
10421 * call-seq:
10422 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10423 * readlines(limit, chomp: false, **enc_opts) -> array
10424 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10426 * Returns an array containing the lines returned by calling
10427 * Kernel#gets until the end-of-stream is reached;
10428 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10430 * With only string argument +sep+ given,
10431 * returns the remaining lines as determined by line separator +sep+,
10432 * or +nil+ if none;
10433 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10435 * # Default separator.
10436 * $ cat t.txt | ruby -e "p readlines"
10437 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10439 * # Specified separator.
10440 * $ cat t.txt | ruby -e "p readlines 'li'"
10441 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10443 * # Get-all separator.
10444 * $ cat t.txt | ruby -e "p readlines nil"
10445 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10447 * # Get-paragraph separator.
10448 * $ cat t.txt | ruby -e "p readlines ''"
10449 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10451 * With only integer argument +limit+ given,
10452 * limits the number of bytes in the line;
10453 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10455 * $cat t.txt | ruby -e "p readlines 10"
10456 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10458 * $cat t.txt | ruby -e "p readlines 11"
10459 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10461 * $cat t.txt | ruby -e "p readlines 12"
10462 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10464 * With arguments +sep+ and +limit+ given,
10465 * combines the two behaviors
10466 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10468 * Optional keyword argument +chomp+ specifies whether line separators
10469 * are to be omitted:
10471 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10472 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10474 * Optional keyword arguments +enc_opts+ specify encoding options;
10475 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10479 static VALUE
10480 rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10482 if (recv == argf) {
10483 return argf_readlines(argc, argv, argf);
10485 return forward(argf, rb_intern("readlines"), argc, argv);
10489 * call-seq:
10490 * ARGF.readlines(sep = $/, chomp: false) -> array
10491 * ARGF.readlines(limit, chomp: false) -> array
10492 * ARGF.readlines(sep, limit, chomp: false) -> array
10494 * ARGF.to_a(sep = $/, chomp: false) -> array
10495 * ARGF.to_a(limit, chomp: false) -> array
10496 * ARGF.to_a(sep, limit, chomp: false) -> array
10498 * Reads each file in ARGF in its entirety, returning an Array containing
10499 * lines from the files. Lines are assumed to be separated by _sep_.
10501 * lines = ARGF.readlines
10502 * lines[0] #=> "This is line one\n"
10504 * See +IO.readlines+ for a full description of all options.
10506 static VALUE
10507 argf_readlines(int argc, VALUE *argv, VALUE argf)
10509 long lineno = ARGF.lineno;
10510 VALUE lines, ary;
10512 ary = rb_ary_new();
10513 while (next_argv()) {
10514 if (ARGF_GENERIC_INPUT_P()) {
10515 lines = forward_current(rb_intern("readlines"), argc, argv);
10517 else {
10518 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10519 argf_close(argf);
10521 ARGF.next_p = 1;
10522 rb_ary_concat(ary, lines);
10523 ARGF.lineno = lineno + RARRAY_LEN(ary);
10524 ARGF.last_lineno = ARGF.lineno;
10526 ARGF.init_p = 0;
10527 return ary;
10531 * call-seq:
10532 * `command` -> string
10534 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10535 * sets global variable <tt>$?</tt> to the process status.
10537 * This method has potential security vulnerabilities if called with untrusted input;
10538 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10540 * Examples:
10542 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10543 * $ `echo oops && exit 99` # => "oops\n"
10544 * $ $? # => #<Process::Status: pid 17088 exit 99>
10545 * $ $?.status # => 99>
10547 * The built-in syntax <tt>%x{...}</tt> uses this method.
10551 static VALUE
10552 rb_f_backquote(VALUE obj, VALUE str)
10554 VALUE port;
10555 VALUE result;
10556 rb_io_t *fptr;
10558 StringValue(str);
10559 rb_last_status_clear();
10560 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10561 if (NIL_P(port)) return rb_str_new(0,0);
10563 GetOpenFile(port, fptr);
10564 result = read_all(fptr, remain_size(fptr), Qnil);
10565 rb_io_close(port);
10566 rb_io_fptr_cleanup_all(fptr);
10567 RB_GC_GUARD(port);
10569 return result;
10572 #ifdef HAVE_SYS_SELECT_H
10573 #include <sys/select.h>
10574 #endif
10576 static VALUE
10577 select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10579 VALUE res, list;
10580 rb_fdset_t *rp, *wp, *ep;
10581 rb_io_t *fptr;
10582 long i;
10583 int max = 0, n;
10584 int pending = 0;
10585 struct timeval timerec;
10587 if (!NIL_P(read)) {
10588 Check_Type(read, T_ARRAY);
10589 for (i=0; i<RARRAY_LEN(read); i++) {
10590 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10591 rb_fd_set(fptr->fd, &fds[0]);
10592 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10593 pending++;
10594 rb_fd_set(fptr->fd, &fds[3]);
10596 if (max < fptr->fd) max = fptr->fd;
10598 if (pending) { /* no blocking if there's buffered data */
10599 timerec.tv_sec = timerec.tv_usec = 0;
10600 tp = &timerec;
10602 rp = &fds[0];
10604 else
10605 rp = 0;
10607 if (!NIL_P(write)) {
10608 Check_Type(write, T_ARRAY);
10609 for (i=0; i<RARRAY_LEN(write); i++) {
10610 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10611 GetOpenFile(write_io, fptr);
10612 rb_fd_set(fptr->fd, &fds[1]);
10613 if (max < fptr->fd) max = fptr->fd;
10615 wp = &fds[1];
10617 else
10618 wp = 0;
10620 if (!NIL_P(except)) {
10621 Check_Type(except, T_ARRAY);
10622 for (i=0; i<RARRAY_LEN(except); i++) {
10623 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10624 VALUE write_io = GetWriteIO(io);
10625 GetOpenFile(io, fptr);
10626 rb_fd_set(fptr->fd, &fds[2]);
10627 if (max < fptr->fd) max = fptr->fd;
10628 if (io != write_io) {
10629 GetOpenFile(write_io, fptr);
10630 rb_fd_set(fptr->fd, &fds[2]);
10631 if (max < fptr->fd) max = fptr->fd;
10634 ep = &fds[2];
10636 else {
10637 ep = 0;
10640 max++;
10642 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10643 if (n < 0) {
10644 rb_sys_fail(0);
10646 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10648 res = rb_ary_new2(3);
10649 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10650 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10651 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10653 if (rp) {
10654 list = RARRAY_AREF(res, 0);
10655 for (i=0; i< RARRAY_LEN(read); i++) {
10656 VALUE obj = rb_ary_entry(read, i);
10657 VALUE io = rb_io_get_io(obj);
10658 GetOpenFile(io, fptr);
10659 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10660 rb_fd_isset(fptr->fd, &fds[3])) {
10661 rb_ary_push(list, obj);
10666 if (wp) {
10667 list = RARRAY_AREF(res, 1);
10668 for (i=0; i< RARRAY_LEN(write); i++) {
10669 VALUE obj = rb_ary_entry(write, i);
10670 VALUE io = rb_io_get_io(obj);
10671 VALUE write_io = GetWriteIO(io);
10672 GetOpenFile(write_io, fptr);
10673 if (rb_fd_isset(fptr->fd, &fds[1])) {
10674 rb_ary_push(list, obj);
10679 if (ep) {
10680 list = RARRAY_AREF(res, 2);
10681 for (i=0; i< RARRAY_LEN(except); i++) {
10682 VALUE obj = rb_ary_entry(except, i);
10683 VALUE io = rb_io_get_io(obj);
10684 VALUE write_io = GetWriteIO(io);
10685 GetOpenFile(io, fptr);
10686 if (rb_fd_isset(fptr->fd, &fds[2])) {
10687 rb_ary_push(list, obj);
10689 else if (io != write_io) {
10690 GetOpenFile(write_io, fptr);
10691 if (rb_fd_isset(fptr->fd, &fds[2])) {
10692 rb_ary_push(list, obj);
10698 return res; /* returns an empty array on interrupt */
10701 struct select_args {
10702 VALUE read, write, except;
10703 struct timeval *timeout;
10704 rb_fdset_t fdsets[4];
10707 static VALUE
10708 select_call(VALUE arg)
10710 struct select_args *p = (struct select_args *)arg;
10712 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10715 static VALUE
10716 select_end(VALUE arg)
10718 struct select_args *p = (struct select_args *)arg;
10719 int i;
10721 for (i = 0; i < numberof(p->fdsets); ++i)
10722 rb_fd_term(&p->fdsets[i]);
10723 return Qnil;
10726 static VALUE sym_normal, sym_sequential, sym_random,
10727 sym_willneed, sym_dontneed, sym_noreuse;
10729 #ifdef HAVE_POSIX_FADVISE
10730 struct io_advise_struct {
10731 int fd;
10732 int advice;
10733 rb_off_t offset;
10734 rb_off_t len;
10737 static VALUE
10738 io_advise_internal(void *arg)
10740 struct io_advise_struct *ptr = arg;
10741 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10744 static VALUE
10745 io_advise_sym_to_const(VALUE sym)
10747 #ifdef POSIX_FADV_NORMAL
10748 if (sym == sym_normal)
10749 return INT2NUM(POSIX_FADV_NORMAL);
10750 #endif
10752 #ifdef POSIX_FADV_RANDOM
10753 if (sym == sym_random)
10754 return INT2NUM(POSIX_FADV_RANDOM);
10755 #endif
10757 #ifdef POSIX_FADV_SEQUENTIAL
10758 if (sym == sym_sequential)
10759 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10760 #endif
10762 #ifdef POSIX_FADV_WILLNEED
10763 if (sym == sym_willneed)
10764 return INT2NUM(POSIX_FADV_WILLNEED);
10765 #endif
10767 #ifdef POSIX_FADV_DONTNEED
10768 if (sym == sym_dontneed)
10769 return INT2NUM(POSIX_FADV_DONTNEED);
10770 #endif
10772 #ifdef POSIX_FADV_NOREUSE
10773 if (sym == sym_noreuse)
10774 return INT2NUM(POSIX_FADV_NOREUSE);
10775 #endif
10777 return Qnil;
10780 static VALUE
10781 do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10783 int rv;
10784 struct io_advise_struct ias;
10785 VALUE num_adv;
10787 num_adv = io_advise_sym_to_const(advice);
10790 * The platform doesn't support this hint. We don't raise exception, instead
10791 * silently ignore it. Because IO::advise is only hint.
10793 if (NIL_P(num_adv))
10794 return Qnil;
10796 ias.fd = fptr->fd;
10797 ias.advice = NUM2INT(num_adv);
10798 ias.offset = offset;
10799 ias.len = len;
10801 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
10802 if (rv && rv != ENOSYS) {
10803 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10804 it returns the error code. */
10805 VALUE message = rb_sprintf("%"PRIsVALUE" "
10806 "(%"PRI_OFFT_PREFIX"d, "
10807 "%"PRI_OFFT_PREFIX"d, "
10808 "%"PRIsVALUE")",
10809 fptr->pathv, offset, len, advice);
10810 rb_syserr_fail_str(rv, message);
10813 return Qnil;
10816 #endif /* HAVE_POSIX_FADVISE */
10818 static void
10819 advice_arg_check(VALUE advice)
10821 if (!SYMBOL_P(advice))
10822 rb_raise(rb_eTypeError, "advice must be a Symbol");
10824 if (advice != sym_normal &&
10825 advice != sym_sequential &&
10826 advice != sym_random &&
10827 advice != sym_willneed &&
10828 advice != sym_dontneed &&
10829 advice != sym_noreuse) {
10830 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10835 * call-seq:
10836 * advise(advice, offset = 0, len = 0) -> nil
10838 * Invokes Posix system call
10839 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10840 * which announces an intention to access data from the current file
10841 * in a particular manner.
10843 * The arguments and results are platform-dependent.
10845 * The relevant data is specified by:
10847 * - +offset+: The offset of the first byte of data.
10848 * - +len+: The number of bytes to be accessed;
10849 * if +len+ is zero, or is larger than the number of bytes remaining,
10850 * all remaining bytes will be accessed.
10852 * Argument +advice+ is one of the following symbols:
10854 * - +:normal+: The application has no advice to give
10855 * about its access pattern for the specified data.
10856 * If no advice is given for an open file, this is the default assumption.
10857 * - +:sequential+: The application expects to access the specified data sequentially
10858 * (with lower offsets read before higher ones).
10859 * - +:random+: The specified data will be accessed in random order.
10860 * - +:noreuse+: The specified data will be accessed only once.
10861 * - +:willneed+: The specified data will be accessed in the near future.
10862 * - +:dontneed+: The specified data will not be accessed in the near future.
10864 * Not implemented on all platforms.
10867 static VALUE
10868 rb_io_advise(int argc, VALUE *argv, VALUE io)
10870 VALUE advice, offset, len;
10871 rb_off_t off, l;
10872 rb_io_t *fptr;
10874 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10875 advice_arg_check(advice);
10877 io = GetWriteIO(io);
10878 GetOpenFile(io, fptr);
10880 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10881 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10883 #ifdef HAVE_POSIX_FADVISE
10884 return do_io_advise(fptr, advice, off, l);
10885 #else
10886 ((void)off, (void)l); /* Ignore all hint */
10887 return Qnil;
10888 #endif
10892 * call-seq:
10893 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10895 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10896 * which monitors multiple file descriptors,
10897 * waiting until one or more of the file descriptors
10898 * becomes ready for some class of I/O operation.
10900 * Not implemented on all platforms.
10902 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10903 * is an array of IO objects.
10905 * Argument +timeout+ is an integer timeout interval in seconds.
10907 * The method monitors the \IO objects given in all three arrays,
10908 * waiting for some to be ready;
10909 * returns a 3-element array whose elements are:
10911 * - An array of the objects in +read_ios+ that are ready for reading.
10912 * - An array of the objects in +write_ios+ that are ready for writing.
10913 * - An array of the objects in +error_ios+ have pending exceptions.
10915 * If no object becomes ready within the given +timeout+, +nil+ is returned.
10917 * \IO.select peeks the buffer of \IO objects for testing readability.
10918 * If the \IO buffer is not empty, \IO.select immediately notifies
10919 * readability. This "peek" only happens for \IO objects. It does not
10920 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10922 * The best way to use \IO.select is invoking it after non-blocking
10923 * methods such as #read_nonblock, #write_nonblock, etc. The methods
10924 * raise an exception which is extended by IO::WaitReadable or
10925 * IO::WaitWritable. The modules notify how the caller should wait
10926 * with \IO.select. If IO::WaitReadable is raised, the caller should
10927 * wait for reading. If IO::WaitWritable is raised, the caller should
10928 * wait for writing.
10930 * So, blocking read (#readpartial) can be emulated using
10931 * #read_nonblock and \IO.select as follows:
10933 * begin
10934 * result = io_like.read_nonblock(maxlen)
10935 * rescue IO::WaitReadable
10936 * IO.select([io_like])
10937 * retry
10938 * rescue IO::WaitWritable
10939 * IO.select(nil, [io_like])
10940 * retry
10941 * end
10943 * Especially, the combination of non-blocking methods and \IO.select is
10944 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
10945 * has #to_io method to return underlying IO object. IO.select calls
10946 * #to_io to obtain the file descriptor to wait.
10948 * This means that readability notified by \IO.select doesn't mean
10949 * readability from OpenSSL::SSL::SSLSocket object.
10951 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
10952 * some data. \IO.select doesn't see the buffer. So \IO.select can
10953 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
10955 * However, several more complicated situations exist.
10957 * SSL is a protocol which is sequence of records.
10958 * The record consists of multiple bytes.
10959 * So, the remote side of SSL sends a partial record, IO.select
10960 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
10961 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
10963 * Also, the remote side can request SSL renegotiation which forces
10964 * the local SSL engine to write some data.
10965 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
10966 * system call and it can block.
10967 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
10968 * IO::WaitWritable instead of blocking.
10969 * So, the caller should wait for ready for writability as above
10970 * example.
10972 * The combination of non-blocking methods and \IO.select is also useful
10973 * for streams such as tty, pipe socket socket when multiple processes
10974 * read from a stream.
10976 * Finally, Linux kernel developers don't guarantee that
10977 * readability of select(2) means readability of following read(2) even
10978 * for a single process;
10979 * see {select(2)}[https://linux.die.net/man/2/select]
10981 * Invoking \IO.select before IO#readpartial works well as usual.
10982 * However it is not the best way to use \IO.select.
10984 * The writability notified by select(2) doesn't show
10985 * how many bytes are writable.
10986 * IO#write method blocks until given whole string is written.
10987 * So, <tt>IO#write(two or more bytes)</tt> can block after
10988 * writability is notified by \IO.select. IO#write_nonblock is required
10989 * to avoid the blocking.
10991 * Blocking write (#write) can be emulated using #write_nonblock and
10992 * IO.select as follows: IO::WaitReadable should also be rescued for
10993 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
10995 * while 0 < string.bytesize
10996 * begin
10997 * written = io_like.write_nonblock(string)
10998 * rescue IO::WaitReadable
10999 * IO.select([io_like])
11000 * retry
11001 * rescue IO::WaitWritable
11002 * IO.select(nil, [io_like])
11003 * retry
11004 * end
11005 * string = string.byteslice(written..-1)
11006 * end
11008 * Example:
11010 * rp, wp = IO.pipe
11011 * mesg = "ping "
11012 * 100.times {
11013 * # IO.select follows IO#read. Not the best way to use IO.select.
11014 * rs, ws, = IO.select([rp], [wp])
11015 * if r = rs[0]
11016 * ret = r.read(5)
11017 * print ret
11018 * case ret
11019 * when /ping/
11020 * mesg = "pong\n"
11021 * when /pong/
11022 * mesg = "ping "
11023 * end
11024 * end
11025 * if w = ws[0]
11026 * w.write(mesg)
11027 * end
11030 * Output:
11032 * ping pong
11033 * ping pong
11034 * ping pong
11035 * (snipped)
11036 * ping
11040 static VALUE
11041 rb_f_select(int argc, VALUE *argv, VALUE obj)
11043 VALUE scheduler = rb_fiber_scheduler_current();
11044 if (scheduler != Qnil) {
11045 // It's optionally supported.
11046 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11047 if (!UNDEF_P(result)) return result;
11050 VALUE timeout;
11051 struct select_args args;
11052 struct timeval timerec;
11053 int i;
11055 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11056 if (NIL_P(timeout)) {
11057 args.timeout = 0;
11059 else {
11060 timerec = rb_time_interval(timeout);
11061 args.timeout = &timerec;
11064 for (i = 0; i < numberof(args.fdsets); ++i)
11065 rb_fd_init(&args.fdsets[i]);
11067 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11070 #ifdef IOCTL_REQ_TYPE
11071 typedef IOCTL_REQ_TYPE ioctl_req_t;
11072 #else
11073 typedef int ioctl_req_t;
11074 # define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11075 #endif
11077 #ifdef HAVE_IOCTL
11078 struct ioctl_arg {
11079 int fd;
11080 ioctl_req_t cmd;
11081 long narg;
11084 static VALUE
11085 nogvl_ioctl(void *ptr)
11087 struct ioctl_arg *arg = ptr;
11089 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11092 static int
11093 do_ioctl(int fd, ioctl_req_t cmd, long narg)
11095 int retval;
11096 struct ioctl_arg arg;
11098 arg.fd = fd;
11099 arg.cmd = cmd;
11100 arg.narg = narg;
11102 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
11104 return retval;
11106 #endif
11108 #define DEFAULT_IOCTL_NARG_LEN (256)
11110 #if defined(__linux__) && defined(_IOC_SIZE)
11111 static long
11112 linux_iocparm_len(ioctl_req_t cmd)
11114 long len;
11116 if ((cmd & 0xFFFF0000) == 0) {
11117 /* legacy and unstructured ioctl number. */
11118 return DEFAULT_IOCTL_NARG_LEN;
11121 len = _IOC_SIZE(cmd);
11123 /* paranoia check for silly drivers which don't keep ioctl convention */
11124 if (len < DEFAULT_IOCTL_NARG_LEN)
11125 len = DEFAULT_IOCTL_NARG_LEN;
11127 return len;
11129 #endif
11131 #ifdef HAVE_IOCTL
11132 static long
11133 ioctl_narg_len(ioctl_req_t cmd)
11135 long len;
11137 #ifdef IOCPARM_MASK
11138 #ifndef IOCPARM_LEN
11139 #define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11140 #endif
11141 #endif
11142 #ifdef IOCPARM_LEN
11143 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11144 #elif defined(__linux__) && defined(_IOC_SIZE)
11145 len = linux_iocparm_len(cmd);
11146 #else
11147 /* otherwise guess at what's safe */
11148 len = DEFAULT_IOCTL_NARG_LEN;
11149 #endif
11151 return len;
11153 #endif
11155 #ifdef HAVE_FCNTL
11156 #ifdef __linux__
11157 typedef long fcntl_arg_t;
11158 #else
11159 /* posix */
11160 typedef int fcntl_arg_t;
11161 #endif
11163 static long
11164 fcntl_narg_len(ioctl_req_t cmd)
11166 long len;
11168 switch (cmd) {
11169 #ifdef F_DUPFD
11170 case F_DUPFD:
11171 len = sizeof(fcntl_arg_t);
11172 break;
11173 #endif
11174 #ifdef F_DUP2FD /* bsd specific */
11175 case F_DUP2FD:
11176 len = sizeof(int);
11177 break;
11178 #endif
11179 #ifdef F_DUPFD_CLOEXEC /* linux specific */
11180 case F_DUPFD_CLOEXEC:
11181 len = sizeof(fcntl_arg_t);
11182 break;
11183 #endif
11184 #ifdef F_GETFD
11185 case F_GETFD:
11186 len = 1;
11187 break;
11188 #endif
11189 #ifdef F_SETFD
11190 case F_SETFD:
11191 len = sizeof(fcntl_arg_t);
11192 break;
11193 #endif
11194 #ifdef F_GETFL
11195 case F_GETFL:
11196 len = 1;
11197 break;
11198 #endif
11199 #ifdef F_SETFL
11200 case F_SETFL:
11201 len = sizeof(fcntl_arg_t);
11202 break;
11203 #endif
11204 #ifdef F_GETOWN
11205 case F_GETOWN:
11206 len = 1;
11207 break;
11208 #endif
11209 #ifdef F_SETOWN
11210 case F_SETOWN:
11211 len = sizeof(fcntl_arg_t);
11212 break;
11213 #endif
11214 #ifdef F_GETOWN_EX /* linux specific */
11215 case F_GETOWN_EX:
11216 len = sizeof(struct f_owner_ex);
11217 break;
11218 #endif
11219 #ifdef F_SETOWN_EX /* linux specific */
11220 case F_SETOWN_EX:
11221 len = sizeof(struct f_owner_ex);
11222 break;
11223 #endif
11224 #ifdef F_GETLK
11225 case F_GETLK:
11226 len = sizeof(struct flock);
11227 break;
11228 #endif
11229 #ifdef F_SETLK
11230 case F_SETLK:
11231 len = sizeof(struct flock);
11232 break;
11233 #endif
11234 #ifdef F_SETLKW
11235 case F_SETLKW:
11236 len = sizeof(struct flock);
11237 break;
11238 #endif
11239 #ifdef F_READAHEAD /* bsd specific */
11240 case F_READAHEAD:
11241 len = sizeof(int);
11242 break;
11243 #endif
11244 #ifdef F_RDAHEAD /* Darwin specific */
11245 case F_RDAHEAD:
11246 len = sizeof(int);
11247 break;
11248 #endif
11249 #ifdef F_GETSIG /* linux specific */
11250 case F_GETSIG:
11251 len = 1;
11252 break;
11253 #endif
11254 #ifdef F_SETSIG /* linux specific */
11255 case F_SETSIG:
11256 len = sizeof(fcntl_arg_t);
11257 break;
11258 #endif
11259 #ifdef F_GETLEASE /* linux specific */
11260 case F_GETLEASE:
11261 len = 1;
11262 break;
11263 #endif
11264 #ifdef F_SETLEASE /* linux specific */
11265 case F_SETLEASE:
11266 len = sizeof(fcntl_arg_t);
11267 break;
11268 #endif
11269 #ifdef F_NOTIFY /* linux specific */
11270 case F_NOTIFY:
11271 len = sizeof(fcntl_arg_t);
11272 break;
11273 #endif
11275 default:
11276 len = 256;
11277 break;
11280 return len;
11282 #else /* HAVE_FCNTL */
11283 static long
11284 fcntl_narg_len(ioctl_req_t cmd)
11286 return 0;
11288 #endif /* HAVE_FCNTL */
11290 #define NARG_SENTINEL 17
11292 static long
11293 setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11295 long narg = 0;
11296 VALUE arg = *argp;
11298 if (!RTEST(arg)) {
11299 narg = 0;
11301 else if (FIXNUM_P(arg)) {
11302 narg = FIX2LONG(arg);
11304 else if (arg == Qtrue) {
11305 narg = 1;
11307 else {
11308 VALUE tmp = rb_check_string_type(arg);
11310 if (NIL_P(tmp)) {
11311 narg = NUM2LONG(arg);
11313 else {
11314 char *ptr;
11315 long len, slen;
11317 *argp = arg = tmp;
11318 len = narg_len(cmd);
11319 rb_str_modify(arg);
11321 slen = RSTRING_LEN(arg);
11322 /* expand for data + sentinel. */
11323 if (slen < len+1) {
11324 rb_str_resize(arg, len+1);
11325 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11326 slen = len+1;
11328 /* a little sanity check here */
11329 ptr = RSTRING_PTR(arg);
11330 ptr[slen - 1] = NARG_SENTINEL;
11331 narg = (long)(SIGNED_VALUE)ptr;
11335 return narg;
11338 static VALUE
11339 finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11341 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11342 if (RB_TYPE_P(arg, T_STRING)) {
11343 char *ptr;
11344 long slen;
11345 RSTRING_GETMEM(arg, ptr, slen);
11346 if (ptr[slen-1] != NARG_SENTINEL)
11347 rb_raise(rb_eArgError, "return value overflowed string");
11348 ptr[slen-1] = '\0';
11351 return INT2NUM(retval);
11354 #ifdef HAVE_IOCTL
11355 static VALUE
11356 rb_ioctl(VALUE io, VALUE req, VALUE arg)
11358 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11359 rb_io_t *fptr;
11360 long narg;
11361 int retval;
11363 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11364 GetOpenFile(io, fptr);
11365 retval = do_ioctl(fptr->fd, cmd, narg);
11366 return finish_narg(retval, arg, fptr);
11370 * call-seq:
11371 * ioctl(integer_cmd, argument) -> integer
11373 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11374 * which issues a low-level command to an I/O device.
11376 * Issues a low-level command to an I/O device.
11377 * The arguments and returned value are platform-dependent.
11378 * The effect of the call is platform-dependent.
11380 * If argument +argument+ is an integer, it is passed directly;
11381 * if it is a string, it is interpreted as a binary sequence of bytes.
11383 * Not implemented on all platforms.
11387 static VALUE
11388 rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11390 VALUE req, arg;
11392 rb_scan_args(argc, argv, "11", &req, &arg);
11393 return rb_ioctl(io, req, arg);
11395 #else
11396 #define rb_io_ioctl rb_f_notimplement
11397 #endif
11399 #ifdef HAVE_FCNTL
11400 struct fcntl_arg {
11401 int fd;
11402 int cmd;
11403 long narg;
11406 static VALUE
11407 nogvl_fcntl(void *ptr)
11409 struct fcntl_arg *arg = ptr;
11411 #if defined(F_DUPFD)
11412 if (arg->cmd == F_DUPFD)
11413 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11414 #endif
11415 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11418 static int
11419 do_fcntl(int fd, int cmd, long narg)
11421 int retval;
11422 struct fcntl_arg arg;
11424 arg.fd = fd;
11425 arg.cmd = cmd;
11426 arg.narg = narg;
11428 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
11429 if (retval != -1) {
11430 switch (cmd) {
11431 #if defined(F_DUPFD)
11432 case F_DUPFD:
11433 #endif
11434 #if defined(F_DUPFD_CLOEXEC)
11435 case F_DUPFD_CLOEXEC:
11436 #endif
11437 rb_update_max_fd(retval);
11441 return retval;
11444 static VALUE
11445 rb_fcntl(VALUE io, VALUE req, VALUE arg)
11447 int cmd = NUM2INT(req);
11448 rb_io_t *fptr;
11449 long narg;
11450 int retval;
11452 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11453 GetOpenFile(io, fptr);
11454 retval = do_fcntl(fptr->fd, cmd, narg);
11455 return finish_narg(retval, arg, fptr);
11459 * call-seq:
11460 * fcntl(integer_cmd, argument) -> integer
11462 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11463 * which provides a mechanism for issuing low-level commands to control or query
11464 * a file-oriented I/O stream. Arguments and results are platform
11465 * dependent.
11467 * If +argument+ is a number, its value is passed directly;
11468 * if it is a string, it is interpreted as a binary sequence of bytes.
11469 * (Array#pack might be a useful way to build this string.)
11471 * Not implemented on all platforms.
11475 static VALUE
11476 rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11478 VALUE req, arg;
11480 rb_scan_args(argc, argv, "11", &req, &arg);
11481 return rb_fcntl(io, req, arg);
11483 #else
11484 #define rb_io_fcntl rb_f_notimplement
11485 #endif
11487 #if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11489 * call-seq:
11490 * syscall(integer_callno, *arguments) -> integer
11492 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11493 * which calls a specified function.
11495 * Calls the operating system function identified by +integer_callno+;
11496 * returns the result of the function or raises SystemCallError if it failed.
11497 * The effect of the call is platform-dependent.
11498 * The arguments and returned value are platform-dependent.
11500 * For each of +arguments+: if it is an integer, it is passed directly;
11501 * if it is a string, it is interpreted as a binary sequence of bytes.
11502 * There may be as many as nine such arguments.
11504 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11505 * are platform-dependent.
11507 * Note: Method +syscall+ is essentially unsafe and unportable.
11508 * The DL (Fiddle) library is preferred for safer and a bit
11509 * more portable programming.
11511 * Not implemented on all platforms.
11515 static VALUE
11516 rb_f_syscall(int argc, VALUE *argv, VALUE _)
11518 VALUE arg[8];
11519 #if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11520 # define SYSCALL __syscall
11521 # define NUM2SYSCALLID(x) NUM2LONG(x)
11522 # define RETVAL2NUM(x) LONG2NUM(x)
11523 # if SIZEOF_LONG == 8
11524 long num, retval = -1;
11525 # elif SIZEOF_LONG_LONG == 8
11526 long long num, retval = -1;
11527 # else
11528 # error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11529 # endif
11530 #elif defined(__linux__)
11531 # define SYSCALL syscall
11532 # define NUM2SYSCALLID(x) NUM2LONG(x)
11533 # define RETVAL2NUM(x) LONG2NUM(x)
11535 * Linux man page says, syscall(2) function prototype is below.
11537 * int syscall(int number, ...);
11539 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11541 long num, retval = -1;
11542 #else
11543 # define SYSCALL syscall
11544 # define NUM2SYSCALLID(x) NUM2INT(x)
11545 # define RETVAL2NUM(x) INT2NUM(x)
11546 int num, retval = -1;
11547 #endif
11548 int i;
11550 if (RTEST(ruby_verbose)) {
11551 rb_category_warning(RB_WARN_CATEGORY_DEPRECATED,
11552 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11555 if (argc == 0)
11556 rb_raise(rb_eArgError, "too few arguments for syscall");
11557 if (argc > numberof(arg))
11558 rb_raise(rb_eArgError, "too many arguments for syscall");
11559 num = NUM2SYSCALLID(argv[0]); ++argv;
11560 for (i = argc - 1; i--; ) {
11561 VALUE v = rb_check_string_type(argv[i]);
11563 if (!NIL_P(v)) {
11564 StringValue(v);
11565 rb_str_modify(v);
11566 arg[i] = (VALUE)StringValueCStr(v);
11568 else {
11569 arg[i] = (VALUE)NUM2LONG(argv[i]);
11573 switch (argc) {
11574 case 1:
11575 retval = SYSCALL(num);
11576 break;
11577 case 2:
11578 retval = SYSCALL(num, arg[0]);
11579 break;
11580 case 3:
11581 retval = SYSCALL(num, arg[0],arg[1]);
11582 break;
11583 case 4:
11584 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11585 break;
11586 case 5:
11587 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11588 break;
11589 case 6:
11590 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11591 break;
11592 case 7:
11593 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11594 break;
11595 case 8:
11596 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11597 break;
11600 if (retval == -1)
11601 rb_sys_fail(0);
11602 return RETVAL2NUM(retval);
11603 #undef SYSCALL
11604 #undef NUM2SYSCALLID
11605 #undef RETVAL2NUM
11607 #else
11608 #define rb_f_syscall rb_f_notimplement
11609 #endif
11611 static VALUE
11612 io_new_instance(VALUE args)
11614 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11617 static rb_encoding *
11618 find_encoding(VALUE v)
11620 rb_encoding *enc = rb_find_encoding(v);
11621 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11622 return enc;
11625 static void
11626 io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11628 rb_encoding *enc, *enc2;
11629 int ecflags = fptr->encs.ecflags;
11630 VALUE ecopts, tmp;
11632 if (!NIL_P(v2)) {
11633 enc2 = find_encoding(v1);
11634 tmp = rb_check_string_type(v2);
11635 if (!NIL_P(tmp)) {
11636 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11637 /* Special case - "-" => no transcoding */
11638 enc = enc2;
11639 enc2 = NULL;
11641 else
11642 enc = find_encoding(v2);
11643 if (enc == enc2) {
11644 /* Special case - "-" => no transcoding */
11645 enc2 = NULL;
11648 else {
11649 enc = find_encoding(v2);
11650 if (enc == enc2) {
11651 /* Special case - "-" => no transcoding */
11652 enc2 = NULL;
11655 if (enc2 == rb_ascii8bit_encoding()) {
11656 /* If external is ASCII-8BIT, no transcoding */
11657 enc = enc2;
11658 enc2 = NULL;
11660 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11661 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11663 else {
11664 if (NIL_P(v1)) {
11665 /* Set to default encodings */
11666 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11667 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11668 ecopts = Qnil;
11670 else {
11671 tmp = rb_check_string_type(v1);
11672 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11673 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11674 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11675 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11677 else {
11678 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11679 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11680 ecopts = Qnil;
11684 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11685 fptr->encs.enc = enc;
11686 fptr->encs.enc2 = enc2;
11687 fptr->encs.ecflags = ecflags;
11688 fptr->encs.ecopts = ecopts;
11689 clear_codeconv(fptr);
11693 struct io_encoding_set_args {
11694 rb_io_t *fptr;
11695 VALUE v1;
11696 VALUE v2;
11697 VALUE opt;
11700 static VALUE
11701 io_encoding_set_v(VALUE v)
11703 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11704 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11705 return Qnil;
11708 static VALUE
11709 pipe_pair_close(VALUE rw)
11711 VALUE *rwp = (VALUE *)rw;
11712 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11716 * call-seq:
11717 * IO.pipe(**opts) -> [read_io, write_io]
11718 * IO.pipe(enc, **opts) -> [read_io, write_io]
11719 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11720 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11721 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11722 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11724 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11725 * connected to each other.
11727 * If argument +enc_string+ is given, it must be a string containing one of:
11729 * - The name of the encoding to be used as the external encoding.
11730 * - The colon-separated names of two encodings to be used as the external
11731 * and internal encodings.
11733 * If argument +int_enc+ is given, it must be an Encoding object
11734 * or encoding name string that specifies the internal encoding to be used;
11735 * if argument +ext_enc+ is also given, it must be an Encoding object
11736 * or encoding name string that specifies the external encoding to be used.
11738 * The string read from +read_io+ is tagged with the external encoding;
11739 * if an internal encoding is also specified, the string is converted
11740 * to, and tagged with, that encoding.
11742 * If any encoding is specified,
11743 * optional hash arguments specify the conversion option.
11745 * Optional keyword arguments +opts+ specify:
11747 * - {Open Options}[rdoc-ref:IO@Open+Options].
11748 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11750 * With no block given, returns the two endpoints in an array:
11752 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11754 * With a block given, calls the block with the two endpoints;
11755 * closes both endpoints and returns the value of the block:
11757 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11759 * Output:
11761 * #<IO:fd 6>
11762 * #<IO:fd 7>
11764 * Not available on all platforms.
11766 * In the example below, the two processes close the ends of the pipe
11767 * that they are not using. This is not just a cosmetic nicety. The
11768 * read end of a pipe will not generate an end of file condition if
11769 * there are any writers with the pipe still open. In the case of the
11770 * parent process, the <tt>rd.read</tt> will never return if it
11771 * does not first issue a <tt>wr.close</tt>:
11773 * rd, wr = IO.pipe
11775 * if fork
11776 * wr.close
11777 * puts "Parent got: <#{rd.read}>"
11778 * rd.close
11779 * Process.wait
11780 * else
11781 * rd.close
11782 * puts 'Sending message to parent'
11783 * wr.write "Hi Dad"
11784 * wr.close
11785 * end
11787 * <em>produces:</em>
11789 * Sending message to parent
11790 * Parent got: <Hi Dad>
11794 static VALUE
11795 rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11797 int pipes[2], state;
11798 VALUE r, w, args[3], v1, v2;
11799 VALUE opt;
11800 rb_io_t *fptr, *fptr2;
11801 struct io_encoding_set_args ies_args;
11802 int fmode = 0;
11803 VALUE ret;
11805 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11806 if (rb_pipe(pipes) < 0)
11807 rb_sys_fail(0);
11809 args[0] = klass;
11810 args[1] = INT2NUM(pipes[0]);
11811 args[2] = INT2FIX(O_RDONLY);
11812 r = rb_protect(io_new_instance, (VALUE)args, &state);
11813 if (state) {
11814 close(pipes[0]);
11815 close(pipes[1]);
11816 rb_jump_tag(state);
11818 GetOpenFile(r, fptr);
11820 ies_args.fptr = fptr;
11821 ies_args.v1 = v1;
11822 ies_args.v2 = v2;
11823 ies_args.opt = opt;
11824 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11825 if (state) {
11826 close(pipes[1]);
11827 io_close(r);
11828 rb_jump_tag(state);
11831 args[1] = INT2NUM(pipes[1]);
11832 args[2] = INT2FIX(O_WRONLY);
11833 w = rb_protect(io_new_instance, (VALUE)args, &state);
11834 if (state) {
11835 close(pipes[1]);
11836 if (!NIL_P(r)) rb_io_close(r);
11837 rb_jump_tag(state);
11839 GetOpenFile(w, fptr2);
11840 rb_io_synchronized(fptr2);
11842 extract_binmode(opt, &fmode);
11844 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11845 rb_io_ascii8bit_binmode(r);
11846 rb_io_ascii8bit_binmode(w);
11849 #if DEFAULT_TEXTMODE
11850 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11851 fptr->mode &= ~FMODE_TEXTMODE;
11852 setmode(fptr->fd, O_BINARY);
11854 #if RUBY_CRLF_ENVIRONMENT
11855 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
11856 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
11858 #endif
11859 #endif
11860 fptr->mode |= fmode;
11861 #if DEFAULT_TEXTMODE
11862 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11863 fptr2->mode &= ~FMODE_TEXTMODE;
11864 setmode(fptr2->fd, O_BINARY);
11866 #endif
11867 fptr2->mode |= fmode;
11869 ret = rb_assoc_new(r, w);
11870 if (rb_block_given_p()) {
11871 VALUE rw[2];
11872 rw[0] = r;
11873 rw[1] = w;
11874 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11876 return ret;
11879 struct foreach_arg {
11880 int argc;
11881 VALUE *argv;
11882 VALUE io;
11885 static void
11886 open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11888 VALUE path, v;
11889 VALUE vmode = Qnil, vperm = Qnil;
11891 path = *argv++;
11892 argc--;
11893 FilePathValue(path);
11894 arg->io = 0;
11895 arg->argc = argc;
11896 arg->argv = argv;
11897 if (NIL_P(opt)) {
11898 vmode = INT2NUM(O_RDONLY);
11899 vperm = INT2FIX(0666);
11901 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11902 int n;
11904 v = rb_to_array_type(v);
11905 n = RARRAY_LENINT(v);
11906 rb_check_arity(n, 0, 3); /* rb_io_open */
11907 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11909 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11912 static VALUE
11913 io_s_foreach(VALUE v)
11915 struct getline_arg *arg = (void *)v;
11916 VALUE str;
11918 if (arg->limit == 0)
11919 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
11920 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11921 rb_lastline_set(str);
11922 rb_yield(str);
11924 rb_lastline_set(Qnil);
11925 return Qnil;
11929 * call-seq:
11930 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
11931 * IO.foreach(path, limit, **opts) {|line| block } -> nil
11932 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
11933 * IO.foreach(...) -> an_enumerator
11935 * Calls the block with each successive line read from the stream.
11937 * When called from class \IO (but not subclasses of \IO),
11938 * this method has potential security vulnerabilities if called with untrusted input;
11939 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11941 * The first argument must be a string that is the path to a file.
11943 * With only argument +path+ given, parses lines from the file at the given +path+,
11944 * as determined by the default line separator,
11945 * and calls the block with each successive line:
11947 * File.foreach('t.txt') {|line| p line }
11949 * Output: the same as above.
11951 * For both forms, command and path, the remaining arguments are the same.
11953 * With argument +sep+ given, parses lines as determined by that line separator
11954 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
11956 * File.foreach('t.txt', 'li') {|line| p line }
11958 * Output:
11960 * "First li"
11961 * "ne\nSecond li"
11962 * "ne\n\nThird li"
11963 * "ne\nFourth li"
11964 * "ne\n"
11966 * Each paragraph:
11968 * File.foreach('t.txt', '') {|paragraph| p paragraph }
11970 * Output:
11972 * "First line\nSecond line\n\n"
11973 * "Third line\nFourth line\n"
11975 * With argument +limit+ given, parses lines as determined by the default
11976 * line separator and the given line-length limit
11977 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
11979 * File.foreach('t.txt', 7) {|line| p line }
11981 * Output:
11983 * "First l"
11984 * "ine\n"
11985 * "Second "
11986 * "line\n"
11987 * "\n"
11988 * "Third l"
11989 * "ine\n"
11990 * "Fourth l"
11991 * "line\n"
11993 * With arguments +sep+ and +limit+ given,
11994 * combines the two behaviors
11995 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
11997 * Optional keyword arguments +opts+ specify:
11999 * - {Open Options}[rdoc-ref:IO@Open+Options].
12000 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12001 * - {Line Options}[rdoc-ref:IO@Line+IO].
12003 * Returns an Enumerator if no block is given.
12007 static VALUE
12008 rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12010 VALUE opt;
12011 int orig_argc = argc;
12012 struct foreach_arg arg;
12013 struct getline_arg garg;
12015 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12016 RETURN_ENUMERATOR(self, orig_argc, argv);
12017 extract_getline_args(argc-1, argv+1, &garg);
12018 open_key_args(self, argc, argv, opt, &arg);
12019 if (NIL_P(arg.io)) return Qnil;
12020 extract_getline_opts(opt, &garg);
12021 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12022 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12025 static VALUE
12026 io_s_readlines(VALUE v)
12028 struct getline_arg *arg = (void *)v;
12029 return io_readlines(arg, arg->io);
12033 * call-seq:
12034 * IO.readlines(path, sep = $/, **opts) -> array
12035 * IO.readlines(path, limit, **opts) -> array
12036 * IO.readlines(path, sep, limit, **opts) -> array
12038 * Returns an array of all lines read from the stream.
12040 * When called from class \IO (but not subclasses of \IO),
12041 * this method has potential security vulnerabilities if called with untrusted input;
12042 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12044 * The first argument must be a string that is the path to a file.
12046 * With only argument +path+ given, parses lines from the file at the given +path+,
12047 * as determined by the default line separator,
12048 * and returns those lines in an array:
12050 * IO.readlines('t.txt')
12051 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12053 * With argument +sep+ given, parses lines as determined by that line separator
12054 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12056 * # Ordinary separator.
12057 * IO.readlines('t.txt', 'li')
12058 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12059 * # Get-paragraphs separator.
12060 * IO.readlines('t.txt', '')
12061 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12062 * # Get-all separator.
12063 * IO.readlines('t.txt', nil)
12064 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12066 * With argument +limit+ given, parses lines as determined by the default
12067 * line separator and the given line-length limit
12068 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12070 * IO.readlines('t.txt', 7)
12071 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12073 * With arguments +sep+ and +limit+ given,
12074 * combines the two behaviors
12075 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12077 * Optional keyword arguments +opts+ specify:
12079 * - {Open Options}[rdoc-ref:IO@Open+Options].
12080 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12081 * - {Line Options}[rdoc-ref:IO@Line+IO].
12085 static VALUE
12086 rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12088 VALUE opt;
12089 struct foreach_arg arg;
12090 struct getline_arg garg;
12092 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12093 extract_getline_args(argc-1, argv+1, &garg);
12094 open_key_args(io, argc, argv, opt, &arg);
12095 if (NIL_P(arg.io)) return Qnil;
12096 extract_getline_opts(opt, &garg);
12097 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12098 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12101 static VALUE
12102 io_s_read(VALUE v)
12104 struct foreach_arg *arg = (void *)v;
12105 return io_read(arg->argc, arg->argv, arg->io);
12108 struct seek_arg {
12109 VALUE io;
12110 VALUE offset;
12111 int mode;
12114 static VALUE
12115 seek_before_access(VALUE argp)
12117 struct seek_arg *arg = (struct seek_arg *)argp;
12118 rb_io_binmode(arg->io);
12119 return rb_io_seek(arg->io, arg->offset, arg->mode);
12123 * call-seq:
12124 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12126 * Opens the stream, reads and returns some or all of its content,
12127 * and closes the stream; returns +nil+ if no bytes were read.
12129 * When called from class \IO (but not subclasses of \IO),
12130 * this method has potential security vulnerabilities if called with untrusted input;
12131 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12133 * The first argument must be a string that is the path to a file.
12135 * With only argument +path+ given, reads in text mode and returns the entire content
12136 * of the file at the given path:
12138 * IO.read('t.txt')
12139 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12141 * On Windows, text mode can terminate reading and leave bytes in the file
12142 * unread when encountering certain special bytes. Consider using
12143 * IO.binread if all bytes in the file should be read.
12145 * With argument +length+, returns +length+ bytes if available:
12147 * IO.read('t.txt', 7) # => "First l"
12148 * IO.read('t.txt', 700)
12149 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12151 * With arguments +length+ and +offset+, returns +length+ bytes
12152 * if available, beginning at the given +offset+:
12154 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12155 * IO.read('t.txt', 10, 200) # => nil
12157 * Optional keyword arguments +opts+ specify:
12159 * - {Open Options}[rdoc-ref:IO@Open+Options].
12160 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12164 static VALUE
12165 rb_io_s_read(int argc, VALUE *argv, VALUE io)
12167 VALUE opt, offset;
12168 long off;
12169 struct foreach_arg arg;
12171 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12172 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12173 rb_raise(rb_eArgError, "negative offset %ld given", off);
12175 open_key_args(io, argc, argv, opt, &arg);
12176 if (NIL_P(arg.io)) return Qnil;
12177 if (!NIL_P(offset)) {
12178 struct seek_arg sarg;
12179 int state = 0;
12180 sarg.io = arg.io;
12181 sarg.offset = offset;
12182 sarg.mode = SEEK_SET;
12183 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12184 if (state) {
12185 rb_io_close(arg.io);
12186 rb_jump_tag(state);
12188 if (arg.argc == 2) arg.argc = 1;
12190 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12194 * call-seq:
12195 * IO.binread(path, length = nil, offset = 0) -> string or nil
12197 * Behaves like IO.read, except that the stream is opened in binary mode
12198 * with ASCII-8BIT encoding.
12200 * When called from class \IO (but not subclasses of \IO),
12201 * this method has potential security vulnerabilities if called with untrusted input;
12202 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12206 static VALUE
12207 rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12209 VALUE offset;
12210 struct foreach_arg arg;
12211 enum {
12212 fmode = FMODE_READABLE|FMODE_BINMODE,
12213 oflags = O_RDONLY
12214 #ifdef O_BINARY
12215 |O_BINARY
12216 #endif
12218 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12220 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12221 FilePathValue(argv[0]);
12222 convconfig.enc = rb_ascii8bit_encoding();
12223 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12224 if (NIL_P(arg.io)) return Qnil;
12225 arg.argv = argv+1;
12226 arg.argc = (argc > 1) ? 1 : 0;
12227 if (!NIL_P(offset)) {
12228 struct seek_arg sarg;
12229 int state = 0;
12230 sarg.io = arg.io;
12231 sarg.offset = offset;
12232 sarg.mode = SEEK_SET;
12233 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12234 if (state) {
12235 rb_io_close(arg.io);
12236 rb_jump_tag(state);
12239 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12242 static VALUE
12243 io_s_write0(VALUE v)
12245 struct write_arg *arg = (void *)v;
12246 return io_write(arg->io,arg->str,arg->nosync);
12249 static VALUE
12250 io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12252 VALUE string, offset, opt;
12253 struct foreach_arg arg;
12254 struct write_arg warg;
12256 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12258 if (NIL_P(opt)) opt = rb_hash_new();
12259 else opt = rb_hash_dup(opt);
12262 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12263 int mode = O_WRONLY|O_CREAT;
12264 #ifdef O_BINARY
12265 if (binary) mode |= O_BINARY;
12266 #endif
12267 if (NIL_P(offset)) mode |= O_TRUNC;
12268 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12270 open_key_args(klass, argc, argv, opt, &arg);
12272 #ifndef O_BINARY
12273 if (binary) rb_io_binmode_m(arg.io);
12274 #endif
12276 if (NIL_P(arg.io)) return Qnil;
12277 if (!NIL_P(offset)) {
12278 struct seek_arg sarg;
12279 int state = 0;
12280 sarg.io = arg.io;
12281 sarg.offset = offset;
12282 sarg.mode = SEEK_SET;
12283 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12284 if (state) {
12285 rb_io_close(arg.io);
12286 rb_jump_tag(state);
12290 warg.io = arg.io;
12291 warg.str = string;
12292 warg.nosync = 0;
12294 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12298 * call-seq:
12299 * IO.write(path, data, offset = 0, **opts) -> integer
12301 * Opens the stream, writes the given +data+ to it,
12302 * and closes the stream; returns the number of bytes written.
12304 * When called from class \IO (but not subclasses of \IO),
12305 * this method has potential security vulnerabilities if called with untrusted input;
12306 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12308 * The first argument must be a string that is the path to a file.
12310 * With only argument +path+ given, writes the given +data+ to the file at that path:
12312 * IO.write('t.tmp', 'abc') # => 3
12313 * File.read('t.tmp') # => "abc"
12315 * If +offset+ is zero (the default), the file is overwritten:
12317 * IO.write('t.tmp', 'A') # => 1
12318 * File.read('t.tmp') # => "A"
12320 * If +offset+ in within the file content, the file is partly overwritten:
12322 * IO.write('t.tmp', 'abcdef') # => 3
12323 * File.read('t.tmp') # => "abcdef"
12324 * # Offset within content.
12325 * IO.write('t.tmp', '012', 2) # => 3
12326 * File.read('t.tmp') # => "ab012f"
12328 * If +offset+ is outside the file content,
12329 * the file is padded with null characters <tt>"\u0000"</tt>:
12331 * IO.write('t.tmp', 'xyz', 10) # => 3
12332 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12334 * Optional keyword arguments +opts+ specify:
12336 * - {Open Options}[rdoc-ref:IO@Open+Options].
12337 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12341 static VALUE
12342 rb_io_s_write(int argc, VALUE *argv, VALUE io)
12344 return io_s_write(argc, argv, io, 0);
12348 * call-seq:
12349 * IO.binwrite(path, string, offset = 0) -> integer
12351 * Behaves like IO.write, except that the stream is opened in binary mode
12352 * with ASCII-8BIT encoding.
12354 * When called from class \IO (but not subclasses of \IO),
12355 * this method has potential security vulnerabilities if called with untrusted input;
12356 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12360 static VALUE
12361 rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12363 return io_s_write(argc, argv, io, 1);
12366 struct copy_stream_struct {
12367 VALUE src;
12368 VALUE dst;
12369 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12370 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12372 rb_io_t *src_fptr;
12373 rb_io_t *dst_fptr;
12374 unsigned close_src : 1;
12375 unsigned close_dst : 1;
12376 int error_no;
12377 rb_off_t total;
12378 const char *syserr;
12379 const char *notimp;
12380 VALUE th;
12381 struct stat src_stat;
12382 struct stat dst_stat;
12383 #ifdef HAVE_FCOPYFILE
12384 copyfile_state_t copyfile_state;
12385 #endif
12388 static void *
12389 exec_interrupts(void *arg)
12391 VALUE th = (VALUE)arg;
12392 rb_thread_execute_interrupts(th);
12393 return NULL;
12397 * returns TRUE if the preceding system call was interrupted
12398 * so we can continue. If the thread was interrupted, we
12399 * reacquire the GVL to execute interrupts before continuing.
12401 static int
12402 maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12404 switch (errno) {
12405 case EINTR:
12406 #if defined(ERESTART)
12407 case ERESTART:
12408 #endif
12409 if (rb_thread_interrupted(stp->th)) {
12410 if (has_gvl)
12411 rb_thread_execute_interrupts(stp->th);
12412 else
12413 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12415 return TRUE;
12417 return FALSE;
12420 struct fiber_scheduler_wait_for_arguments {
12421 VALUE scheduler;
12423 rb_io_t *fptr;
12424 short events;
12426 VALUE result;
12429 static void *
12430 fiber_scheduler_wait_for(void * _arguments)
12432 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12434 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12436 return NULL;
12439 #if USE_POLL
12440 # define IOWAIT_SYSCALL "poll"
12441 STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12442 STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12443 static int
12444 nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12446 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
12447 if (scheduler != Qnil) {
12448 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12449 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12450 return RTEST(args.result);
12453 int fd = fptr->fd;
12454 if (fd == -1) return 0;
12456 struct pollfd fds;
12458 fds.fd = fd;
12459 fds.events = events;
12461 int timeout_milliseconds = -1;
12463 if (timeout) {
12464 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12467 return poll(&fds, 1, timeout_milliseconds);
12469 #else /* !USE_POLL */
12470 # define IOWAIT_SYSCALL "select"
12471 static int
12472 nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12474 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
12475 if (scheduler != Qnil) {
12476 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12477 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12478 return RTEST(args.result);
12481 int fd = fptr->fd;
12483 if (fd == -1) {
12484 errno = EBADF;
12485 return -1;
12488 rb_fdset_t fds;
12489 int ret;
12491 rb_fd_init(&fds);
12492 rb_fd_set(fd, &fds);
12494 switch (events) {
12495 case RB_WAITFD_IN:
12496 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12497 break;
12498 case RB_WAITFD_OUT:
12499 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12500 break;
12501 default:
12502 VM_UNREACHABLE(nogvl_wait_for);
12505 rb_fd_term(&fds);
12507 // On timeout, this returns 0.
12508 return ret;
12510 #endif /* !USE_POLL */
12512 static int
12513 maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12515 int ret;
12517 do {
12518 if (has_gvl) {
12519 ret = RB_NUM2INT(rb_io_wait(stp->src, RB_INT2NUM(RUBY_IO_READABLE), Qnil));
12521 else {
12522 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12524 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12526 if (ret < 0) {
12527 stp->syserr = IOWAIT_SYSCALL;
12528 stp->error_no = errno;
12529 return ret;
12531 return 0;
12534 static int
12535 nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12537 int ret;
12539 do {
12540 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12541 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12543 if (ret < 0) {
12544 stp->syserr = IOWAIT_SYSCALL;
12545 stp->error_no = errno;
12546 return ret;
12548 return 0;
12551 #ifdef USE_COPY_FILE_RANGE
12553 static ssize_t
12554 simple_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)
12556 #ifdef HAVE_COPY_FILE_RANGE
12557 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12558 #else
12559 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12560 #endif
12563 static int
12564 nogvl_copy_file_range(struct copy_stream_struct *stp)
12566 ssize_t ss;
12567 rb_off_t src_size;
12568 rb_off_t copy_length, src_offset, *src_offset_ptr;
12570 if (!S_ISREG(stp->src_stat.st_mode))
12571 return 0;
12573 src_size = stp->src_stat.st_size;
12574 src_offset = stp->src_offset;
12575 if (src_offset >= (rb_off_t)0) {
12576 src_offset_ptr = &src_offset;
12578 else {
12579 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12582 copy_length = stp->copy_length;
12583 if (copy_length < (rb_off_t)0) {
12584 if (src_offset < (rb_off_t)0) {
12585 rb_off_t current_offset;
12586 errno = 0;
12587 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12588 if (current_offset < (rb_off_t)0 && errno) {
12589 stp->syserr = "lseek";
12590 stp->error_no = errno;
12591 return (int)current_offset;
12593 copy_length = src_size - current_offset;
12595 else {
12596 copy_length = src_size - src_offset;
12600 retry_copy_file_range:
12601 # if SIZEOF_OFF_T > SIZEOF_SIZE_T
12602 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12603 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12604 # else
12605 ss = (ssize_t)copy_length;
12606 # endif
12607 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12608 if (0 < ss) {
12609 stp->total += ss;
12610 copy_length -= ss;
12611 if (0 < copy_length) {
12612 goto retry_copy_file_range;
12615 if (ss < 0) {
12616 if (maygvl_copy_stream_continue_p(0, stp)) {
12617 goto retry_copy_file_range;
12619 switch (errno) {
12620 case EINVAL:
12621 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12622 docker container) */
12623 #ifdef ENOSYS
12624 case ENOSYS:
12625 #endif
12626 #ifdef EXDEV
12627 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12628 #endif
12629 return 0;
12630 case EAGAIN:
12631 #if EWOULDBLOCK != EAGAIN
12632 case EWOULDBLOCK:
12633 #endif
12635 int ret = nogvl_copy_stream_wait_write(stp);
12636 if (ret < 0) return ret;
12638 goto retry_copy_file_range;
12639 case EBADF:
12641 int e = errno;
12642 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12644 if (flags != -1 && flags & O_APPEND) {
12645 return 0;
12647 errno = e;
12650 stp->syserr = "copy_file_range";
12651 stp->error_no = errno;
12652 return (int)ss;
12654 return 1;
12656 #endif
12658 #ifdef HAVE_FCOPYFILE
12659 static int
12660 nogvl_fcopyfile(struct copy_stream_struct *stp)
12662 rb_off_t cur, ss = 0;
12663 const rb_off_t src_offset = stp->src_offset;
12664 int ret;
12666 if (stp->copy_length >= (rb_off_t)0) {
12667 /* copy_length can't be specified in fcopyfile(3) */
12668 return 0;
12671 if (!S_ISREG(stp->src_stat.st_mode))
12672 return 0;
12674 if (!S_ISREG(stp->dst_stat.st_mode))
12675 return 0;
12676 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12677 return 0;
12678 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12679 /* fcopyfile(3) appends src IO to dst IO and then truncates
12680 * dst IO to src IO's original size. */
12681 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12682 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12683 if (end > (rb_off_t)0) return 0;
12686 if (src_offset > (rb_off_t)0) {
12687 rb_off_t r;
12689 /* get current offset */
12690 errno = 0;
12691 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12692 if (cur < (rb_off_t)0 && errno) {
12693 stp->error_no = errno;
12694 return 1;
12697 errno = 0;
12698 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12699 if (r < (rb_off_t)0 && errno) {
12700 stp->error_no = errno;
12701 return 1;
12705 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12706 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12707 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12709 if (ret == 0) { /* success */
12710 stp->total = ss;
12711 if (src_offset > (rb_off_t)0) {
12712 rb_off_t r;
12713 errno = 0;
12714 /* reset offset */
12715 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12716 if (r < (rb_off_t)0 && errno) {
12717 stp->error_no = errno;
12718 return 1;
12722 else {
12723 switch (errno) {
12724 case ENOTSUP:
12725 case EPERM:
12726 case EINVAL:
12727 return 0;
12729 stp->syserr = "fcopyfile";
12730 stp->error_no = errno;
12731 return (int)ret;
12733 return 1;
12735 #endif
12737 #ifdef HAVE_SENDFILE
12739 # ifdef __linux__
12740 # define USE_SENDFILE
12742 # ifdef HAVE_SYS_SENDFILE_H
12743 # include <sys/sendfile.h>
12744 # endif
12746 static ssize_t
12747 simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12749 return sendfile(out_fd, in_fd, offset, (size_t)count);
12752 # elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12753 /* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12754 * without cpuset -l 0.
12756 # define USE_SENDFILE
12758 static ssize_t
12759 simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12761 int r;
12762 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12763 rb_off_t sbytes;
12764 # ifdef __APPLE__
12765 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12766 sbytes = count;
12767 # else
12768 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12769 # endif
12770 if (r != 0 && sbytes == 0) return r;
12771 if (offset) {
12772 *offset += sbytes;
12774 else {
12775 lseek(in_fd, sbytes, SEEK_CUR);
12777 return (ssize_t)sbytes;
12780 # endif
12782 #endif
12784 #ifdef USE_SENDFILE
12785 static int
12786 nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12788 ssize_t ss;
12789 rb_off_t src_size;
12790 rb_off_t copy_length;
12791 rb_off_t src_offset;
12792 int use_pread;
12794 if (!S_ISREG(stp->src_stat.st_mode))
12795 return 0;
12797 src_size = stp->src_stat.st_size;
12798 #ifndef __linux__
12799 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12800 return 0;
12801 #endif
12803 src_offset = stp->src_offset;
12804 use_pread = src_offset >= (rb_off_t)0;
12806 copy_length = stp->copy_length;
12807 if (copy_length < (rb_off_t)0) {
12808 if (use_pread)
12809 copy_length = src_size - src_offset;
12810 else {
12811 rb_off_t cur;
12812 errno = 0;
12813 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12814 if (cur < (rb_off_t)0 && errno) {
12815 stp->syserr = "lseek";
12816 stp->error_no = errno;
12817 return (int)cur;
12819 copy_length = src_size - cur;
12823 retry_sendfile:
12824 # if SIZEOF_OFF_T > SIZEOF_SIZE_T
12825 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12826 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12827 # else
12828 ss = (ssize_t)copy_length;
12829 # endif
12830 if (use_pread) {
12831 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12833 else {
12834 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12836 if (0 < ss) {
12837 stp->total += ss;
12838 copy_length -= ss;
12839 if (0 < copy_length) {
12840 goto retry_sendfile;
12843 if (ss < 0) {
12844 if (maygvl_copy_stream_continue_p(0, stp))
12845 goto retry_sendfile;
12846 switch (errno) {
12847 case EINVAL:
12848 #ifdef ENOSYS
12849 case ENOSYS:
12850 #endif
12851 #ifdef EOPNOTSUP
12852 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12853 see also: [Feature #16965] */
12854 case EOPNOTSUP:
12855 #endif
12856 return 0;
12857 case EAGAIN:
12858 #if EWOULDBLOCK != EAGAIN
12859 case EWOULDBLOCK:
12860 #endif
12862 int ret;
12863 #ifndef __linux__
12865 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12866 * select() reports regular files to always be "ready", so
12867 * there is no need to select() on it.
12868 * Other OSes may have the same limitation for sendfile() which
12869 * allow us to bypass maygvl_copy_stream_wait_read()...
12871 ret = maygvl_copy_stream_wait_read(0, stp);
12872 if (ret < 0) return ret;
12873 #endif
12874 ret = nogvl_copy_stream_wait_write(stp);
12875 if (ret < 0) return ret;
12877 goto retry_sendfile;
12879 stp->syserr = "sendfile";
12880 stp->error_no = errno;
12881 return (int)ss;
12883 return 1;
12885 #endif
12887 static ssize_t
12888 maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12890 if (has_gvl)
12891 return rb_io_read_memory(fptr, buf, count);
12892 else
12893 return read(fptr->fd, buf, count);
12896 static ssize_t
12897 maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12899 ssize_t ss;
12900 retry_read:
12901 if (offset < (rb_off_t)0) {
12902 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12904 else {
12905 ss = pread(stp->src_fptr->fd, buf, len, offset);
12907 if (ss == 0) {
12908 return 0;
12910 if (ss < 0) {
12911 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12912 goto retry_read;
12913 switch (errno) {
12914 case EAGAIN:
12915 #if EWOULDBLOCK != EAGAIN
12916 case EWOULDBLOCK:
12917 #endif
12919 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12920 if (ret < 0) return ret;
12922 goto retry_read;
12923 #ifdef ENOSYS
12924 case ENOSYS:
12925 stp->notimp = "pread";
12926 return ss;
12927 #endif
12929 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
12930 stp->error_no = errno;
12932 return ss;
12935 static int
12936 nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
12938 ssize_t ss;
12939 int off = 0;
12940 while (len) {
12941 ss = write(stp->dst_fptr->fd, buf+off, len);
12942 if (ss < 0) {
12943 if (maygvl_copy_stream_continue_p(0, stp))
12944 continue;
12945 if (io_again_p(errno)) {
12946 int ret = nogvl_copy_stream_wait_write(stp);
12947 if (ret < 0) return ret;
12948 continue;
12950 stp->syserr = "write";
12951 stp->error_no = errno;
12952 return (int)ss;
12954 off += (int)ss;
12955 len -= (int)ss;
12956 stp->total += ss;
12958 return 0;
12961 static void
12962 nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
12964 char buf[1024*16];
12965 size_t len;
12966 ssize_t ss;
12967 int ret;
12968 rb_off_t copy_length;
12969 rb_off_t src_offset;
12970 int use_eof;
12971 int use_pread;
12973 copy_length = stp->copy_length;
12974 use_eof = copy_length < (rb_off_t)0;
12975 src_offset = stp->src_offset;
12976 use_pread = src_offset >= (rb_off_t)0;
12978 if (use_pread && stp->close_src) {
12979 rb_off_t r;
12980 errno = 0;
12981 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12982 if (r < (rb_off_t)0 && errno) {
12983 stp->syserr = "lseek";
12984 stp->error_no = errno;
12985 return;
12987 src_offset = (rb_off_t)-1;
12988 use_pread = 0;
12991 while (use_eof || 0 < copy_length) {
12992 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
12993 len = (size_t)copy_length;
12995 else {
12996 len = sizeof(buf);
12998 if (use_pread) {
12999 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13000 if (0 < ss)
13001 src_offset += ss;
13003 else {
13004 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13006 if (ss <= 0) /* EOF or error */
13007 return;
13009 ret = nogvl_copy_stream_write(stp, buf, ss);
13010 if (ret < 0)
13011 return;
13013 if (!use_eof)
13014 copy_length -= ss;
13018 static void *
13019 nogvl_copy_stream_func(void *arg)
13021 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13022 #if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13023 int ret;
13024 #endif
13026 #ifdef USE_COPY_FILE_RANGE
13027 ret = nogvl_copy_file_range(stp);
13028 if (ret != 0)
13029 goto finish; /* error or success */
13030 #endif
13032 #ifdef HAVE_FCOPYFILE
13033 ret = nogvl_fcopyfile(stp);
13034 if (ret != 0)
13035 goto finish; /* error or success */
13036 #endif
13038 #ifdef USE_SENDFILE
13039 ret = nogvl_copy_stream_sendfile(stp);
13040 if (ret != 0)
13041 goto finish; /* error or success */
13042 #endif
13044 nogvl_copy_stream_read_write(stp);
13046 #if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13047 finish:
13048 #endif
13049 return 0;
13052 static VALUE
13053 copy_stream_fallback_body(VALUE arg)
13055 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13056 const int buflen = 16*1024;
13057 VALUE n;
13058 VALUE buf = rb_str_buf_new(buflen);
13059 rb_off_t rest = stp->copy_length;
13060 rb_off_t off = stp->src_offset;
13061 ID read_method = id_readpartial;
13063 if (!stp->src_fptr) {
13064 if (!rb_respond_to(stp->src, read_method)) {
13065 read_method = id_read;
13069 while (1) {
13070 long numwrote;
13071 long l;
13072 if (stp->copy_length < (rb_off_t)0) {
13073 l = buflen;
13075 else {
13076 if (rest == 0) {
13077 rb_str_resize(buf, 0);
13078 break;
13080 l = buflen < rest ? buflen : (long)rest;
13082 if (!stp->src_fptr) {
13083 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13085 if (read_method == id_read && NIL_P(rc))
13086 break;
13088 else {
13089 ssize_t ss;
13090 rb_str_resize(buf, buflen);
13091 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13092 rb_str_resize(buf, ss > 0 ? ss : 0);
13093 if (ss < 0)
13094 return Qnil;
13095 if (ss == 0)
13096 rb_eof_error();
13097 if (off >= (rb_off_t)0)
13098 off += ss;
13100 n = rb_io_write(stp->dst, buf);
13101 numwrote = NUM2LONG(n);
13102 stp->total += numwrote;
13103 rest -= numwrote;
13104 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13105 break;
13109 return Qnil;
13112 static VALUE
13113 copy_stream_fallback(struct copy_stream_struct *stp)
13115 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13116 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13118 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13119 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13120 rb_eEOFError, (VALUE)0);
13121 return Qnil;
13124 static VALUE
13125 copy_stream_body(VALUE arg)
13127 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13128 VALUE src_io = stp->src, dst_io = stp->dst;
13129 const int common_oflags = 0
13130 #ifdef O_NOCTTY
13131 | O_NOCTTY
13132 #endif
13135 stp->th = rb_thread_current();
13137 stp->total = 0;
13139 if (src_io == argf ||
13140 !(RB_TYPE_P(src_io, T_FILE) ||
13141 RB_TYPE_P(src_io, T_STRING) ||
13142 rb_respond_to(src_io, rb_intern("to_path")))) {
13143 stp->src_fptr = NULL;
13145 else {
13146 int stat_ret;
13147 VALUE tmp_io = rb_io_check_io(src_io);
13148 if (!NIL_P(tmp_io)) {
13149 src_io = tmp_io;
13151 else if (!RB_TYPE_P(src_io, T_FILE)) {
13152 VALUE args[2];
13153 FilePathValue(src_io);
13154 args[0] = src_io;
13155 args[1] = INT2NUM(O_RDONLY|common_oflags);
13156 src_io = rb_class_new_instance(2, args, rb_cFile);
13157 stp->src = src_io;
13158 stp->close_src = 1;
13160 RB_IO_POINTER(src_io, stp->src_fptr);
13161 rb_io_check_byte_readable(stp->src_fptr);
13163 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13164 if (stat_ret < 0) {
13165 stp->syserr = "fstat";
13166 stp->error_no = errno;
13167 return Qnil;
13171 if (dst_io == argf ||
13172 !(RB_TYPE_P(dst_io, T_FILE) ||
13173 RB_TYPE_P(dst_io, T_STRING) ||
13174 rb_respond_to(dst_io, rb_intern("to_path")))) {
13175 stp->dst_fptr = NULL;
13177 else {
13178 int stat_ret;
13179 VALUE tmp_io = rb_io_check_io(dst_io);
13180 if (!NIL_P(tmp_io)) {
13181 dst_io = GetWriteIO(tmp_io);
13183 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13184 VALUE args[3];
13185 FilePathValue(dst_io);
13186 args[0] = dst_io;
13187 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13188 args[2] = INT2FIX(0666);
13189 dst_io = rb_class_new_instance(3, args, rb_cFile);
13190 stp->dst = dst_io;
13191 stp->close_dst = 1;
13193 else {
13194 dst_io = GetWriteIO(dst_io);
13195 stp->dst = dst_io;
13197 RB_IO_POINTER(dst_io, stp->dst_fptr);
13198 rb_io_check_writable(stp->dst_fptr);
13200 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13201 if (stat_ret < 0) {
13202 stp->syserr = "fstat";
13203 stp->error_no = errno;
13204 return Qnil;
13208 #ifdef O_BINARY
13209 if (stp->src_fptr)
13210 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13211 #endif
13212 if (stp->dst_fptr)
13213 io_ascii8bit_binmode(stp->dst_fptr);
13215 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13216 size_t len = stp->src_fptr->rbuf.len;
13217 VALUE str;
13218 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13219 len = (size_t)stp->copy_length;
13221 str = rb_str_buf_new(len);
13222 rb_str_resize(str,len);
13223 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13224 if (stp->dst_fptr) { /* IO or filename */
13225 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13226 rb_sys_fail_on_write(stp->dst_fptr);
13228 else /* others such as StringIO */
13229 rb_io_write(dst_io, str);
13230 rb_str_resize(str, 0);
13231 stp->total += len;
13232 if (stp->copy_length >= (rb_off_t)0)
13233 stp->copy_length -= len;
13236 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13237 rb_raise(rb_eIOError, "flush failed");
13240 if (stp->copy_length == 0)
13241 return Qnil;
13243 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13244 return copy_stream_fallback(stp);
13247 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13248 return Qnil;
13251 static VALUE
13252 copy_stream_finalize(VALUE arg)
13254 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13256 #ifdef HAVE_FCOPYFILE
13257 if (stp->copyfile_state) {
13258 copyfile_state_free(stp->copyfile_state);
13260 #endif
13262 if (stp->close_src) {
13263 rb_io_close_m(stp->src);
13265 if (stp->close_dst) {
13266 rb_io_close_m(stp->dst);
13268 if (stp->syserr) {
13269 rb_syserr_fail(stp->error_no, stp->syserr);
13271 if (stp->notimp) {
13272 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13274 return Qnil;
13278 * call-seq:
13279 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13281 * Copies from the given +src+ to the given +dst+,
13282 * returning the number of bytes copied.
13284 * - The given +src+ must be one of the following:
13286 * - The path to a readable file, from which source data is to be read.
13287 * - An \IO-like object, opened for reading and capable of responding
13288 * to method +:readpartial+ or method +:read+.
13290 * - The given +dst+ must be one of the following:
13292 * - The path to a writable file, to which data is to be written.
13293 * - An \IO-like object, opened for writing and capable of responding
13294 * to method +:write+.
13296 * The examples here use file <tt>t.txt</tt> as source:
13298 * File.read('t.txt')
13299 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13300 * File.read('t.txt').size # => 47
13302 * If only arguments +src+ and +dst+ are given,
13303 * the entire source stream is copied:
13305 * # Paths.
13306 * IO.copy_stream('t.txt', 't.tmp') # => 47
13308 * # IOs (recall that a File is also an IO).
13309 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13310 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13311 * IO.copy_stream(src_io, dst_io) # => 47
13312 * src_io.close
13313 * dst_io.close
13315 * With argument +src_length+ a non-negative integer,
13316 * no more than that many bytes are copied:
13318 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13319 * File.read('t.tmp') # => "First line"
13321 * With argument +src_offset+ also given,
13322 * the source stream is read beginning at that offset:
13324 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13325 * IO.read('t.tmp') # => "Second line"
13328 static VALUE
13329 rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13331 VALUE src, dst, length, src_offset;
13332 struct copy_stream_struct st;
13334 MEMZERO(&st, struct copy_stream_struct, 1);
13336 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13338 st.src = src;
13339 st.dst = dst;
13341 st.src_fptr = NULL;
13342 st.dst_fptr = NULL;
13344 if (NIL_P(length))
13345 st.copy_length = (rb_off_t)-1;
13346 else
13347 st.copy_length = NUM2OFFT(length);
13349 if (NIL_P(src_offset))
13350 st.src_offset = (rb_off_t)-1;
13351 else
13352 st.src_offset = NUM2OFFT(src_offset);
13354 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13356 return OFFT2NUM(st.total);
13360 * call-seq:
13361 * external_encoding -> encoding or nil
13363 * Returns the Encoding object that represents the encoding of the stream,
13364 * or +nil+ if the stream is in write mode and no encoding is specified.
13366 * See {Encodings}[rdoc-ref:File@Encodings].
13370 static VALUE
13371 rb_io_external_encoding(VALUE io)
13373 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13375 if (fptr->encs.enc2) {
13376 return rb_enc_from_encoding(fptr->encs.enc2);
13378 if (fptr->mode & FMODE_WRITABLE) {
13379 if (fptr->encs.enc)
13380 return rb_enc_from_encoding(fptr->encs.enc);
13381 return Qnil;
13383 return rb_enc_from_encoding(io_read_encoding(fptr));
13387 * call-seq:
13388 * internal_encoding -> encoding or nil
13390 * Returns the Encoding object that represents the encoding of the internal string,
13391 * if conversion is specified,
13392 * or +nil+ otherwise.
13394 * See {Encodings}[rdoc-ref:File@Encodings].
13398 static VALUE
13399 rb_io_internal_encoding(VALUE io)
13401 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13403 if (!fptr->encs.enc2) return Qnil;
13404 return rb_enc_from_encoding(io_read_encoding(fptr));
13408 * call-seq:
13409 * set_encoding(ext_enc) -> self
13410 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13411 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13413 * See {Encodings}[rdoc-ref:File@Encodings].
13415 * Argument +ext_enc+, if given, must be an Encoding object
13416 * or a String with the encoding name;
13417 * it is assigned as the encoding for the stream.
13419 * Argument +int_enc+, if given, must be an Encoding object
13420 * or a String with the encoding name;
13421 * it is assigned as the encoding for the internal string.
13423 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13424 * containing two colon-separated encoding names;
13425 * corresponding Encoding objects are assigned as the external
13426 * and internal encodings for the stream.
13428 * If the external encoding of a string is binary/ASCII-8BIT,
13429 * the internal encoding of the string is set to nil, since no
13430 * transcoding is needed.
13432 * Optional keyword arguments +enc_opts+ specify
13433 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13437 static VALUE
13438 rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13440 rb_io_t *fptr;
13441 VALUE v1, v2, opt;
13443 if (!RB_TYPE_P(io, T_FILE)) {
13444 return forward(io, id_set_encoding, argc, argv);
13447 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13448 GetOpenFile(io, fptr);
13449 io_encoding_set(fptr, v1, v2, opt);
13450 return io;
13453 void
13454 rb_stdio_set_default_encoding(void)
13456 VALUE val = Qnil;
13458 #ifdef _WIN32
13459 if (isatty(fileno(stdin))) {
13460 rb_encoding *external = rb_locale_encoding();
13461 rb_encoding *internal = rb_default_internal_encoding();
13462 if (!internal) internal = rb_default_external_encoding();
13463 io_encoding_set(RFILE(rb_stdin)->fptr,
13464 rb_enc_from_encoding(external),
13465 rb_enc_from_encoding(internal),
13466 Qnil);
13468 else
13469 #endif
13470 rb_io_set_encoding(1, &val, rb_stdin);
13471 rb_io_set_encoding(1, &val, rb_stdout);
13472 rb_io_set_encoding(1, &val, rb_stderr);
13475 static inline int
13476 global_argf_p(VALUE arg)
13478 return arg == argf;
13481 typedef VALUE (*argf_encoding_func)(VALUE io);
13483 static VALUE
13484 argf_encoding(VALUE argf, argf_encoding_func func)
13486 if (!RTEST(ARGF.current_file)) {
13487 return rb_enc_default_external();
13489 return func(rb_io_check_io(ARGF.current_file));
13493 * call-seq:
13494 * ARGF.external_encoding -> encoding
13496 * Returns the external encoding for files read from ARGF as an Encoding
13497 * object. The external encoding is the encoding of the text as stored in a
13498 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13499 * represent this text within Ruby.
13501 * To set the external encoding use ARGF.set_encoding.
13503 * For example:
13505 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13508 static VALUE
13509 argf_external_encoding(VALUE argf)
13511 return argf_encoding(argf, rb_io_external_encoding);
13515 * call-seq:
13516 * ARGF.internal_encoding -> encoding
13518 * Returns the internal encoding for strings read from ARGF as an
13519 * Encoding object.
13521 * If ARGF.set_encoding has been called with two encoding names, the second
13522 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13523 * value is returned. Failing that, if a default external encoding was
13524 * specified on the command-line, that value is used. If the encoding is
13525 * unknown, +nil+ is returned.
13527 static VALUE
13528 argf_internal_encoding(VALUE argf)
13530 return argf_encoding(argf, rb_io_internal_encoding);
13534 * call-seq:
13535 * ARGF.set_encoding(ext_enc) -> ARGF
13536 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13537 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13538 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13539 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13541 * If single argument is specified, strings read from ARGF are tagged with
13542 * the encoding specified.
13544 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13545 * the read string is converted from the first encoding (external encoding)
13546 * to the second encoding (internal encoding), then tagged with the second
13547 * encoding.
13549 * If two arguments are specified, they must be encoding objects or encoding
13550 * names. Again, the first specifies the external encoding; the second
13551 * specifies the internal encoding.
13553 * If the external encoding and the internal encoding are specified, the
13554 * optional Hash argument can be used to adjust the conversion process. The
13555 * structure of this hash is explained in the String#encode documentation.
13557 * For example:
13559 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13560 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13561 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13562 * # to UTF-8.
13564 static VALUE
13565 argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13567 rb_io_t *fptr;
13569 if (!next_argv()) {
13570 rb_raise(rb_eArgError, "no stream to set encoding");
13572 rb_io_set_encoding(argc, argv, ARGF.current_file);
13573 GetOpenFile(ARGF.current_file, fptr);
13574 ARGF.encs = fptr->encs;
13575 return argf;
13579 * call-seq:
13580 * ARGF.tell -> Integer
13581 * ARGF.pos -> Integer
13583 * Returns the current offset (in bytes) of the current file in ARGF.
13585 * ARGF.pos #=> 0
13586 * ARGF.gets #=> "This is line one\n"
13587 * ARGF.pos #=> 17
13590 static VALUE
13591 argf_tell(VALUE argf)
13593 if (!next_argv()) {
13594 rb_raise(rb_eArgError, "no stream to tell");
13596 ARGF_FORWARD(0, 0);
13597 return rb_io_tell(ARGF.current_file);
13601 * call-seq:
13602 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13604 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13605 * the value of _whence_. See IO#seek for further details.
13607 static VALUE
13608 argf_seek_m(int argc, VALUE *argv, VALUE argf)
13610 if (!next_argv()) {
13611 rb_raise(rb_eArgError, "no stream to seek");
13613 ARGF_FORWARD(argc, argv);
13614 return rb_io_seek_m(argc, argv, ARGF.current_file);
13618 * call-seq:
13619 * ARGF.pos = position -> Integer
13621 * Seeks to the position given by _position_ (in bytes) in ARGF.
13623 * For example:
13625 * ARGF.pos = 17
13626 * ARGF.gets #=> "This is line two\n"
13628 static VALUE
13629 argf_set_pos(VALUE argf, VALUE offset)
13631 if (!next_argv()) {
13632 rb_raise(rb_eArgError, "no stream to set position");
13634 ARGF_FORWARD(1, &offset);
13635 return rb_io_set_pos(ARGF.current_file, offset);
13639 * call-seq:
13640 * ARGF.rewind -> 0
13642 * Positions the current file to the beginning of input, resetting
13643 * ARGF.lineno to zero.
13645 * ARGF.readline #=> "This is line one\n"
13646 * ARGF.rewind #=> 0
13647 * ARGF.lineno #=> 0
13648 * ARGF.readline #=> "This is line one\n"
13650 static VALUE
13651 argf_rewind(VALUE argf)
13653 VALUE ret;
13654 int old_lineno;
13656 if (!next_argv()) {
13657 rb_raise(rb_eArgError, "no stream to rewind");
13659 ARGF_FORWARD(0, 0);
13660 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13661 ret = rb_io_rewind(ARGF.current_file);
13662 if (!global_argf_p(argf)) {
13663 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13665 return ret;
13669 * call-seq:
13670 * ARGF.fileno -> integer
13671 * ARGF.to_i -> integer
13673 * Returns an integer representing the numeric file descriptor for
13674 * the current file. Raises an ArgumentError if there isn't a current file.
13676 * ARGF.fileno #=> 3
13678 static VALUE
13679 argf_fileno(VALUE argf)
13681 if (!next_argv()) {
13682 rb_raise(rb_eArgError, "no stream");
13684 ARGF_FORWARD(0, 0);
13685 return rb_io_fileno(ARGF.current_file);
13689 * call-seq:
13690 * ARGF.to_io -> IO
13692 * Returns an IO object representing the current file. This will be a
13693 * File object unless the current file is a stream such as STDIN.
13695 * For example:
13697 * ARGF.to_io #=> #<File:glark.txt>
13698 * ARGF.to_io #=> #<IO:<STDIN>>
13700 static VALUE
13701 argf_to_io(VALUE argf)
13703 next_argv();
13704 ARGF_FORWARD(0, 0);
13705 return ARGF.current_file;
13709 * call-seq:
13710 * ARGF.eof? -> true or false
13711 * ARGF.eof -> true or false
13713 * Returns true if the current file in ARGF is at end of file, i.e. it has
13714 * no data to read. The stream must be opened for reading or an IOError
13715 * will be raised.
13717 * $ echo "eof" | ruby argf.rb
13719 * ARGF.eof? #=> false
13720 * 3.times { ARGF.readchar }
13721 * ARGF.eof? #=> false
13722 * ARGF.readchar #=> "\n"
13723 * ARGF.eof? #=> true
13726 static VALUE
13727 argf_eof(VALUE argf)
13729 next_argv();
13730 if (RTEST(ARGF.current_file)) {
13731 if (ARGF.init_p == 0) return Qtrue;
13732 next_argv();
13733 ARGF_FORWARD(0, 0);
13734 if (rb_io_eof(ARGF.current_file)) {
13735 return Qtrue;
13738 return Qfalse;
13742 * call-seq:
13743 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13745 * Reads _length_ bytes from ARGF. The files named on the command line
13746 * are concatenated and treated as a single file by this method, so when
13747 * called without arguments the contents of this pseudo file are returned in
13748 * their entirety.
13750 * _length_ must be a non-negative integer or +nil+.
13752 * If _length_ is a positive integer, +read+ tries to read
13753 * _length_ bytes without any conversion (binary mode).
13754 * It returns +nil+ if an EOF is encountered before anything can be read.
13755 * Fewer than _length_ bytes are returned if an EOF is encountered during
13756 * the read.
13757 * In the case of an integer _length_, the resulting string is always
13758 * in ASCII-8BIT encoding.
13760 * If _length_ is omitted or is +nil+, it reads until EOF
13761 * and the encoding conversion is applied, if applicable.
13762 * A string is returned even if EOF is encountered before any data is read.
13764 * If _length_ is zero, it returns an empty string (<code>""</code>).
13766 * If the optional _outbuf_ argument is present,
13767 * it must reference a String, which will receive the data.
13768 * The _outbuf_ will contain only the received data after the method call
13769 * even if it is not empty at the beginning.
13771 * For example:
13773 * $ echo "small" > small.txt
13774 * $ echo "large" > large.txt
13775 * $ ./glark.rb small.txt large.txt
13777 * ARGF.read #=> "small\nlarge"
13778 * ARGF.read(200) #=> "small\nlarge"
13779 * ARGF.read(2) #=> "sm"
13780 * ARGF.read(0) #=> ""
13782 * Note that this method behaves like the fread() function in C.
13783 * This means it retries to invoke read(2) system calls to read data
13784 * with the specified length.
13785 * If you need the behavior like a single read(2) system call,
13786 * consider ARGF#readpartial or ARGF#read_nonblock.
13789 static VALUE
13790 argf_read(int argc, VALUE *argv, VALUE argf)
13792 VALUE tmp, str, length;
13793 long len = 0;
13795 rb_scan_args(argc, argv, "02", &length, &str);
13796 if (!NIL_P(length)) {
13797 len = NUM2LONG(argv[0]);
13799 if (!NIL_P(str)) {
13800 StringValue(str);
13801 rb_str_resize(str,0);
13802 argv[1] = Qnil;
13805 retry:
13806 if (!next_argv()) {
13807 return str;
13809 if (ARGF_GENERIC_INPUT_P()) {
13810 tmp = argf_forward(argc, argv, argf);
13812 else {
13813 tmp = io_read(argc, argv, ARGF.current_file);
13815 if (NIL_P(str)) str = tmp;
13816 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13817 if (NIL_P(tmp) || NIL_P(length)) {
13818 if (ARGF.next_p != -1) {
13819 argf_close(argf);
13820 ARGF.next_p = 1;
13821 goto retry;
13824 else if (argc >= 1) {
13825 long slen = RSTRING_LEN(str);
13826 if (slen < len) {
13827 argv[0] = LONG2NUM(len - slen);
13828 goto retry;
13831 return str;
13834 struct argf_call_arg {
13835 int argc;
13836 VALUE *argv;
13837 VALUE argf;
13840 static VALUE
13841 argf_forward_call(VALUE arg)
13843 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13844 argf_forward(p->argc, p->argv, p->argf);
13845 return Qnil;
13848 static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13849 int nonblock);
13852 * call-seq:
13853 * ARGF.readpartial(maxlen) -> string
13854 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13856 * Reads at most _maxlen_ bytes from the ARGF stream.
13858 * If the optional _outbuf_ argument is present,
13859 * it must reference a String, which will receive the data.
13860 * The _outbuf_ will contain only the received data after the method call
13861 * even if it is not empty at the beginning.
13863 * It raises EOFError on end of ARGF stream.
13864 * Since ARGF stream is a concatenation of multiple files,
13865 * internally EOF is occur for each file.
13866 * ARGF.readpartial returns empty strings for EOFs except the last one and
13867 * raises EOFError for the last one.
13871 static VALUE
13872 argf_readpartial(int argc, VALUE *argv, VALUE argf)
13874 return argf_getpartial(argc, argv, argf, Qnil, 0);
13878 * call-seq:
13879 * ARGF.read_nonblock(maxlen[, options]) -> string
13880 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13882 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13885 static VALUE
13886 argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13888 VALUE opts;
13890 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13892 if (!NIL_P(opts))
13893 argc--;
13895 return argf_getpartial(argc, argv, argf, opts, 1);
13898 static VALUE
13899 argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13901 VALUE tmp, str, length;
13902 int no_exception;
13904 rb_scan_args(argc, argv, "11", &length, &str);
13905 if (!NIL_P(str)) {
13906 StringValue(str);
13907 argv[1] = str;
13909 no_exception = no_exception_p(opts);
13911 if (!next_argv()) {
13912 if (!NIL_P(str)) {
13913 rb_str_resize(str, 0);
13915 rb_eof_error();
13917 if (ARGF_GENERIC_INPUT_P()) {
13918 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13919 struct argf_call_arg arg;
13920 arg.argc = argc;
13921 arg.argv = argv;
13922 arg.argf = argf;
13923 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
13924 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
13926 else {
13927 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13929 if (NIL_P(tmp)) {
13930 if (ARGF.next_p == -1) {
13931 return io_nonblock_eof(no_exception);
13933 argf_close(argf);
13934 ARGF.next_p = 1;
13935 if (RARRAY_LEN(ARGF.argv) == 0) {
13936 return io_nonblock_eof(no_exception);
13938 if (NIL_P(str))
13939 str = rb_str_new(NULL, 0);
13940 return str;
13942 return tmp;
13946 * call-seq:
13947 * ARGF.getc -> String or nil
13949 * Reads the next character from ARGF and returns it as a String. Returns
13950 * +nil+ at the end of the stream.
13952 * ARGF treats the files named on the command line as a single file created
13953 * by concatenating their contents. After returning the last character of the
13954 * first file, it returns the first character of the second file, and so on.
13956 * For example:
13958 * $ echo "foo" > file
13959 * $ ruby argf.rb file
13961 * ARGF.getc #=> "f"
13962 * ARGF.getc #=> "o"
13963 * ARGF.getc #=> "o"
13964 * ARGF.getc #=> "\n"
13965 * ARGF.getc #=> nil
13966 * ARGF.getc #=> nil
13968 static VALUE
13969 argf_getc(VALUE argf)
13971 VALUE ch;
13973 retry:
13974 if (!next_argv()) return Qnil;
13975 if (ARGF_GENERIC_INPUT_P()) {
13976 ch = forward_current(rb_intern("getc"), 0, 0);
13978 else {
13979 ch = rb_io_getc(ARGF.current_file);
13981 if (NIL_P(ch) && ARGF.next_p != -1) {
13982 argf_close(argf);
13983 ARGF.next_p = 1;
13984 goto retry;
13987 return ch;
13991 * call-seq:
13992 * ARGF.getbyte -> Integer or nil
13994 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
13995 * the end of the stream.
13997 * For example:
13999 * $ echo "foo" > file
14000 * $ ruby argf.rb file
14002 * ARGF.getbyte #=> 102
14003 * ARGF.getbyte #=> 111
14004 * ARGF.getbyte #=> 111
14005 * ARGF.getbyte #=> 10
14006 * ARGF.getbyte #=> nil
14008 static VALUE
14009 argf_getbyte(VALUE argf)
14011 VALUE ch;
14013 retry:
14014 if (!next_argv()) return Qnil;
14015 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14016 ch = forward_current(rb_intern("getbyte"), 0, 0);
14018 else {
14019 ch = rb_io_getbyte(ARGF.current_file);
14021 if (NIL_P(ch) && ARGF.next_p != -1) {
14022 argf_close(argf);
14023 ARGF.next_p = 1;
14024 goto retry;
14027 return ch;
14031 * call-seq:
14032 * ARGF.readchar -> String or nil
14034 * Reads the next character from ARGF and returns it as a String. Raises
14035 * an EOFError after the last character of the last file has been read.
14037 * For example:
14039 * $ echo "foo" > file
14040 * $ ruby argf.rb file
14042 * ARGF.readchar #=> "f"
14043 * ARGF.readchar #=> "o"
14044 * ARGF.readchar #=> "o"
14045 * ARGF.readchar #=> "\n"
14046 * ARGF.readchar #=> end of file reached (EOFError)
14048 static VALUE
14049 argf_readchar(VALUE argf)
14051 VALUE ch;
14053 retry:
14054 if (!next_argv()) rb_eof_error();
14055 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14056 ch = forward_current(rb_intern("getc"), 0, 0);
14058 else {
14059 ch = rb_io_getc(ARGF.current_file);
14061 if (NIL_P(ch) && ARGF.next_p != -1) {
14062 argf_close(argf);
14063 ARGF.next_p = 1;
14064 goto retry;
14067 return ch;
14071 * call-seq:
14072 * ARGF.readbyte -> Integer
14074 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14075 * an EOFError after the last byte of the last file has been read.
14077 * For example:
14079 * $ echo "foo" > file
14080 * $ ruby argf.rb file
14082 * ARGF.readbyte #=> 102
14083 * ARGF.readbyte #=> 111
14084 * ARGF.readbyte #=> 111
14085 * ARGF.readbyte #=> 10
14086 * ARGF.readbyte #=> end of file reached (EOFError)
14088 static VALUE
14089 argf_readbyte(VALUE argf)
14091 VALUE c;
14093 NEXT_ARGF_FORWARD(0, 0);
14094 c = argf_getbyte(argf);
14095 if (NIL_P(c)) {
14096 rb_eof_error();
14098 return c;
14101 #define FOREACH_ARGF() while (next_argv())
14103 static VALUE
14104 argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14106 const VALUE current = ARGF.current_file;
14107 rb_yield_values2(argc, argv);
14108 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14109 rb_iter_break_value(Qundef);
14111 return Qnil;
14114 #define ARGF_block_call(mid, argc, argv, func, argf) \
14115 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14116 func, argf, rb_keyword_given_p())
14118 static void
14119 argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14121 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14122 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14125 static VALUE
14126 argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14128 if (!global_argf_p(argf)) {
14129 ARGF.last_lineno = ++ARGF.lineno;
14131 return argf_block_call_i(i, argf, argc, argv, blockarg);
14134 static void
14135 argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14137 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14138 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14142 * call-seq:
14143 * ARGF.each(sep=$/) {|line| block } -> ARGF
14144 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14145 * ARGF.each(...) -> an_enumerator
14147 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14148 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14149 * ARGF.each_line(...) -> an_enumerator
14151 * Returns an enumerator which iterates over each line (separated by _sep_,
14152 * which defaults to your platform's newline character) of each file in
14153 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14154 * block, otherwise an enumerator is returned.
14155 * The optional _limit_ argument is an Integer specifying the maximum
14156 * length of each line; longer lines will be split according to this limit.
14158 * This method allows you to treat the files supplied on the command line as
14159 * a single file consisting of the concatenation of each named file. After
14160 * the last line of the first file has been returned, the first line of the
14161 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14162 * used to determine the filename of the current line and line number of the
14163 * whole input, respectively.
14165 * For example, the following code prints out each line of each named file
14166 * prefixed with its line number, displaying the filename once per file:
14168 * ARGF.each_line do |line|
14169 * puts ARGF.filename if ARGF.file.lineno == 1
14170 * puts "#{ARGF.file.lineno}: #{line}"
14171 * end
14173 * While the following code prints only the first file's name at first, and
14174 * the contents with line number counted through all named files.
14176 * ARGF.each_line do |line|
14177 * puts ARGF.filename if ARGF.lineno == 1
14178 * puts "#{ARGF.lineno}: #{line}"
14179 * end
14181 static VALUE
14182 argf_each_line(int argc, VALUE *argv, VALUE argf)
14184 RETURN_ENUMERATOR(argf, argc, argv);
14185 FOREACH_ARGF() {
14186 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14188 return argf;
14192 * call-seq:
14193 * ARGF.each_byte {|byte| block } -> ARGF
14194 * ARGF.each_byte -> an_enumerator
14196 * Iterates over each byte of each file in +ARGV+.
14197 * A byte is returned as an Integer in the range 0..255.
14199 * This method allows you to treat the files supplied on the command line as
14200 * a single file consisting of the concatenation of each named file. After
14201 * the last byte of the first file has been returned, the first byte of the
14202 * second file is returned. The ARGF.filename method can be used to
14203 * determine the filename of the current byte.
14205 * If no block is given, an enumerator is returned instead.
14207 * For example:
14209 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14212 static VALUE
14213 argf_each_byte(VALUE argf)
14215 RETURN_ENUMERATOR(argf, 0, 0);
14216 FOREACH_ARGF() {
14217 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14219 return argf;
14223 * call-seq:
14224 * ARGF.each_char {|char| block } -> ARGF
14225 * ARGF.each_char -> an_enumerator
14227 * Iterates over each character of each file in ARGF.
14229 * This method allows you to treat the files supplied on the command line as
14230 * a single file consisting of the concatenation of each named file. After
14231 * the last character of the first file has been returned, the first
14232 * character of the second file is returned. The ARGF.filename method can
14233 * be used to determine the name of the file in which the current character
14234 * appears.
14236 * If no block is given, an enumerator is returned instead.
14238 static VALUE
14239 argf_each_char(VALUE argf)
14241 RETURN_ENUMERATOR(argf, 0, 0);
14242 FOREACH_ARGF() {
14243 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14245 return argf;
14249 * call-seq:
14250 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14251 * ARGF.each_codepoint -> an_enumerator
14253 * Iterates over each codepoint of each file in ARGF.
14255 * This method allows you to treat the files supplied on the command line as
14256 * a single file consisting of the concatenation of each named file. After
14257 * the last codepoint of the first file has been returned, the first
14258 * codepoint of the second file is returned. The ARGF.filename method can
14259 * be used to determine the name of the file in which the current codepoint
14260 * appears.
14262 * If no block is given, an enumerator is returned instead.
14264 static VALUE
14265 argf_each_codepoint(VALUE argf)
14267 RETURN_ENUMERATOR(argf, 0, 0);
14268 FOREACH_ARGF() {
14269 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14271 return argf;
14275 * call-seq:
14276 * ARGF.filename -> String
14277 * ARGF.path -> String
14279 * Returns the current filename. "-" is returned when the current file is
14280 * STDIN.
14282 * For example:
14284 * $ echo "foo" > foo
14285 * $ echo "bar" > bar
14286 * $ echo "glark" > glark
14288 * $ ruby argf.rb foo bar glark
14290 * ARGF.filename #=> "foo"
14291 * ARGF.read(5) #=> "foo\nb"
14292 * ARGF.filename #=> "bar"
14293 * ARGF.skip
14294 * ARGF.filename #=> "glark"
14296 static VALUE
14297 argf_filename(VALUE argf)
14299 next_argv();
14300 return ARGF.filename;
14303 static VALUE
14304 argf_filename_getter(ID id, VALUE *var)
14306 return argf_filename(*var);
14310 * call-seq:
14311 * ARGF.file -> IO or File object
14313 * Returns the current file as an IO or File object.
14314 * <code>$stdin</code> is returned when the current file is STDIN.
14316 * For example:
14318 * $ echo "foo" > foo
14319 * $ echo "bar" > bar
14321 * $ ruby argf.rb foo bar
14323 * ARGF.file #=> #<File:foo>
14324 * ARGF.read(5) #=> "foo\nb"
14325 * ARGF.file #=> #<File:bar>
14327 static VALUE
14328 argf_file(VALUE argf)
14330 next_argv();
14331 return ARGF.current_file;
14335 * call-seq:
14336 * ARGF.binmode -> ARGF
14338 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14339 * be reset to non-binary mode. This option has the following effects:
14341 * * Newline conversion is disabled.
14342 * * Encoding conversion is disabled.
14343 * * Content is treated as ASCII-8BIT.
14345 static VALUE
14346 argf_binmode_m(VALUE argf)
14348 ARGF.binmode = 1;
14349 next_argv();
14350 ARGF_FORWARD(0, 0);
14351 rb_io_ascii8bit_binmode(ARGF.current_file);
14352 return argf;
14356 * call-seq:
14357 * ARGF.binmode? -> true or false
14359 * Returns true if ARGF is being read in binary mode; false otherwise.
14360 * To enable binary mode use ARGF.binmode.
14362 * For example:
14364 * ARGF.binmode? #=> false
14365 * ARGF.binmode
14366 * ARGF.binmode? #=> true
14368 static VALUE
14369 argf_binmode_p(VALUE argf)
14371 return RBOOL(ARGF.binmode);
14375 * call-seq:
14376 * ARGF.skip -> ARGF
14378 * Sets the current file to the next file in ARGV. If there aren't any more
14379 * files it has no effect.
14381 * For example:
14383 * $ ruby argf.rb foo bar
14384 * ARGF.filename #=> "foo"
14385 * ARGF.skip
14386 * ARGF.filename #=> "bar"
14388 static VALUE
14389 argf_skip(VALUE argf)
14391 if (ARGF.init_p && ARGF.next_p == 0) {
14392 argf_close(argf);
14393 ARGF.next_p = 1;
14395 return argf;
14399 * call-seq:
14400 * ARGF.close -> ARGF
14402 * Closes the current file and skips to the next file in ARGV. If there are
14403 * no more files to open, just closes the current file. STDIN will not be
14404 * closed.
14406 * For example:
14408 * $ ruby argf.rb foo bar
14410 * ARGF.filename #=> "foo"
14411 * ARGF.close
14412 * ARGF.filename #=> "bar"
14413 * ARGF.close
14415 static VALUE
14416 argf_close_m(VALUE argf)
14418 next_argv();
14419 argf_close(argf);
14420 if (ARGF.next_p != -1) {
14421 ARGF.next_p = 1;
14423 ARGF.lineno = 0;
14424 return argf;
14428 * call-seq:
14429 * ARGF.closed? -> true or false
14431 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14432 * ARGF.close to actually close the current file.
14434 static VALUE
14435 argf_closed(VALUE argf)
14437 next_argv();
14438 ARGF_FORWARD(0, 0);
14439 return rb_io_closed_p(ARGF.current_file);
14443 * call-seq:
14444 * ARGF.to_s -> String
14446 * Returns "ARGF".
14448 static VALUE
14449 argf_to_s(VALUE argf)
14451 return rb_str_new2("ARGF");
14455 * call-seq:
14456 * ARGF.inplace_mode -> String
14458 * Returns the file extension appended to the names of backup copies of
14459 * modified files under in-place edit mode. This value can be set using
14460 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14462 static VALUE
14463 argf_inplace_mode_get(VALUE argf)
14465 if (!ARGF.inplace) return Qnil;
14466 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14467 return rb_str_dup(ARGF.inplace);
14470 static VALUE
14471 opt_i_get(ID id, VALUE *var)
14473 return argf_inplace_mode_get(*var);
14477 * call-seq:
14478 * ARGF.inplace_mode = ext -> ARGF
14480 * Sets the filename extension for in-place editing mode to the given String.
14481 * The backup copy of each file being edited has this value appended to its
14482 * filename.
14484 * For example:
14486 * $ ruby argf.rb file.txt
14488 * ARGF.inplace_mode = '.bak'
14489 * ARGF.each_line do |line|
14490 * print line.sub("foo","bar")
14491 * end
14493 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14494 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14495 * "bar".
14497 static VALUE
14498 argf_inplace_mode_set(VALUE argf, VALUE val)
14500 if (!RTEST(val)) {
14501 ARGF.inplace = Qfalse;
14503 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14504 ARGF.inplace = Qnil;
14506 else {
14507 ARGF.inplace = rb_str_new_frozen(val);
14509 return argf;
14512 static void
14513 opt_i_set(VALUE val, ID id, VALUE *var)
14515 argf_inplace_mode_set(*var, val);
14518 void
14519 ruby_set_inplace_mode(const char *suffix)
14521 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14525 * call-seq:
14526 * ARGF.argv -> ARGV
14528 * Returns the +ARGV+ array, which contains the arguments passed to your
14529 * script, one per element.
14531 * For example:
14533 * $ ruby argf.rb -v glark.txt
14535 * ARGF.argv #=> ["-v", "glark.txt"]
14538 static VALUE
14539 argf_argv(VALUE argf)
14541 return ARGF.argv;
14544 static VALUE
14545 argf_argv_getter(ID id, VALUE *var)
14547 return argf_argv(*var);
14550 VALUE
14551 rb_get_argv(void)
14553 return ARGF.argv;
14557 * call-seq:
14558 * ARGF.to_write_io -> io
14560 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14561 * enabled.
14563 static VALUE
14564 argf_write_io(VALUE argf)
14566 if (!RTEST(ARGF.current_file)) {
14567 rb_raise(rb_eIOError, "not opened for writing");
14569 return GetWriteIO(ARGF.current_file);
14573 * call-seq:
14574 * ARGF.write(*objects) -> integer
14576 * Writes each of the given +objects+ if inplace mode.
14578 static VALUE
14579 argf_write(int argc, VALUE *argv, VALUE argf)
14581 return rb_io_writev(argf_write_io(argf), argc, argv);
14584 void
14585 rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14587 rb_readwrite_syserr_fail(waiting, errno, mesg);
14590 void
14591 rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14593 VALUE arg, c = Qnil;
14594 arg = mesg ? rb_str_new2(mesg) : Qnil;
14595 switch (waiting) {
14596 case RB_IO_WAIT_WRITABLE:
14597 switch (n) {
14598 case EAGAIN:
14599 c = rb_eEAGAINWaitWritable;
14600 break;
14601 #if EAGAIN != EWOULDBLOCK
14602 case EWOULDBLOCK:
14603 c = rb_eEWOULDBLOCKWaitWritable;
14604 break;
14605 #endif
14606 case EINPROGRESS:
14607 c = rb_eEINPROGRESSWaitWritable;
14608 break;
14609 default:
14610 rb_mod_syserr_fail_str(rb_mWaitWritable, n, arg);
14612 break;
14613 case RB_IO_WAIT_READABLE:
14614 switch (n) {
14615 case EAGAIN:
14616 c = rb_eEAGAINWaitReadable;
14617 break;
14618 #if EAGAIN != EWOULDBLOCK
14619 case EWOULDBLOCK:
14620 c = rb_eEWOULDBLOCKWaitReadable;
14621 break;
14622 #endif
14623 case EINPROGRESS:
14624 c = rb_eEINPROGRESSWaitReadable;
14625 break;
14626 default:
14627 rb_mod_syserr_fail_str(rb_mWaitReadable, n, arg);
14629 break;
14630 default:
14631 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14633 rb_exc_raise(rb_class_new_instance(1, &arg, c));
14636 static VALUE
14637 get_LAST_READ_LINE(ID _x, VALUE *_y)
14639 return rb_lastline_get();
14642 static void
14643 set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14645 rb_lastline_set(val);
14649 * Document-class: IOError
14651 * Raised when an IO operation fails.
14653 * File.open("/etc/hosts") {|f| f << "example"}
14654 * #=> IOError: not opened for writing
14656 * File.open("/etc/hosts") {|f| f.close; f.read }
14657 * #=> IOError: closed stream
14659 * Note that some IO failures raise <code>SystemCallError</code>s
14660 * and these are not subclasses of IOError:
14662 * File.open("does/not/exist")
14663 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14667 * Document-class: EOFError
14669 * Raised by some IO operations when reaching the end of file. Many IO
14670 * methods exist in two forms,
14672 * one that returns +nil+ when the end of file is reached, the other
14673 * raises EOFError.
14675 * EOFError is a subclass of IOError.
14677 * file = File.open("/etc/hosts")
14678 * file.read
14679 * file.gets #=> nil
14680 * file.readline #=> EOFError: end of file reached
14681 * file.close
14685 * Document-class: ARGF
14687 * == \ARGF and +ARGV+
14689 * The \ARGF object works with the array at global variable +ARGV+
14690 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14692 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14694 * Initially, it contains the command-line arguments and options
14695 * that are passed to the Ruby program;
14696 * the program can modify that array as it likes.
14698 * - **ARGF** may be thought of as the <b>argument files</b> object.
14700 * It can access file streams and/or the <tt>$stdin</tt> stream,
14701 * based on what it finds in +ARGV+.
14702 * This provides a convenient way for the command line
14703 * to specify streams for a Ruby program to read.
14705 * == Reading
14707 * \ARGF may read from _source_ streams,
14708 * which at any particular time are determined by the content of +ARGV+.
14710 * === Simplest Case
14712 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14713 * the source is <tt>$stdin</tt>:
14715 * - \File +t.rb+:
14717 * p ['ARGV', ARGV]
14718 * p ['ARGF.read', ARGF.read]
14720 * - Commands and outputs
14721 * (see below for the content of files +foo.txt+ and +bar.txt+):
14723 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14724 * ["ARGV", []]
14725 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14727 * $ cat foo.txt bar.txt | ruby t.rb
14728 * ["ARGV", []]
14729 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14731 * === About the Examples
14733 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14735 * $ cat foo.txt
14736 * Foo 0
14737 * Foo 1
14738 * $ cat bar.txt
14739 * Bar 0
14740 * Bar 1
14741 * Bar 2
14742 * Bar 3
14744 * === Sources in +ARGV+
14746 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14747 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14748 * the sources are found in +ARGV+.
14750 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14751 * and is one of:
14753 * - The string path to a file that may be opened as a stream.
14754 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14756 * Each element that is _not_ one of these
14757 * should be removed from +ARGV+ before \ARGF accesses that source.
14759 * In the following example:
14761 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14762 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14764 * Example:
14766 * - \File +t.rb+:
14768 * # Print arguments (and options, if any) found on command line.
14769 * p ['ARGV', ARGV]
14771 * - Command and output:
14773 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14774 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14776 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14778 * - \File +t.rb+:
14780 * p "ARGV: #{ARGV}"
14781 * p "Line: #{ARGF.read}" # Read everything from all specified streams.
14783 * - Command and output:
14785 * $ ruby t.rb foo.txt bar.txt
14786 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14787 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14789 * Because the value at +ARGV+ is an ordinary array,
14790 * you can manipulate it to control which sources \ARGF considers:
14792 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14793 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14795 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14796 * when all sources have been accessed, the array is empty:
14798 * - \File +t.rb+:
14800 * until ARGV.empty? && ARGF.eof?
14801 * p "ARGV: #{ARGV}"
14802 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14803 * end
14805 * - Command and output:
14807 * $ ruby t.rb foo.txt bar.txt
14808 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14809 * "Line: Foo 0\n"
14810 * "ARGV: [\"bar.txt\"]"
14811 * "Line: Foo 1\n"
14812 * "ARGV: [\"bar.txt\"]"
14813 * "Line: Bar 0\n"
14814 * "ARGV: []"
14815 * "Line: Bar 1\n"
14816 * "ARGV: []"
14817 * "Line: Bar 2\n"
14818 * "ARGV: []"
14819 * "Line: Bar 3\n"
14821 * ==== Filepaths in +ARGV+
14823 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14825 * This program prints what it reads from files at the paths specified
14826 * on the command line:
14828 * - \File +t.rb+:
14830 * p ['ARGV', ARGV]
14831 * # Read and print all content from the specified sources.
14832 * p ['ARGF.read', ARGF.read]
14834 * - Command and output:
14836 * $ ruby t.rb foo.txt bar.txt
14837 * ["ARGV", [foo.txt, bar.txt]
14838 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14840 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14842 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14844 * - \File +t.rb+:
14846 * p ['ARGV', ARGV]
14847 * p ['ARGF.read', ARGF.read]
14849 * - Command and output:
14851 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14852 * ["ARGV", ["-"]]
14853 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14855 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14856 * (exception:
14857 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14859 * - Command and output:
14861 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14862 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14863 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14865 * ==== Mixtures and Repetitions in +ARGV+
14867 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14868 * and character <tt>'-'</tt>, including repetitions.
14870 * ==== Modifications to +ARGV+
14872 * The running Ruby program may make any modifications to the +ARGV+ array;
14873 * the current value of +ARGV+ affects \ARGF reading.
14875 * ==== Empty +ARGV+
14877 * For an empty +ARGV+, an \ARGF read method either returns +nil+
14878 * or raises an exception, depending on the specific method.
14880 * === More Read Methods
14882 * As seen above, method ARGF#read reads the content of all sources
14883 * into a single string.
14884 * Other \ARGF methods provide other ways to access that content;
14885 * these include:
14887 * - Byte access: #each_byte, #getbyte, #readbyte.
14888 * - Character access: #each_char, #getc, #readchar.
14889 * - Codepoint access: #each_codepoint.
14890 * - Line access: #each_line, #gets, #readline, #readlines.
14891 * - Source access: #read, #read_nonblock, #readpartial.
14893 * === About \Enumerable
14895 * \ARGF includes module Enumerable.
14896 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
14898 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
14899 * _not_ from +ARGV+;
14900 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
14901 * not an array of the strings from +ARGV+:
14903 * - \File +t.rb+:
14905 * p ['ARGV', ARGV]
14906 * p ['ARGF.entries', ARGF.entries]
14908 * - Command and output:
14910 * $ ruby t.rb foo.txt bar.txt
14911 * ["ARGV", ["foo.txt", "bar.txt"]]
14912 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
14914 * == Writing
14916 * If <i>inplace mode</i> is in effect,
14917 * \ARGF may write to target streams,
14918 * which at any particular time are determined by the content of ARGV.
14920 * Methods about inplace mode:
14922 * - #inplace_mode
14923 * - #inplace_mode=
14924 * - #to_write_io
14926 * Methods for writing:
14928 * - #print
14929 * - #printf
14930 * - #putc
14931 * - #puts
14932 * - #write
14937 * An instance of class \IO (commonly called a _stream_)
14938 * represents an input/output stream in the underlying operating system.
14939 * \Class \IO is the basis for input and output in Ruby.
14941 * \Class File is the only class in the Ruby core that is a subclass of \IO.
14942 * Some classes in the Ruby standard library are also subclasses of \IO;
14943 * these include TCPSocket and UDPSocket.
14945 * The global constant ARGF (also accessible as <tt>$<</tt>)
14946 * provides an IO-like stream that allows access to all file paths
14947 * found in ARGV (or found in STDIN if ARGV is empty).
14948 * ARGF is not itself a subclass of \IO.
14950 * \Class StringIO provides an IO-like stream that handles a String.
14951 * StringIO is not itself a subclass of \IO.
14953 * Important objects based on \IO include:
14955 * - $stdin.
14956 * - $stdout.
14957 * - $stderr.
14958 * - Instances of class File.
14960 * An instance of \IO may be created using:
14962 * - IO.new: returns a new \IO object for the given integer file descriptor.
14963 * - IO.open: passes a new \IO object to the given block.
14964 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
14965 * of a newly-launched subprocess.
14966 * - Kernel#open: Returns a new \IO object connected to a given source:
14967 * stream, file, or subprocess.
14969 * Like a File stream, an \IO stream has:
14971 * - A read/write mode, which may be read-only, write-only, or read/write;
14972 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
14973 * - A data mode, which may be text-only or binary;
14974 * see {Data Mode}[rdoc-ref:File@Data+Mode].
14975 * - Internal and external encodings;
14976 * see {Encodings}[rdoc-ref:File@Encodings].
14978 * And like other \IO streams, it has:
14980 * - A position, which determines where in the stream the next
14981 * read or write is to occur;
14982 * see {Position}[rdoc-ref:IO@Position].
14983 * - A line number, which is a special, line-oriented, "position"
14984 * (different from the position mentioned above);
14985 * see {Line Number}[rdoc-ref:IO@Line+Number].
14987 * == Extension <tt>io/console</tt>
14989 * Extension <tt>io/console</tt> provides numerous methods
14990 * for interacting with the console;
14991 * requiring it adds numerous methods to class \IO.
14993 * == Example Files
14995 * Many examples here use these variables:
14997 * :include: doc/examples/files.rdoc
14999 * == Open Options
15001 * A number of \IO methods accept optional keyword arguments
15002 * that determine how a new stream is to be opened:
15004 * - +:mode+: Stream mode.
15005 * - +:flags+: Integer file open flags;
15006 * If +mode+ is also given, the two are bitwise-ORed.
15007 * - +:external_encoding+: External encoding for the stream.
15008 * - +:internal_encoding+: Internal encoding for the stream.
15009 * <tt>'-'</tt> is a synonym for the default internal encoding.
15010 * If the value is +nil+ no conversion occurs.
15011 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15012 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15013 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15014 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15015 * when the stream closes; otherwise it remains open.
15016 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15017 * #path method.
15019 * Also available are the options offered in String#encode,
15020 * which may control conversion between external and internal encoding.
15022 * == Basic \IO
15024 * You can perform basic stream \IO with these methods,
15025 * which typically operate on multi-byte strings:
15027 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15028 * - IO#write: Writes zero or more strings to the stream;
15029 * each given object that is not already a string is converted via +to_s+.
15031 * === Position
15033 * An \IO stream has a nonnegative integer _position_,
15034 * which is the byte offset at which the next read or write is to occur.
15035 * A new stream has position zero (and line number zero);
15036 * method +rewind+ resets the position (and line number) to zero.
15038 * The relevant methods:
15040 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15041 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15042 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15043 * relative to a given position +whence+
15044 * (indicating the beginning, end, or current position).
15045 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15047 * === Open and Closed Streams
15049 * A new \IO stream may be open for reading, open for writing, or both.
15051 * A stream is automatically closed when claimed by the garbage collector.
15053 * Attempted reading or writing on a closed stream raises an exception.
15055 * The relevant methods:
15057 * - IO#close: Closes the stream for both reading and writing.
15058 * - IO#close_read: Closes the stream for reading.
15059 * - IO#close_write: Closes the stream for writing.
15060 * - IO#closed?: Returns whether the stream is closed.
15062 * === End-of-Stream
15064 * You can query whether a stream is positioned at its end:
15066 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15068 * You can reposition to end-of-stream by using method IO#seek:
15070 * f = File.new('t.txt')
15071 * f.eof? # => false
15072 * f.seek(0, :END)
15073 * f.eof? # => true
15074 * f.close
15076 * Or by reading all stream content (which is slower than using IO#seek):
15078 * f.rewind
15079 * f.eof? # => false
15080 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15081 * f.eof? # => true
15083 * == Line \IO
15085 * \Class \IO supports line-oriented
15086 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15088 * === Line Input
15090 * \Class \IO supports line-oriented input for
15091 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15093 * ==== \File Line Input
15095 * You can read lines from a file using these methods:
15097 * - IO.foreach: Reads each line and passes it to the given block.
15098 * - IO.readlines: Reads and returns all lines in an array.
15100 * For each of these methods:
15102 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15103 * - Line parsing depends on the effective <i>line separator</i>;
15104 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15105 * - The length of each returned line depends on the effective <i>line limit</i>;
15106 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15108 * ==== Stream Line Input
15110 * You can read lines from an \IO stream using these methods:
15112 * - IO#each_line: Reads each remaining line, passing it to the given block.
15113 * - IO#gets: Returns the next line.
15114 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15115 * - IO#readlines: Returns all remaining lines in an array.
15117 * For each of these methods:
15119 * - Reading may begin mid-line,
15120 * depending on the stream's _position_;
15121 * see {Position}[rdoc-ref:IO@Position].
15122 * - Line parsing depends on the effective <i>line separator</i>;
15123 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15124 * - The length of each returned line depends on the effective <i>line limit</i>;
15125 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15127 * ===== Line Separator
15129 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15130 * the string that determines what is considered a line;
15131 * it is sometimes called the <i>input record separator</i>.
15133 * The default line separator is taken from global variable <tt>$/</tt>,
15134 * whose initial value is <tt>"\n"</tt>.
15136 * Generally, the line to be read next is all data
15137 * from the current {position}[rdoc-ref:IO@Position]
15138 * to the next line separator
15139 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15141 * f = File.new('t.txt')
15142 * # Method gets with no sep argument returns the next line, according to $/.
15143 * f.gets # => "First line\n"
15144 * f.gets # => "Second line\n"
15145 * f.gets # => "\n"
15146 * f.gets # => "Fourth line\n"
15147 * f.gets # => "Fifth line\n"
15148 * f.close
15150 * You can use a different line separator by passing argument +sep+:
15152 * f = File.new('t.txt')
15153 * f.gets('l') # => "First l"
15154 * f.gets('li') # => "ine\nSecond li"
15155 * f.gets('lin') # => "ne\n\nFourth lin"
15156 * f.gets # => "e\n"
15157 * f.close
15159 * Or by setting global variable <tt>$/</tt>:
15161 * f = File.new('t.txt')
15162 * $/ = 'l'
15163 * f.gets # => "First l"
15164 * f.gets # => "ine\nSecond l"
15165 * f.gets # => "ine\n\nFourth l"
15166 * f.close
15168 * ===== Special Line Separator Values
15170 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15171 * accepts two special values for parameter +sep+:
15173 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15175 * f = File.new('t.txt')
15176 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15177 * f.close
15179 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15180 * (paragraphs being separated by two consecutive line separators):
15182 * f = File.new('t.txt')
15183 * f.gets('') # => "First line\nSecond line\n\n"
15184 * f.gets('') # => "Fourth line\nFifth line\n"
15185 * f.close
15187 * ===== Line Limit
15189 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15190 * uses an integer <i>line limit</i>,
15191 * which restricts the number of bytes that may be returned.
15192 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15193 * than the limit).
15195 * The default limit value is <tt>-1</tt>;
15196 * any negative limit value means that there is no limit.
15198 * If there is no limit, the line is determined only by +sep+.
15200 * # Text with 1-byte characters.
15201 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15202 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15203 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15204 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15205 * # No more than one line.
15206 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15207 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15208 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15210 * # Text with 2-byte characters, which will not be split.
15211 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15212 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15213 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15214 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15216 * ===== Line Separator and Line Limit
15218 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15220 * - Returns the next line as determined by line separator +sep+.
15221 * - But returns no more bytes than are allowed by the limit +limit+.
15223 * Example:
15225 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15226 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15228 * ===== Line Number
15230 * A readable \IO stream has a non-negative integer <i>line number</i>:
15232 * - IO#lineno: Returns the line number.
15233 * - IO#lineno=: Resets and returns the line number.
15235 * Unless modified by a call to method IO#lineno=,
15236 * the line number is the number of lines read
15237 * by certain line-oriented methods,
15238 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15240 * - IO.foreach: Increments the line number on each call to the block.
15241 * - IO#each_line: Increments the line number on each call to the block.
15242 * - IO#gets: Increments the line number.
15243 * - IO#readline: Increments the line number.
15244 * - IO#readlines: Increments the line number for each line read.
15246 * A new stream is initially has line number zero (and position zero);
15247 * method +rewind+ resets the line number (and position) to zero:
15249 * f = File.new('t.txt')
15250 * f.lineno # => 0
15251 * f.gets # => "First line\n"
15252 * f.lineno # => 1
15253 * f.rewind
15254 * f.lineno # => 0
15255 * f.close
15257 * Reading lines from a stream usually changes its line number:
15259 * f = File.new('t.txt', 'r')
15260 * f.lineno # => 0
15261 * f.readline # => "This is line one.\n"
15262 * f.lineno # => 1
15263 * f.readline # => "This is the second line.\n"
15264 * f.lineno # => 2
15265 * f.readline # => "Here's the third line.\n"
15266 * f.lineno # => 3
15267 * f.eof? # => true
15268 * f.close
15270 * Iterating over lines in a stream usually changes its line number:
15272 * File.open('t.txt') do |f|
15273 * f.each_line do |line|
15274 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15275 * end
15276 * end
15278 * Output:
15280 * "position=11 eof?=false lineno=1"
15281 * "position=23 eof?=false lineno=2"
15282 * "position=24 eof?=false lineno=3"
15283 * "position=36 eof?=false lineno=4"
15284 * "position=47 eof?=true lineno=5"
15286 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15287 * the line number does not affect where the next read or write will occur:
15289 * f = File.new('t.txt')
15290 * f.lineno = 1000
15291 * f.lineno # => 1000
15292 * f.gets # => "First line\n"
15293 * f.lineno # => 1001
15294 * f.close
15296 * Associated with the line number is the global variable <tt>$.</tt>:
15298 * - When a stream is opened, <tt>$.</tt> is not set;
15299 * its value is left over from previous activity in the process:
15301 * $. = 41
15302 * f = File.new('t.txt')
15303 * $. = 41
15304 * # => 41
15305 * f.close
15307 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15309 * f0 = File.new('t.txt')
15310 * f1 = File.new('t.dat')
15311 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15312 * $. # => 5
15313 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15314 * $. # => 1
15315 * f0.close
15316 * f1.close
15318 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15320 * f = File.new('t.txt')
15321 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15322 * $. # => 5
15323 * f.rewind
15324 * f.seek(0, :SET)
15325 * $. # => 5
15326 * f.close
15328 * === Line Output
15330 * You can write to an \IO stream line-by-line using this method:
15332 * - IO#puts: Writes objects to the stream.
15334 * == Character \IO
15336 * You can process an \IO stream character-by-character using these methods:
15338 * - IO#getc: Reads and returns the next character from the stream.
15339 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15340 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15341 * - IO#putc: Writes a character to the stream.
15342 * - IO#each_char: Reads each remaining character in the stream,
15343 * passing the character to the given block.
15344 * == Byte \IO
15346 * You can process an \IO stream byte-by-byte using these methods:
15348 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15349 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15350 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15351 * - IO#each_byte: Reads each remaining byte in the stream,
15352 * passing the byte to the given block.
15354 * == Codepoint \IO
15356 * You can process an \IO stream codepoint-by-codepoint:
15358 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15360 * == What's Here
15362 * First, what's elsewhere. \Class \IO:
15364 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15365 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15366 * which provides dozens of additional methods.
15368 * Here, class \IO provides methods that are useful for:
15370 * - {Creating}[rdoc-ref:IO@Creating]
15371 * - {Reading}[rdoc-ref:IO@Reading]
15372 * - {Writing}[rdoc-ref:IO@Writing]
15373 * - {Positioning}[rdoc-ref:IO@Positioning]
15374 * - {Iterating}[rdoc-ref:IO@Iterating]
15375 * - {Settings}[rdoc-ref:IO@Settings]
15376 * - {Querying}[rdoc-ref:IO@Querying]
15377 * - {Buffering}[rdoc-ref:IO@Buffering]
15378 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15379 * - {Other}[rdoc-ref:IO@Other]
15381 * === Creating
15383 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15384 * integer file descriptor.
15385 * - ::open: Creates a new \IO object.
15386 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15387 * - ::popen: Creates an \IO object to interact with a subprocess.
15388 * - ::select: Selects which given \IO instances are ready for reading,
15389 * writing, or have pending exceptions.
15391 * === Reading
15393 * - ::binread: Returns a binary string with all or a subset of bytes
15394 * from the given file.
15395 * - ::read: Returns a string with all or a subset of bytes from the given file.
15396 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15397 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15398 * - #getc: Returns the next character read from +self+ as a string.
15399 * - #gets: Returns the line read from +self+.
15400 * - #pread: Returns all or the next _n_ bytes read from +self+,
15401 * not updating the receiver's offset.
15402 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15403 * for a given _n_.
15404 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15405 * in non-block mode.
15406 * - #readbyte: Returns the next byte read from +self+;
15407 * same as #getbyte, but raises an exception on end-of-stream.
15408 * - #readchar: Returns the next character read from +self+;
15409 * same as #getc, but raises an exception on end-of-stream.
15410 * - #readline: Returns the next line read from +self+;
15411 * same as #getline, but raises an exception of end-of-stream.
15412 * - #readlines: Returns an array of all lines read read from +self+.
15413 * - #readpartial: Returns up to the given number of bytes from +self+.
15415 * === Writing
15417 * - ::binwrite: Writes the given string to the file at the given filepath,
15418 * in binary mode.
15419 * - ::write: Writes the given string to +self+.
15420 * - #<<: Appends the given string to +self+.
15421 * - #print: Prints last read line or given objects to +self+.
15422 * - #printf: Writes to +self+ based on the given format string and objects.
15423 * - #putc: Writes a character to +self+.
15424 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15425 * - #pwrite: Writes the given string at the given offset,
15426 * not updating the receiver's offset.
15427 * - #write: Writes one or more given strings to +self+.
15428 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15430 * === Positioning
15432 * - #lineno: Returns the current line number in +self+.
15433 * - #lineno=: Sets the line number is +self+.
15434 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15435 * - #pos=: Sets the byte offset in +self+.
15436 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15437 * - #rewind: Positions +self+ to the beginning of input.
15438 * - #seek: Sets the offset for +self+ relative to given position.
15440 * === Iterating
15442 * - ::foreach: Yields each line of given file to the block.
15443 * - #each (aliased as #each_line): Calls the given block
15444 * with each successive line in +self+.
15445 * - #each_byte: Calls the given block with each successive byte in +self+
15446 * as an integer.
15447 * - #each_char: Calls the given block with each successive character in +self+
15448 * as a string.
15449 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15450 * as an integer.
15452 * === Settings
15454 * - #autoclose=: Sets whether +self+ auto-closes.
15455 * - #binmode: Sets +self+ to binary mode.
15456 * - #close: Closes +self+.
15457 * - #close_on_exec=: Sets the close-on-exec flag.
15458 * - #close_read: Closes +self+ for reading.
15459 * - #close_write: Closes +self+ for writing.
15460 * - #set_encoding: Sets the encoding for +self+.
15461 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15462 * Unicode byte-order-mark.
15463 * - #sync=: Sets the sync-mode to the given value.
15465 * === Querying
15467 * - #autoclose?: Returns whether +self+ auto-closes.
15468 * - #binmode?: Returns whether +self+ is in binary mode.
15469 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15470 * - #closed?: Returns whether +self+ is closed.
15471 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15472 * - #external_encoding: Returns the external encoding object for +self+.
15473 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15474 * - #internal_encoding: Returns the internal encoding object for +self+.
15475 * - #pid: Returns the process ID of a child process associated with +self+,
15476 * if +self+ was created by ::popen.
15477 * - #stat: Returns the File::Stat object containing status information for +self+.
15478 * - #sync: Returns whether +self+ is in sync-mode.
15479 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15481 * === Buffering
15483 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15484 * - #flush: Flushes any buffered data within +self+ to the underlying
15485 * operating system.
15486 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15487 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15488 * - #ungetc: Prepends buffer for +self+ with given string.
15490 * === Low-Level Access
15492 * - ::sysopen: Opens the file given by its path,
15493 * returning the integer file descriptor.
15494 * - #advise: Announces the intention to access data from +self+ in a specific way.
15495 * - #fcntl: Passes a low-level command to the file specified
15496 * by the given file descriptor.
15497 * - #ioctl: Passes a low-level command to the device specified
15498 * by the given file descriptor.
15499 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15500 * - #sysseek: Sets the offset for +self+.
15501 * - #syswrite: Writes the given string to +self+ using a low-level write.
15503 * === Other
15505 * - ::copy_stream: Copies data from a source to a destination,
15506 * each of which is a filepath or an \IO-like object.
15507 * - ::try_convert: Returns a new \IO object resulting from converting
15508 * the given object.
15509 * - #inspect: Returns the string representation of +self+.
15513 void
15514 Init_IO(void)
15516 VALUE rb_cARGF;
15517 #ifdef __CYGWIN__
15518 #include <sys/cygwin.h>
15519 static struct __cygwin_perfile pf[] =
15521 {"", O_RDONLY | O_BINARY},
15522 {"", O_WRONLY | O_BINARY},
15523 {"", O_RDWR | O_BINARY},
15524 {"", O_APPEND | O_BINARY},
15525 {NULL, 0}
15527 cygwin_internal(CW_PERFILE, pf);
15528 #endif
15530 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15531 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15533 id_write = rb_intern_const("write");
15534 id_read = rb_intern_const("read");
15535 id_getc = rb_intern_const("getc");
15536 id_flush = rb_intern_const("flush");
15537 id_readpartial = rb_intern_const("readpartial");
15538 id_set_encoding = rb_intern_const("set_encoding");
15539 id_fileno = rb_intern_const("fileno");
15541 rb_define_global_function("syscall", rb_f_syscall, -1);
15543 rb_define_global_function("open", rb_f_open, -1);
15544 rb_define_global_function("printf", rb_f_printf, -1);
15545 rb_define_global_function("print", rb_f_print, -1);
15546 rb_define_global_function("putc", rb_f_putc, 1);
15547 rb_define_global_function("puts", rb_f_puts, -1);
15548 rb_define_global_function("gets", rb_f_gets, -1);
15549 rb_define_global_function("readline", rb_f_readline, -1);
15550 rb_define_global_function("select", rb_f_select, -1);
15552 rb_define_global_function("readlines", rb_f_readlines, -1);
15554 rb_define_global_function("`", rb_f_backquote, 1);
15556 rb_define_global_function("p", rb_f_p, -1);
15557 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15559 rb_cIO = rb_define_class("IO", rb_cObject);
15560 rb_include_module(rb_cIO, rb_mEnumerable);
15562 /* Can be raised by IO operations when IO#timeout= is set. */
15563 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15565 /* Readable event mask for IO#wait. */
15566 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15567 /* Writable event mask for IO#wait. */
15568 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15569 /* Priority event mask for IO#wait. */
15570 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15572 /* exception to wait for reading. see IO.select. */
15573 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15574 /* exception to wait for writing. see IO.select. */
15575 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15576 /* exception to wait for reading by EAGAIN. see IO.select. */
15577 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15578 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15579 /* exception to wait for writing by EAGAIN. see IO.select. */
15580 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15581 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15582 #if EAGAIN == EWOULDBLOCK
15583 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15584 /* same as IO::EAGAINWaitReadable */
15585 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15586 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15587 /* same as IO::EAGAINWaitWritable */
15588 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15589 #else
15590 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15591 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15592 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15593 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15594 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15595 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15596 #endif
15597 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15598 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15599 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15600 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15601 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15602 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15604 #if 0
15605 /* This is necessary only for forcing rdoc handle File::open */
15606 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15607 #endif
15609 rb_define_alloc_func(rb_cIO, io_alloc);
15610 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15611 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15612 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15613 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15614 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15615 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15616 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15617 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15618 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15619 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15620 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15621 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15622 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15623 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15624 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15626 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15628 rb_output_fs = Qnil;
15629 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15631 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15632 rb_vm_register_global_object(rb_default_rs);
15633 rb_rs = rb_default_rs;
15634 rb_output_rs = Qnil;
15635 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15636 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15637 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15639 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15640 rb_gvar_ractor_local("$_");
15642 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15643 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15645 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15646 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15647 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15648 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15650 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15651 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15652 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15653 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15654 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15656 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15657 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15659 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15660 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15662 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15663 rb_define_alias(rb_cIO, "to_i", "fileno");
15664 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15666 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15667 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15669 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15670 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15671 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15672 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15674 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15675 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15677 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15679 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15680 rb_define_method(rb_cIO, "read", io_read, -1);
15681 rb_define_method(rb_cIO, "write", io_write_m, -1);
15682 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15683 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15684 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15685 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15686 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15687 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15688 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15689 rb_define_method(rb_cIO, "<<", rb_io_addstr, 1);
15690 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15691 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15692 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15693 /* Set I/O position from the beginning */
15694 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15695 /* Set I/O position from the current position */
15696 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15697 /* Set I/O position from the end */
15698 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15699 #ifdef SEEK_DATA
15700 /* Set I/O position to the next location containing data */
15701 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15702 #endif
15703 #ifdef SEEK_HOLE
15704 /* Set I/O position to the next hole */
15705 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15706 #endif
15707 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15708 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15709 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15710 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15711 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15713 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15714 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15716 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15717 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15718 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15719 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15721 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15722 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15723 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15724 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15725 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15726 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15728 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15729 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15730 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15732 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15733 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15735 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15737 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15738 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15739 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15740 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15742 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15743 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15745 rb_define_method(rb_cIO, "wait", io_wait, -1);
15747 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15748 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15749 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15751 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15752 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15753 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15754 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15756 rb_gvar_ractor_local("$stdin");
15757 rb_gvar_ractor_local("$stdout");
15758 rb_gvar_ractor_local("$>");
15759 rb_gvar_ractor_local("$stderr");
15761 rb_global_variable(&rb_stdin);
15762 rb_stdin = rb_io_prep_stdin();
15763 rb_global_variable(&rb_stdout);
15764 rb_stdout = rb_io_prep_stdout();
15765 rb_global_variable(&rb_stderr);
15766 rb_stderr = rb_io_prep_stderr();
15768 orig_stdout = rb_stdout;
15769 orig_stderr = rb_stderr;
15771 /* Holds the original stdin */
15772 rb_define_global_const("STDIN", rb_stdin);
15773 /* Holds the original stdout */
15774 rb_define_global_const("STDOUT", rb_stdout);
15775 /* Holds the original stderr */
15776 rb_define_global_const("STDERR", rb_stderr);
15778 #if 0
15779 /* Hack to get rdoc to regard ARGF as a class: */
15780 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15781 #endif
15783 rb_cARGF = rb_class_new(rb_cObject);
15784 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15785 rb_define_alloc_func(rb_cARGF, argf_alloc);
15787 rb_include_module(rb_cARGF, rb_mEnumerable);
15789 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15790 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15791 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15792 rb_define_alias(rb_cARGF, "inspect", "to_s");
15793 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15795 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15796 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15797 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15798 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15799 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15800 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15801 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15802 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15803 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15805 rb_define_method(rb_cARGF, "read", argf_read, -1);
15806 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15807 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15808 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15809 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15810 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15811 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15812 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15813 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15814 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15815 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15816 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15817 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15818 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15819 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15820 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15821 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15822 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15823 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15824 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15826 rb_define_method(rb_cARGF, "write", argf_write, -1);
15827 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15828 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15829 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15830 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15832 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15833 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15834 rb_define_method(rb_cARGF, "file", argf_file, 0);
15835 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15836 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15837 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15839 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15840 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15842 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15843 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15845 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15846 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15847 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15849 argf = rb_class_new_instance(0, 0, rb_cARGF);
15851 rb_define_readonly_variable("$<", &argf);
15853 * ARGF is a stream designed for use in scripts that process files given
15854 * as command-line arguments or passed in via STDIN.
15856 * See ARGF (the class) for more details.
15858 rb_define_global_const("ARGF", argf);
15860 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15861 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15862 ARGF.filename = rb_str_new2("-");
15864 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15865 rb_gvar_ractor_local("$-i");
15867 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15869 #if defined (_WIN32) || defined(__CYGWIN__)
15870 atexit(pipe_atexit);
15871 #endif
15873 Init_File();
15875 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15877 sym_mode = ID2SYM(rb_intern_const("mode"));
15878 sym_perm = ID2SYM(rb_intern_const("perm"));
15879 sym_flags = ID2SYM(rb_intern_const("flags"));
15880 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15881 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15882 sym_encoding = ID2SYM(rb_id_encoding());
15883 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15884 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15885 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15886 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15887 sym_normal = ID2SYM(rb_intern_const("normal"));
15888 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15889 sym_random = ID2SYM(rb_intern_const("random"));
15890 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15891 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15892 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15893 sym_SET = ID2SYM(rb_intern_const("SET"));
15894 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15895 sym_END = ID2SYM(rb_intern_const("END"));
15896 #ifdef SEEK_DATA
15897 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15898 #endif
15899 #ifdef SEEK_HOLE
15900 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15901 #endif
15902 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15903 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15906 #include "io.rbinc"