* 2022-01-18 [ci skip]
[ruby-80x24.org.git] / io.c
blob0973bd604fe9d7d65aeb728fadd6fd7d924c7aee
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 #ifdef _WIN32
20 # include "ruby/ruby.h"
21 # include "ruby/io.h"
22 #endif
24 #include <ctype.h>
25 #include <errno.h>
26 #include <stddef.h>
28 /* non-Linux poll may not work on all FDs */
29 #if defined(HAVE_POLL)
30 # if defined(__linux__)
31 # define USE_POLL 1
32 # endif
33 # if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
34 # define USE_POLL 1
35 # endif
36 #endif
38 #ifndef USE_POLL
39 # define USE_POLL 0
40 #endif
42 #undef free
43 #define free(x) xfree(x)
45 #if defined(DOSISH) || defined(__CYGWIN__)
46 #include <io.h>
47 #endif
49 #include <sys/types.h>
50 #if defined HAVE_NET_SOCKET_H
51 # include <net/socket.h>
52 #elif defined HAVE_SYS_SOCKET_H
53 # include <sys/socket.h>
54 #endif
56 #if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
57 # define NO_SAFE_RENAME
58 #endif
60 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
61 # define USE_SETVBUF
62 #endif
64 #ifdef __QNXNTO__
65 #include <unix.h>
66 #endif
68 #include <sys/types.h>
69 #if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
70 #include <sys/ioctl.h>
71 #endif
72 #if defined(HAVE_FCNTL_H) || defined(_WIN32)
73 #include <fcntl.h>
74 #elif defined(HAVE_SYS_FCNTL_H)
75 #include <sys/fcntl.h>
76 #endif
78 #if !HAVE_OFF_T && !defined(off_t)
79 # define off_t long
80 #endif
82 #ifdef HAVE_SYS_TIME_H
83 # include <sys/time.h>
84 #endif
86 #include <sys/stat.h>
88 #if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
89 # include <sys/param.h>
90 #endif
92 #if !defined NOFILE
93 # define NOFILE 64
94 #endif
96 #ifdef HAVE_UNISTD_H
97 #include <unistd.h>
98 #endif
100 #ifdef HAVE_SYSCALL_H
101 #include <syscall.h>
102 #elif defined HAVE_SYS_SYSCALL_H
103 #include <sys/syscall.h>
104 #endif
106 #ifdef HAVE_SYS_UIO_H
107 #include <sys/uio.h>
108 #endif
110 #ifdef HAVE_SYS_WAIT_H
111 # include <sys/wait.h> /* for WNOHANG on BSD */
112 #endif
114 #ifdef HAVE_COPYFILE_H
115 # include <copyfile.h>
116 #endif
118 #include "ruby/internal/stdbool.h"
119 #include "ccan/list/list.h"
120 #include "dln.h"
121 #include "encindex.h"
122 #include "id.h"
123 #include "internal.h"
124 #include "internal/encoding.h"
125 #include "internal/error.h"
126 #include "internal/inits.h"
127 #include "internal/io.h"
128 #include "internal/numeric.h"
129 #include "internal/object.h"
130 #include "internal/process.h"
131 #include "internal/thread.h"
132 #include "internal/transcode.h"
133 #include "internal/variable.h"
134 #include "ruby/io.h"
135 #include "ruby/io/buffer.h"
136 #include "ruby/thread.h"
137 #include "ruby/util.h"
138 #include "ruby_atomic.h"
139 #include "ruby/ractor.h"
141 #if !USE_POLL
142 # include "vm_core.h"
143 #endif
145 #include "builtin.h"
147 #ifndef O_ACCMODE
148 #define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
149 #endif
151 #if SIZEOF_OFF_T > SIZEOF_LONG && !defined(HAVE_LONG_LONG)
152 # error off_t is bigger than long, but you have no long long...
153 #endif
155 #ifndef PIPE_BUF
156 # ifdef _POSIX_PIPE_BUF
157 # define PIPE_BUF _POSIX_PIPE_BUF
158 # else
159 # define PIPE_BUF 512 /* is this ok? */
160 # endif
161 #endif
163 #ifndef EWOULDBLOCK
164 # define EWOULDBLOCK EAGAIN
165 #endif
167 #if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
168 /* Mac OS X and OpenBSD have __syscall but don't define it in headers */
169 off_t __syscall(quad_t number, ...);
170 #endif
172 #define IO_RBUF_CAPA_MIN 8192
173 #define IO_CBUF_CAPA_MIN (128*1024)
174 #define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
175 #define IO_WBUF_CAPA_MIN 8192
177 /* define system APIs */
178 #ifdef _WIN32
179 #undef open
180 #define open rb_w32_uopen
181 #undef rename
182 #define rename(f, t) rb_w32_urename((f), (t))
183 #endif
185 VALUE rb_cIO;
186 VALUE rb_eEOFError;
187 VALUE rb_eIOError;
188 VALUE rb_mWaitReadable;
189 VALUE rb_mWaitWritable;
191 static VALUE rb_eEAGAINWaitReadable;
192 static VALUE rb_eEAGAINWaitWritable;
193 static VALUE rb_eEWOULDBLOCKWaitReadable;
194 static VALUE rb_eEWOULDBLOCKWaitWritable;
195 static VALUE rb_eEINPROGRESSWaitWritable;
196 static VALUE rb_eEINPROGRESSWaitReadable;
198 VALUE rb_stdin, rb_stdout, rb_stderr;
199 static VALUE orig_stdout, orig_stderr;
201 VALUE rb_output_fs;
202 VALUE rb_rs;
203 VALUE rb_output_rs;
204 VALUE rb_default_rs;
206 static VALUE argf;
208 static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
209 static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
210 static VALUE sym_textmode, sym_binmode, sym_autoclose;
211 static VALUE sym_SET, sym_CUR, sym_END;
212 static VALUE sym_wait_readable, sym_wait_writable;
213 #ifdef SEEK_DATA
214 static VALUE sym_DATA;
215 #endif
216 #ifdef SEEK_HOLE
217 static VALUE sym_HOLE;
218 #endif
220 static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
222 struct argf {
223 VALUE filename, current_file;
224 long last_lineno; /* $. */
225 long lineno;
226 VALUE argv;
227 VALUE inplace;
228 struct rb_io_enc_t encs;
229 int8_t init_p, next_p, binmode;
232 static rb_atomic_t max_file_descriptor = NOFILE;
233 void
234 rb_update_max_fd(int fd)
236 rb_atomic_t afd = (rb_atomic_t)fd;
237 rb_atomic_t max_fd = max_file_descriptor;
238 int err;
240 if (fd < 0 || afd <= max_fd)
241 return;
243 #if defined(HAVE_FCNTL) && defined(F_GETFL)
244 err = fcntl(fd, F_GETFL) == -1;
245 #else
247 struct stat buf;
248 err = fstat(fd, &buf) != 0;
250 #endif
251 if (err && errno == EBADF) {
252 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
255 while (max_fd < afd) {
256 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
260 void
261 rb_maygvl_fd_fix_cloexec(int fd)
263 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
264 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
265 int flags, flags2, ret;
266 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
267 if (flags == -1) {
268 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
270 if (fd <= 2)
271 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
272 else
273 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
274 if (flags != flags2) {
275 ret = fcntl(fd, F_SETFD, flags2);
276 if (ret != 0) {
277 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
280 #endif
283 void
284 rb_fd_fix_cloexec(int fd)
286 rb_maygvl_fd_fix_cloexec(fd);
287 rb_update_max_fd(fd);
290 /* this is only called once */
291 static int
292 rb_fix_detect_o_cloexec(int fd)
294 #if defined(O_CLOEXEC) && defined(F_GETFD)
295 int flags = fcntl(fd, F_GETFD);
297 if (flags == -1)
298 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
300 if (flags & FD_CLOEXEC)
301 return 1;
302 #endif /* fall through if O_CLOEXEC does not work: */
303 rb_maygvl_fd_fix_cloexec(fd);
304 return 0;
307 static inline bool
308 io_again_p(int e)
310 return (e == EWOULDBLOCK) || (e == EAGAIN);
314 rb_cloexec_open(const char *pathname, int flags, mode_t mode)
316 int ret;
317 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
319 static const int retry_interval = 0;
320 static const int retry_max_count = 10000;
322 int retry_count = 0;
324 #ifdef O_CLOEXEC
325 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
326 flags |= O_CLOEXEC;
327 #elif defined O_NOINHERIT
328 flags |= O_NOINHERIT;
329 #endif
331 while ((ret = open(pathname, flags, mode)) == -1) {
332 int e = errno;
333 if (!io_again_p(e)) break;
334 if (retry_count++ >= retry_max_count) break;
336 sleep(retry_interval);
339 if (ret < 0) return ret;
340 if (ret <= 2 || o_cloexec_state == 0) {
341 rb_maygvl_fd_fix_cloexec(ret);
343 else if (o_cloexec_state > 0) {
344 return ret;
346 else {
347 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
349 return ret;
353 rb_cloexec_dup(int oldfd)
355 /* Don't allocate standard file descriptors: 0, 1, 2 */
356 return rb_cloexec_fcntl_dupfd(oldfd, 3);
360 rb_cloexec_dup2(int oldfd, int newfd)
362 int ret;
364 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
365 * rb_cloexec_dup2 succeeds as dup2. */
366 if (oldfd == newfd) {
367 ret = newfd;
369 else {
370 #if defined(HAVE_DUP3) && defined(O_CLOEXEC)
371 static int try_dup3 = 1;
372 if (2 < newfd && try_dup3) {
373 ret = dup3(oldfd, newfd, O_CLOEXEC);
374 if (ret != -1)
375 return ret;
376 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
377 if (errno == ENOSYS) {
378 try_dup3 = 0;
379 ret = dup2(oldfd, newfd);
382 else {
383 ret = dup2(oldfd, newfd);
385 #else
386 ret = dup2(oldfd, newfd);
387 #endif
388 if (ret < 0) return ret;
390 rb_maygvl_fd_fix_cloexec(ret);
391 return ret;
394 static int
395 rb_fd_set_nonblock(int fd)
397 #ifdef _WIN32
398 return rb_w32_set_nonblock(fd);
399 #elif defined(F_GETFL)
400 int oflags = fcntl(fd, F_GETFL);
402 if (oflags == -1)
403 return -1;
404 if (oflags & O_NONBLOCK)
405 return 0;
406 oflags |= O_NONBLOCK;
407 return fcntl(fd, F_SETFL, oflags);
408 #endif
409 return 0;
413 rb_cloexec_pipe(int descriptors[2])
415 #ifdef HAVE_PIPE2
416 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
417 #else
418 int result = pipe(descriptors);
419 #endif
421 if (result < 0)
422 return result;
424 #ifdef __CYGWIN__
425 if (result == 0 && descriptors[1] == -1) {
426 close(descriptors[0]);
427 descriptors[0] = -1;
428 errno = ENFILE;
429 return -1;
431 #endif
433 #ifndef HAVE_PIPE2
434 rb_maygvl_fd_fix_cloexec(descriptors[0]);
435 rb_maygvl_fd_fix_cloexec(descriptors[1]);
437 #ifndef _WIN32
438 rb_fd_set_nonblock(descriptors[0]);
439 rb_fd_set_nonblock(descriptors[1]);
440 #endif
441 #endif
443 return result;
447 rb_cloexec_fcntl_dupfd(int fd, int minfd)
449 int ret;
451 #if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
452 static int try_dupfd_cloexec = 1;
453 if (try_dupfd_cloexec) {
454 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
455 if (ret != -1) {
456 if (ret <= 2)
457 rb_maygvl_fd_fix_cloexec(ret);
458 return ret;
460 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
461 if (errno == EINVAL) {
462 ret = fcntl(fd, F_DUPFD, minfd);
463 if (ret != -1) {
464 try_dupfd_cloexec = 0;
468 else {
469 ret = fcntl(fd, F_DUPFD, minfd);
471 #elif defined(HAVE_FCNTL) && defined(F_DUPFD)
472 ret = fcntl(fd, F_DUPFD, minfd);
473 #else
474 ret = dup(fd);
475 if (ret >= 0 && ret < minfd) {
476 const int prev_fd = ret;
477 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
478 close(prev_fd);
480 return ret;
481 #endif
482 if (ret < 0) return ret;
483 rb_maygvl_fd_fix_cloexec(ret);
484 return ret;
487 #define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
488 #define ARGF argf_of(argf)
490 #define GetWriteIO(io) rb_io_get_write_io(io)
492 #define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
493 #define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
494 #define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
495 #define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
497 #define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
498 #define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
499 #define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
501 #if defined(_WIN32)
502 #define WAIT_FD_IN_WIN32(fptr) \
503 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil))
504 #else
505 #define WAIT_FD_IN_WIN32(fptr)
506 #endif
508 #define READ_CHECK(fptr) do {\
509 if (!READ_DATA_PENDING(fptr)) {\
510 WAIT_FD_IN_WIN32(fptr);\
511 rb_io_check_closed(fptr);\
513 } while(0)
515 #ifndef S_ISSOCK
516 # ifdef _S_ISSOCK
517 # define S_ISSOCK(m) _S_ISSOCK(m)
518 # else
519 # ifdef _S_IFSOCK
520 # define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
521 # else
522 # ifdef S_IFSOCK
523 # define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
524 # endif
525 # endif
526 # endif
527 #endif
529 static int io_fflush(rb_io_t *);
530 static rb_io_t *flush_before_seek(rb_io_t *fptr);
532 #define FMODE_PREP (1<<16)
533 #define FMODE_SIGNAL_ON_EPIPE (1<<17)
535 #define fptr_signal_on_epipe(fptr) \
536 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
538 #define fptr_set_signal_on_epipe(fptr, flag) \
539 ((flag) ? \
540 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
541 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
543 extern ID ruby_static_id_signo;
545 NORETURN(static void raise_on_write(rb_io_t *fptr, int e, VALUE errinfo));
546 static void
547 raise_on_write(rb_io_t *fptr, int e, VALUE errinfo)
549 #if defined EPIPE
550 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
551 const VALUE sig =
552 # if defined SIGPIPE
553 INT2FIX(SIGPIPE) - INT2FIX(0) +
554 # endif
555 INT2FIX(0);
556 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
558 #endif
559 rb_exc_raise(errinfo);
562 #define rb_sys_fail_on_write(fptr) \
563 do { \
564 int e = errno; \
565 raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
566 } while (0)
568 #define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
569 #define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
570 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
571 # define RUBY_CRLF_ENVIRONMENT 1
572 #else
573 # define RUBY_CRLF_ENVIRONMENT 0
574 #endif
576 #if RUBY_CRLF_ENVIRONMENT
577 /* Windows */
578 # define DEFAULT_TEXTMODE FMODE_TEXTMODE
579 # define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
581 * CRLF newline is set as default newline decorator.
582 * If only CRLF newline conversion is needed, we use binary IO process
583 * with OS's text mode for IO performance improvement.
584 * If encoding conversion is needed or a user sets text mode, we use encoding
585 * conversion IO process and universal newline decorator by default.
587 #define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
588 #define WRITECONV_MASK ( \
589 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
590 ECONV_STATEFUL_DECORATOR_MASK|\
592 #define NEED_WRITECONV(fptr) ( \
593 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
594 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
596 #define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
598 #define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
599 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
600 if (((fptr)->mode & FMODE_READABLE) &&\
601 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
602 setmode((fptr)->fd, O_BINARY);\
604 else {\
605 setmode((fptr)->fd, O_TEXT);\
608 } while(0)
610 #define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
611 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
612 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
614 } while(0)
617 * IO unread with taking care of removed '\r' in text mode.
619 static void
620 io_unread(rb_io_t *fptr)
622 off_t r, pos;
623 ssize_t read_size;
624 long i;
625 long newlines = 0;
626 long extra_max;
627 char *p;
628 char *buf;
630 rb_io_check_closed(fptr);
631 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
632 return;
635 errno = 0;
636 if (!rb_w32_fd_is_text(fptr->fd)) {
637 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
638 if (r < 0 && errno) {
639 if (errno == ESPIPE)
640 fptr->mode |= FMODE_DUPLEX;
641 return;
644 fptr->rbuf.off = 0;
645 fptr->rbuf.len = 0;
646 return;
649 pos = lseek(fptr->fd, 0, SEEK_CUR);
650 if (pos < 0 && errno) {
651 if (errno == ESPIPE)
652 fptr->mode |= FMODE_DUPLEX;
653 return;
656 /* add extra offset for removed '\r' in rbuf */
657 extra_max = (long)(pos - fptr->rbuf.len);
658 p = fptr->rbuf.ptr + fptr->rbuf.off;
660 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
661 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
662 newlines++;
665 for (i = 0; i < fptr->rbuf.len; i++) {
666 if (*p == '\n') newlines++;
667 if (extra_max == newlines) break;
668 p++;
671 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
672 while (newlines >= 0) {
673 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
674 if (newlines == 0) break;
675 if (r < 0) {
676 newlines--;
677 continue;
679 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
680 if (read_size < 0) {
681 int e = errno;
682 free(buf);
683 rb_syserr_fail_path(e, fptr->pathv);
685 if (read_size == fptr->rbuf.len) {
686 lseek(fptr->fd, r, SEEK_SET);
687 break;
689 else {
690 newlines--;
693 free(buf);
694 fptr->rbuf.off = 0;
695 fptr->rbuf.len = 0;
696 return;
700 * We use io_seek to back cursor position when changing mode from text to binary,
701 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
702 * conversion for working properly with mode change.
704 * Return previous translation mode.
706 static inline int
707 set_binary_mode_with_seek_cur(rb_io_t *fptr)
709 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
711 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
712 return setmode(fptr->fd, O_BINARY);
714 flush_before_seek(fptr);
715 return setmode(fptr->fd, O_BINARY);
717 #define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
719 #else
720 /* Unix */
721 # define DEFAULT_TEXTMODE 0
722 #define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
723 #define NEED_WRITECONV(fptr) ( \
724 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
725 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
726 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
728 #define SET_BINARY_MODE(fptr) (void)(fptr)
729 #define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
730 #define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
731 #define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
732 #endif
734 #if !defined HAVE_SHUTDOWN && !defined shutdown
735 #define shutdown(a,b) 0
736 #endif
738 #if defined(_WIN32)
739 #define is_socket(fd, path) rb_w32_is_socket(fd)
740 #elif !defined(S_ISSOCK)
741 #define is_socket(fd, path) 0
742 #else
743 static int
744 is_socket(int fd, VALUE path)
746 struct stat sbuf;
747 if (fstat(fd, &sbuf) < 0)
748 rb_sys_fail_path(path);
749 return S_ISSOCK(sbuf.st_mode);
751 #endif
753 static const char closed_stream[] = "closed stream";
755 static void
756 io_fd_check_closed(int fd)
758 if (fd < 0) {
759 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
760 rb_raise(rb_eIOError, closed_stream);
764 void
765 rb_eof_error(void)
767 rb_raise(rb_eEOFError, "end of file reached");
770 VALUE
771 rb_io_taint_check(VALUE io)
773 rb_check_frozen(io);
774 return io;
777 void
778 rb_io_check_initialized(rb_io_t *fptr)
780 if (!fptr) {
781 rb_raise(rb_eIOError, "uninitialized stream");
785 void
786 rb_io_check_closed(rb_io_t *fptr)
788 rb_io_check_initialized(fptr);
789 io_fd_check_closed(fptr->fd);
792 static rb_io_t *
793 rb_io_get_fptr(VALUE io)
795 rb_io_t *fptr = RFILE(io)->fptr;
796 rb_io_check_initialized(fptr);
797 return fptr;
800 VALUE
801 rb_io_get_io(VALUE io)
803 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
806 VALUE
807 rb_io_check_io(VALUE io)
809 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
812 VALUE
813 rb_io_get_write_io(VALUE io)
815 VALUE write_io;
816 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
817 if (write_io) {
818 return write_io;
820 return io;
823 VALUE
824 rb_io_set_write_io(VALUE io, VALUE w)
826 VALUE write_io;
827 rb_io_t *fptr = rb_io_get_fptr(io);
828 if (!RTEST(w)) {
829 w = 0;
831 else {
832 GetWriteIO(w);
834 write_io = fptr->tied_io_for_writing;
835 fptr->tied_io_for_writing = w;
836 return write_io ? write_io : Qnil;
840 * call-seq:
841 * IO.try_convert(object) -> new_io or nil
843 * Attempts to convert +object+ into an \IO object via method +to_io+;
844 * returns the new \IO object if successful, or +nil+ otherwise:
846 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
847 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
848 * IO.try_convert('STDOUT') # => nil
851 static VALUE
852 rb_io_s_try_convert(VALUE dummy, VALUE io)
854 return rb_io_check_io(io);
857 #if !RUBY_CRLF_ENVIRONMENT
858 static void
859 io_unread(rb_io_t *fptr)
861 off_t r;
862 rb_io_check_closed(fptr);
863 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
864 return;
865 /* xxx: target position may be negative if buffer is filled by ungetc */
866 errno = 0;
867 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
868 if (r < 0 && errno) {
869 if (errno == ESPIPE)
870 fptr->mode |= FMODE_DUPLEX;
871 return;
873 fptr->rbuf.off = 0;
874 fptr->rbuf.len = 0;
875 return;
877 #endif
879 static rb_encoding *io_input_encoding(rb_io_t *fptr);
881 static void
882 io_ungetbyte(VALUE str, rb_io_t *fptr)
884 long len = RSTRING_LEN(str);
886 if (fptr->rbuf.ptr == NULL) {
887 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
888 fptr->rbuf.off = 0;
889 fptr->rbuf.len = 0;
890 #if SIZEOF_LONG > SIZEOF_INT
891 if (len > INT_MAX)
892 rb_raise(rb_eIOError, "ungetbyte failed");
893 #endif
894 if (len > min_capa)
895 fptr->rbuf.capa = (int)len;
896 else
897 fptr->rbuf.capa = min_capa;
898 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
900 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
901 rb_raise(rb_eIOError, "ungetbyte failed");
903 if (fptr->rbuf.off < len) {
904 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
905 fptr->rbuf.ptr+fptr->rbuf.off,
906 char, fptr->rbuf.len);
907 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
909 fptr->rbuf.off-=(int)len;
910 fptr->rbuf.len+=(int)len;
911 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
914 static rb_io_t *
915 flush_before_seek(rb_io_t *fptr)
917 if (io_fflush(fptr) < 0)
918 rb_sys_fail_on_write(fptr);
919 io_unread(fptr);
920 errno = 0;
921 return fptr;
924 #define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
925 #define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
927 #ifndef SEEK_CUR
928 # define SEEK_SET 0
929 # define SEEK_CUR 1
930 # define SEEK_END 2
931 #endif
933 void
934 rb_io_check_char_readable(rb_io_t *fptr)
936 rb_io_check_closed(fptr);
937 if (!(fptr->mode & FMODE_READABLE)) {
938 rb_raise(rb_eIOError, "not opened for reading");
940 if (fptr->wbuf.len) {
941 if (io_fflush(fptr) < 0)
942 rb_sys_fail_on_write(fptr);
944 if (fptr->tied_io_for_writing) {
945 rb_io_t *wfptr;
946 GetOpenFile(fptr->tied_io_for_writing, wfptr);
947 if (io_fflush(wfptr) < 0)
948 rb_sys_fail_on_write(wfptr);
952 void
953 rb_io_check_byte_readable(rb_io_t *fptr)
955 rb_io_check_char_readable(fptr);
956 if (READ_CHAR_PENDING(fptr)) {
957 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
961 void
962 rb_io_check_readable(rb_io_t *fptr)
964 rb_io_check_byte_readable(fptr);
967 static rb_encoding*
968 io_read_encoding(rb_io_t *fptr)
970 if (fptr->encs.enc) {
971 return fptr->encs.enc;
973 return rb_default_external_encoding();
976 static rb_encoding*
977 io_input_encoding(rb_io_t *fptr)
979 if (fptr->encs.enc2) {
980 return fptr->encs.enc2;
982 return io_read_encoding(fptr);
985 void
986 rb_io_check_writable(rb_io_t *fptr)
988 rb_io_check_closed(fptr);
989 if (!(fptr->mode & FMODE_WRITABLE)) {
990 rb_raise(rb_eIOError, "not opened for writing");
992 if (fptr->rbuf.len) {
993 io_unread(fptr);
998 rb_io_read_pending(rb_io_t *fptr)
1000 /* This function is used for bytes and chars. Confusing. */
1001 if (READ_CHAR_PENDING(fptr))
1002 return 1; /* should raise? */
1003 return READ_DATA_PENDING(fptr);
1006 void
1007 rb_io_read_check(rb_io_t *fptr)
1009 if (!READ_DATA_PENDING(fptr)) {
1010 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
1012 return;
1016 rb_gc_for_fd(int err)
1018 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1019 rb_gc();
1020 return 1;
1022 return 0;
1025 static int
1026 ruby_dup(int orig)
1028 int fd;
1030 fd = rb_cloexec_dup(orig);
1031 if (fd < 0) {
1032 int e = errno;
1033 if (rb_gc_for_fd(e)) {
1034 fd = rb_cloexec_dup(orig);
1036 if (fd < 0) {
1037 rb_syserr_fail(e, 0);
1040 rb_update_max_fd(fd);
1041 return fd;
1044 static VALUE
1045 io_alloc(VALUE klass)
1047 NEWOBJ_OF(io, struct RFile, klass, T_FILE);
1049 io->fptr = 0;
1051 return (VALUE)io;
1054 #ifndef S_ISREG
1055 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1056 #endif
1058 struct io_internal_read_struct {
1059 VALUE th;
1060 rb_io_t *fptr;
1061 int nonblock;
1062 void *buf;
1063 size_t capa;
1066 struct io_internal_write_struct {
1067 int fd;
1068 const void *buf;
1069 size_t capa;
1072 #ifdef HAVE_WRITEV
1073 struct io_internal_writev_struct {
1074 int fd;
1075 int iovcnt;
1076 const struct iovec *iov;
1078 #endif
1080 static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events);
1081 static VALUE
1082 internal_read_func(void *ptr)
1084 struct io_internal_read_struct *iis = ptr;
1085 ssize_t r;
1086 retry:
1087 r = read(iis->fptr->fd, iis->buf, iis->capa);
1088 if (r < 0 && !iis->nonblock) {
1089 int e = errno;
1090 if (io_again_p(e)) {
1091 if (nogvl_wait_for(iis->th, iis->fptr, RB_WAITFD_IN) != -1) {
1092 goto retry;
1094 errno = e;
1097 return r;
1100 #if defined __APPLE__
1101 # define do_write_retry(code) do {ret = code;} while (ret == -1 && errno == EPROTOTYPE)
1102 #else
1103 # define do_write_retry(code) ret = code
1104 #endif
1105 static VALUE
1106 internal_write_func(void *ptr)
1108 struct io_internal_write_struct *iis = ptr;
1109 ssize_t ret;
1110 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1111 return (VALUE)ret;
1114 static void*
1115 internal_write_func2(void *ptr)
1117 return (void*)internal_write_func(ptr);
1120 #ifdef HAVE_WRITEV
1121 static VALUE
1122 internal_writev_func(void *ptr)
1124 struct io_internal_writev_struct *iis = ptr;
1125 ssize_t ret;
1126 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1127 return (VALUE)ret;
1129 #endif
1131 static ssize_t
1132 rb_read_internal(rb_io_t *fptr, void *buf, size_t count)
1134 VALUE scheduler = rb_fiber_scheduler_current();
1135 if (scheduler != Qnil) {
1136 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1138 if (result != Qundef) {
1139 return rb_fiber_scheduler_io_result_apply(result);
1143 struct io_internal_read_struct iis = {
1144 .th = rb_thread_current(),
1145 .fptr = fptr,
1146 .nonblock = 0,
1147 .buf = buf,
1148 .capa = count
1151 return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fptr->fd);
1154 static ssize_t
1155 rb_write_internal(rb_io_t *fptr, const void *buf, size_t count)
1157 VALUE scheduler = rb_fiber_scheduler_current();
1158 if (scheduler != Qnil) {
1159 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1161 if (result != Qundef) {
1162 return rb_fiber_scheduler_io_result_apply(result);
1166 struct io_internal_write_struct iis = {
1167 .fd = fptr->fd,
1168 .buf = buf,
1169 .capa = count
1172 if (fptr->write_lock && rb_mutex_owned_p(fptr->write_lock))
1173 return (ssize_t)rb_thread_call_without_gvl2(internal_write_func2, &iis, RUBY_UBF_IO, NULL);
1174 else
1175 return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fptr->fd);
1178 #ifdef HAVE_WRITEV
1179 static ssize_t
1180 rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1182 VALUE scheduler = rb_fiber_scheduler_current();
1183 if (scheduler != Qnil) {
1184 for (int i = 0; i < iovcnt; i += 1) {
1185 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[i].iov_base, iov[i].iov_len, 0);
1187 if (result != Qundef) {
1188 return rb_fiber_scheduler_io_result_apply(result);
1193 struct io_internal_writev_struct iis = {
1194 .fd = fptr->fd,
1195 .iov = iov,
1196 .iovcnt = iovcnt,
1199 return (ssize_t)rb_thread_io_blocking_region(internal_writev_func, &iis, fptr->fd);
1201 #endif
1203 static VALUE
1204 io_flush_buffer_sync(void *arg)
1206 rb_io_t *fptr = arg;
1207 long l = fptr->wbuf.len;
1208 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1210 if (fptr->wbuf.len <= r) {
1211 fptr->wbuf.off = 0;
1212 fptr->wbuf.len = 0;
1213 return 0;
1215 if (0 <= r) {
1216 fptr->wbuf.off += (int)r;
1217 fptr->wbuf.len -= (int)r;
1218 errno = EAGAIN;
1220 return (VALUE)-1;
1223 static void*
1224 io_flush_buffer_sync2(void *arg)
1226 VALUE result = io_flush_buffer_sync(arg);
1229 * rb_thread_call_without_gvl2 uses 0 as interrupted.
1230 * So, we need to avoid to use 0.
1232 return !result ? (void*)1 : (void*)result;
1235 static VALUE
1236 io_flush_buffer_async(VALUE arg)
1238 rb_io_t *fptr = (rb_io_t *)arg;
1239 return rb_thread_io_blocking_region(io_flush_buffer_sync, fptr, fptr->fd);
1242 static VALUE
1243 io_flush_buffer_async2(VALUE arg)
1245 rb_io_t *fptr = (rb_io_t *)arg;
1246 VALUE ret;
1248 ret = (VALUE)rb_thread_call_without_gvl2(io_flush_buffer_sync2, fptr, RUBY_UBF_IO, NULL);
1250 if (!ret) {
1251 /* pending async interrupt is there. */
1252 errno = EAGAIN;
1253 return -1;
1255 else if (ret == 1) {
1256 return 0;
1258 return ret;
1261 static inline int
1262 io_flush_buffer(rb_io_t *fptr)
1264 if (fptr->write_lock) {
1265 if (rb_mutex_owned_p(fptr->write_lock))
1266 return (int)io_flush_buffer_async2((VALUE)fptr);
1267 else
1268 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async2, (VALUE)fptr);
1270 else {
1271 return (int)io_flush_buffer_async((VALUE)fptr);
1275 static int
1276 io_fflush(rb_io_t *fptr)
1278 rb_io_check_closed(fptr);
1280 if (fptr->wbuf.len == 0)
1281 return 0;
1283 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1284 if (!rb_io_maybe_wait_writable(errno, fptr->self, Qnil))
1285 return -1;
1287 rb_io_check_closed(fptr);
1290 return 0;
1293 VALUE
1294 rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1296 VALUE scheduler = rb_fiber_scheduler_current();
1298 if (scheduler != Qnil) {
1299 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1302 rb_io_t * fptr = NULL;
1303 RB_IO_POINTER(io, fptr);
1305 struct timeval tv_storage;
1306 struct timeval *tv = NULL;
1308 if (timeout != Qnil) {
1309 tv_storage = rb_time_interval(timeout);
1310 tv = &tv_storage;
1313 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1315 if (ready < 0) {
1316 rb_sys_fail(0);
1319 // Not sure if this is necessary:
1320 rb_io_check_closed(fptr);
1322 if (ready) {
1323 return RB_INT2NUM(ready);
1325 else {
1326 return Qfalse;
1330 static VALUE
1331 io_from_fd(int fd)
1333 return prep_io(fd, FMODE_PREP, rb_cIO, NULL);
1336 static int
1337 io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1339 VALUE scheduler = rb_fiber_scheduler_current();
1341 if (scheduler != Qnil) {
1342 return RTEST(
1343 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1347 return rb_thread_wait_for_single_fd(fd, events, timeout);
1351 rb_io_wait_readable(int f)
1353 io_fd_check_closed(f);
1355 VALUE scheduler = rb_fiber_scheduler_current();
1357 switch (errno) {
1358 case EINTR:
1359 #if defined(ERESTART)
1360 case ERESTART:
1361 #endif
1362 rb_thread_check_ints();
1363 return TRUE;
1365 case EAGAIN:
1366 #if EWOULDBLOCK != EAGAIN
1367 case EWOULDBLOCK:
1368 #endif
1369 if (scheduler != Qnil) {
1370 return RTEST(
1371 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1374 else {
1375 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1377 return TRUE;
1379 default:
1380 return FALSE;
1385 rb_io_wait_writable(int f)
1387 io_fd_check_closed(f);
1389 VALUE scheduler = rb_fiber_scheduler_current();
1391 switch (errno) {
1392 case EINTR:
1393 #if defined(ERESTART)
1394 case ERESTART:
1395 #endif
1397 * In old Linux, several special files under /proc and /sys don't handle
1398 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1399 * Otherwise, we face nasty hang up. Sigh.
1400 * e.g. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
1401 * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
1402 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1403 * Then rb_thread_check_ints() is enough.
1405 rb_thread_check_ints();
1406 return TRUE;
1408 case EAGAIN:
1409 #if EWOULDBLOCK != EAGAIN
1410 case EWOULDBLOCK:
1411 #endif
1412 if (scheduler != Qnil) {
1413 return RTEST(
1414 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1417 else {
1418 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1420 return TRUE;
1422 default:
1423 return FALSE;
1428 rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1430 return io_wait_for_single_fd(fd, events, timeout);
1434 rb_thread_wait_fd(int fd)
1436 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1440 rb_thread_fd_writable(int fd)
1442 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1445 VALUE
1446 rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1448 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1449 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1450 // instead relies on `read(-1) -> -1` which causes this code path. We then
1451 // check here whether the IO was in fact closed. Probably it's better to
1452 // check that `fptr->fd != -1` before using it in syscall.
1453 rb_io_check_closed(RFILE(io)->fptr);
1455 switch (error) {
1456 // In old Linux, several special files under /proc and /sys don't handle
1457 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1458 // Otherwise, we face nasty hang up. Sigh.
1459 // e.g. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
1460 // http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
1461 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1462 // Then rb_thread_check_ints() is enough.
1463 case EINTR:
1464 #if defined(ERESTART)
1465 case ERESTART:
1466 #endif
1467 // We might have pending interrupts since the previous syscall was interrupted:
1468 rb_thread_check_ints();
1470 // The operation was interrupted, so retry it immediately:
1471 return events;
1473 case EAGAIN:
1474 #if EWOULDBLOCK != EAGAIN
1475 case EWOULDBLOCK:
1476 #endif
1477 // The operation would block, so wait for the specified events:
1478 return rb_io_wait(io, events, timeout);
1480 default:
1481 // Non-specific error, no event is ready:
1482 return Qfalse;
1487 rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
1489 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1491 if (RTEST(result)) {
1492 return RB_NUM2INT(result);
1494 else {
1495 return 0;
1500 rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
1502 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1504 if (RTEST(result)) {
1505 return RB_NUM2INT(result);
1507 else {
1508 return 0;
1512 static void
1513 make_writeconv(rb_io_t *fptr)
1515 if (!fptr->writeconv_initialized) {
1516 const char *senc, *denc;
1517 rb_encoding *enc;
1518 int ecflags;
1519 VALUE ecopts;
1521 fptr->writeconv_initialized = 1;
1523 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1524 ecopts = fptr->encs.ecopts;
1526 if (!fptr->encs.enc || (fptr->encs.enc == rb_ascii8bit_encoding() && !fptr->encs.enc2)) {
1527 /* no encoding conversion */
1528 fptr->writeconv_pre_ecflags = 0;
1529 fptr->writeconv_pre_ecopts = Qnil;
1530 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1531 if (!fptr->writeconv)
1532 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1533 fptr->writeconv_asciicompat = Qnil;
1535 else {
1536 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1537 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1538 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1539 /* single conversion */
1540 fptr->writeconv_pre_ecflags = ecflags;
1541 fptr->writeconv_pre_ecopts = ecopts;
1542 fptr->writeconv = NULL;
1543 fptr->writeconv_asciicompat = Qnil;
1545 else {
1546 /* double conversion */
1547 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1548 fptr->writeconv_pre_ecopts = ecopts;
1549 if (senc) {
1550 denc = rb_enc_name(enc);
1551 fptr->writeconv_asciicompat = rb_str_new2(senc);
1553 else {
1554 senc = denc = "";
1555 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1557 ecflags = fptr->encs.ecflags & (ECONV_ERROR_HANDLER_MASK|ECONV_STATEFUL_DECORATOR_MASK);
1558 ecopts = fptr->encs.ecopts;
1559 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1560 if (!fptr->writeconv)
1561 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1567 /* writing functions */
1568 struct binwrite_arg {
1569 rb_io_t *fptr;
1570 VALUE str;
1571 const char *ptr;
1572 long length;
1575 struct write_arg {
1576 VALUE io;
1577 VALUE str;
1578 int nosync;
1581 #ifdef HAVE_WRITEV
1582 static VALUE
1583 io_binwrite_string(VALUE arg)
1585 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1586 rb_io_t *fptr = p->fptr;
1587 long r;
1589 if (fptr->wbuf.len) {
1590 struct iovec iov[2];
1592 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1593 iov[0].iov_len = fptr->wbuf.len;
1594 iov[1].iov_base = (char *)p->ptr;
1595 iov[1].iov_len = p->length;
1597 r = rb_writev_internal(fptr, iov, 2);
1599 if (r < 0)
1600 return r;
1602 if (fptr->wbuf.len <= r) {
1603 r -= fptr->wbuf.len;
1604 fptr->wbuf.off = 0;
1605 fptr->wbuf.len = 0;
1607 else {
1608 fptr->wbuf.off += (int)r;
1609 fptr->wbuf.len -= (int)r;
1610 r = 0L;
1613 else {
1614 r = rb_write_internal(fptr, p->ptr, p->length);
1617 return r;
1619 #else
1620 static VALUE
1621 io_binwrite_string(VALUE arg)
1623 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1624 rb_io_t *fptr = p->fptr;
1625 long l, len;
1627 l = len = p->length;
1629 if (fptr->wbuf.len) {
1630 if (fptr->wbuf.len+len <= fptr->wbuf.capa) {
1631 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+len) {
1632 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1633 fptr->wbuf.off = 0;
1635 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, p->ptr, char, len);
1636 fptr->wbuf.len += (int)len;
1637 l = 0;
1639 if (io_fflush(fptr) < 0)
1640 return -2L; /* fail in fflush */
1641 if (l == 0)
1642 return len;
1645 return rb_write_internal(p->fptr, p->ptr, p->length);
1647 #endif
1649 inline static void
1650 io_allocate_write_buffer(rb_io_t *fptr, int sync)
1652 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1653 fptr->wbuf.off = 0;
1654 fptr->wbuf.len = 0;
1655 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1656 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1657 fptr->write_lock = rb_mutex_new();
1658 rb_mutex_allow_trap(fptr->write_lock, 1);
1662 static long
1663 io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
1665 long n, r, offset = 0;
1667 /* don't write anything if current thread has a pending interrupt. */
1668 rb_thread_check_ints();
1670 if ((n = len) <= 0) return n;
1672 io_allocate_write_buffer(fptr, !nosync);
1674 if ((!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY))) ||
1675 (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)) {
1676 struct binwrite_arg arg;
1678 arg.fptr = fptr;
1679 arg.str = str;
1680 retry:
1681 arg.ptr = ptr + offset;
1682 arg.length = n;
1684 if (fptr->write_lock) {
1685 r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1687 else {
1688 r = io_binwrite_string((VALUE)&arg);
1691 /* xxx: other threads may modify given string. */
1692 if (r == n) return len;
1693 if (0 <= r) {
1694 offset += r;
1695 n -= r;
1696 errno = EAGAIN;
1699 if (r == -2L)
1700 return -1L;
1701 if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) {
1702 rb_io_check_closed(fptr);
1704 if (offset < len)
1705 goto retry;
1708 return -1L;
1711 if (fptr->wbuf.off) {
1712 if (fptr->wbuf.len)
1713 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1714 fptr->wbuf.off = 0;
1717 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr+offset, char, len);
1718 fptr->wbuf.len += (int)len;
1720 return len;
1723 # define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1724 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1726 #define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1727 MODE_BTMODE(d, e, f) : \
1728 MODE_BTMODE(a, b, c))
1730 static VALUE
1731 do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1733 if (NEED_WRITECONV(fptr)) {
1734 VALUE common_encoding = Qnil;
1735 SET_BINARY_MODE(fptr);
1737 make_writeconv(fptr);
1739 if (fptr->writeconv) {
1740 #define fmode (fptr->mode)
1741 if (!NIL_P(fptr->writeconv_asciicompat))
1742 common_encoding = fptr->writeconv_asciicompat;
1743 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1744 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1745 rb_enc_name(rb_enc_get(str)));
1747 #undef fmode
1749 else {
1750 if (fptr->encs.enc2)
1751 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1752 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1753 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1756 if (!NIL_P(common_encoding)) {
1757 str = rb_str_encode(str, common_encoding,
1758 fptr->writeconv_pre_ecflags, fptr->writeconv_pre_ecopts);
1759 *converted = 1;
1762 if (fptr->writeconv) {
1763 str = rb_econv_str_convert(fptr->writeconv, str, ECONV_PARTIAL_INPUT);
1764 *converted = 1;
1767 #if RUBY_CRLF_ENVIRONMENT
1768 #define fmode (fptr->mode)
1769 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1770 if ((fptr->mode & FMODE_READABLE) &&
1771 !(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
1772 setmode(fptr->fd, O_BINARY);
1774 else {
1775 setmode(fptr->fd, O_TEXT);
1777 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1778 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1779 rb_enc_name(rb_enc_get(str)));
1782 #undef fmode
1783 #endif
1784 return str;
1787 static long
1788 io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1790 int converted = 0;
1791 VALUE tmp;
1792 long n, len;
1793 const char *ptr;
1794 #ifdef _WIN32
1795 if (fptr->mode & FMODE_TTY) {
1796 long len = rb_w32_write_console(str, fptr->fd);
1797 if (len > 0) return len;
1799 #endif
1800 str = do_writeconv(str, fptr, &converted);
1801 if (converted)
1802 OBJ_FREEZE(str);
1804 tmp = rb_str_tmp_frozen_acquire(str);
1805 RSTRING_GETMEM(tmp, ptr, len);
1806 n = io_binwrite(tmp, ptr, len, fptr, nosync);
1807 rb_str_tmp_frozen_release(str, tmp);
1809 return n;
1812 ssize_t
1813 rb_io_bufwrite(VALUE io, const void *buf, size_t size)
1815 rb_io_t *fptr;
1817 GetOpenFile(io, fptr);
1818 rb_io_check_writable(fptr);
1819 return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
1822 static VALUE
1823 io_write(VALUE io, VALUE str, int nosync)
1825 rb_io_t *fptr;
1826 long n;
1827 VALUE tmp;
1829 io = GetWriteIO(io);
1830 str = rb_obj_as_string(str);
1831 tmp = rb_io_check_io(io);
1832 if (NIL_P(tmp)) {
1833 /* port is not IO, call write method for it. */
1834 return rb_funcall(io, id_write, 1, str);
1836 io = tmp;
1837 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
1839 GetOpenFile(io, fptr);
1840 rb_io_check_writable(fptr);
1842 n = io_fwrite(str, fptr, nosync);
1843 if (n < 0L) rb_sys_fail_on_write(fptr);
1845 return LONG2FIX(n);
1848 #ifdef HAVE_WRITEV
1849 struct binwritev_arg {
1850 rb_io_t *fptr;
1851 const struct iovec *iov;
1852 int iovcnt;
1855 static VALUE
1856 call_writev_internal(VALUE arg)
1858 struct binwritev_arg *p = (struct binwritev_arg *)arg;
1859 return rb_writev_internal(p->fptr, p->iov, p->iovcnt);
1862 static long
1863 io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
1865 int i;
1866 long r, total = 0, written_len = 0;
1868 /* don't write anything if current thread has a pending interrupt. */
1869 rb_thread_check_ints();
1871 if (iovcnt == 0) return 0;
1872 for (i = 1; i < iovcnt; i++) total += iov[i].iov_len;
1874 io_allocate_write_buffer(fptr, 1);
1876 if (fptr->wbuf.ptr && fptr->wbuf.len) {
1877 long offset = fptr->wbuf.off + fptr->wbuf.len;
1878 if (offset + total <= fptr->wbuf.capa) {
1879 for (i = 1; i < iovcnt; i++) {
1880 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
1881 offset += iov[i].iov_len;
1884 fptr->wbuf.len += total;
1885 return total;
1887 else {
1888 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
1889 iov[0].iov_len = fptr->wbuf.len;
1892 else {
1893 iov++;
1894 if (!--iovcnt) return 0;
1897 retry:
1898 if (fptr->write_lock) {
1899 struct binwritev_arg arg;
1900 arg.fptr = fptr;
1901 arg.iov = iov;
1902 arg.iovcnt = iovcnt;
1903 r = rb_mutex_synchronize(fptr->write_lock, call_writev_internal, (VALUE)&arg);
1905 else {
1906 r = rb_writev_internal(fptr, iov, iovcnt);
1909 if (r >= 0) {
1910 written_len += r;
1911 if (fptr->wbuf.ptr && fptr->wbuf.len) {
1912 if (written_len < fptr->wbuf.len) {
1913 fptr->wbuf.off += r;
1914 fptr->wbuf.len -= r;
1916 else {
1917 written_len -= fptr->wbuf.len;
1918 fptr->wbuf.off = 0;
1919 fptr->wbuf.len = 0;
1923 if (written_len == total) return total;
1925 while (r >= (ssize_t)iov->iov_len) {
1926 /* iovcnt > 0 */
1927 r -= iov->iov_len;
1928 iov->iov_len = 0;
1929 iov++;
1931 if (!--iovcnt) {
1932 // assert(written_len == total);
1934 return total;
1938 iov->iov_base = (char *)iov->iov_base + r;
1939 iov->iov_len -= r;
1941 errno = EAGAIN;
1944 if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) {
1945 rb_io_check_closed(fptr);
1946 goto retry;
1949 return -1L;
1952 static long
1953 io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
1955 int i, converted, iovcnt = argc + 1;
1956 long n;
1957 VALUE v1, v2, str, tmp, *tmp_array;
1958 struct iovec *iov;
1960 iov = ALLOCV_N(struct iovec, v1, iovcnt);
1961 tmp_array = ALLOCV_N(VALUE, v2, argc);
1963 for (i = 0; i < argc; i++) {
1964 str = rb_obj_as_string(argv[i]);
1965 converted = 0;
1966 str = do_writeconv(str, fptr, &converted);
1968 if (converted)
1969 OBJ_FREEZE(str);
1971 tmp = rb_str_tmp_frozen_acquire(str);
1972 tmp_array[i] = tmp;
1974 /* iov[0] is reserved for buffer of fptr */
1975 iov[i+1].iov_base = RSTRING_PTR(tmp);
1976 iov[i+1].iov_len = RSTRING_LEN(tmp);
1979 n = io_binwritev(iov, iovcnt, fptr);
1980 if (v1) ALLOCV_END(v1);
1982 for (i = 0; i < argc; i++) {
1983 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
1986 if (v2) ALLOCV_END(v2);
1988 return n;
1991 static int
1992 iovcnt_ok(int iovcnt)
1994 #ifdef IOV_MAX
1995 return iovcnt < IOV_MAX;
1996 #else /* GNU/Hurd has writev, but no IOV_MAX */
1997 return 1;
1998 #endif
2000 #endif /* HAVE_WRITEV */
2002 static VALUE
2003 io_writev(int argc, const VALUE *argv, VALUE io)
2005 rb_io_t *fptr;
2006 long n;
2007 VALUE tmp, total = INT2FIX(0);
2008 int i, cnt = 1;
2010 io = GetWriteIO(io);
2011 tmp = rb_io_check_io(io);
2013 if (NIL_P(tmp)) {
2014 /* port is not IO, call write method for it. */
2015 return rb_funcallv(io, id_write, argc, argv);
2018 io = tmp;
2020 GetOpenFile(io, fptr);
2021 rb_io_check_writable(fptr);
2023 for (i = 0; i < argc; i += cnt) {
2024 #ifdef HAVE_WRITEV
2025 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2026 n = io_fwritev(cnt, &argv[i], fptr);
2028 else
2029 #endif
2031 cnt = 1;
2032 /* sync at last item */
2033 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2036 if (n < 0L)
2037 rb_sys_fail_on_write(fptr);
2039 total = rb_fix_plus(LONG2FIX(n), total);
2042 return total;
2046 * call-seq:
2047 * write(*objects) -> integer
2049 * Writes each of the given +objects+ to +self+,
2050 * which must be opened for writing (see {Modes}[#class-IO-label-Modes]);
2051 * returns the total number bytes written;
2052 * each of +objects+ that is not a string is converted via method +to_s+:
2054 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2055 * $stdout.write('foo', :bar, 2, "\n") # => 8
2057 * Output:
2059 * Hello, World!
2060 * foobar2
2064 static VALUE
2065 io_write_m(int argc, VALUE *argv, VALUE io)
2067 if (argc != 1) {
2068 return io_writev(argc, argv, io);
2070 else {
2071 VALUE str = argv[0];
2072 return io_write(io, str, 0);
2076 VALUE
2077 rb_io_write(VALUE io, VALUE str)
2079 return rb_funcallv(io, id_write, 1, &str);
2082 static VALUE
2083 rb_io_writev(VALUE io, int argc, const VALUE *argv)
2085 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2086 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2087 VALUE klass = CLASS_OF(io);
2088 char sep = FL_TEST(klass, FL_SINGLETON) ? (klass = io, '.') : '#';
2089 rb_category_warning(
2090 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2091 " which accepts just one argument",
2092 klass, sep
2096 do rb_io_write(io, *argv++); while (--argc);
2098 /* unused right now */
2099 return argv[0];
2102 return rb_funcallv(io, id_write, argc, argv);
2106 * call-seq:
2107 * self << object -> self
2109 * Writes the given +object+ to +self+,
2110 * which must be opened for writing (see {Modes}[#class-IO-label-Modes]);
2111 * returns +self+;
2112 * if +object+ is not a string, it is converted via method +to_s+:
2114 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2115 * $stdout << 'foo' << :bar << 2 << "\n"
2117 * Output:
2119 * Hello, World!
2120 * foobar2
2125 VALUE
2126 rb_io_addstr(VALUE io, VALUE str)
2128 rb_io_write(io, str);
2129 return io;
2132 #ifdef HAVE_FSYNC
2133 static VALUE
2134 nogvl_fsync(void *ptr)
2136 rb_io_t *fptr = ptr;
2138 #ifdef _WIN32
2139 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2140 return 0;
2141 #endif
2142 return (VALUE)fsync(fptr->fd);
2144 #endif
2146 VALUE
2147 rb_io_flush_raw(VALUE io, int sync)
2149 rb_io_t *fptr;
2151 if (!RB_TYPE_P(io, T_FILE)) {
2152 return rb_funcall(io, id_flush, 0);
2155 io = GetWriteIO(io);
2156 GetOpenFile(io, fptr);
2158 if (fptr->mode & FMODE_WRITABLE) {
2159 if (io_fflush(fptr) < 0)
2160 rb_sys_fail_on_write(fptr);
2162 if (fptr->mode & FMODE_READABLE) {
2163 io_unread(fptr);
2166 return io;
2170 * call-seq:
2171 * flush -> self
2173 * Flushes data buffered in +self+ to the operating system
2174 * (but does not necessarily flush data buffered in the operating system):
2176 * $stdout.print 'no newline' # Not necessarily flushed.
2177 * $stdout.flush # Flushed.
2181 VALUE
2182 rb_io_flush(VALUE io)
2184 return rb_io_flush_raw(io, 1);
2188 * call-seq:
2189 * tell -> integer
2191 * Returns the current position (in bytes) in +self+
2192 * (see {Position}[#class-IO-label-Position]):
2194 * f = File.open('t.txt')
2195 * f.tell # => 0
2196 * f.gets # => "First line\n"
2197 * f.tell # => 12
2199 * Related: IO#pos=, IO#seek.
2201 * IO#pos is an alias for IO#tell.
2205 static VALUE
2206 rb_io_tell(VALUE io)
2208 rb_io_t *fptr;
2209 off_t pos;
2211 GetOpenFile(io, fptr);
2212 pos = io_tell(fptr);
2213 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2214 pos -= fptr->rbuf.len;
2215 return OFFT2NUM(pos);
2218 static VALUE
2219 rb_io_seek(VALUE io, VALUE offset, int whence)
2221 rb_io_t *fptr;
2222 off_t pos;
2224 pos = NUM2OFFT(offset);
2225 GetOpenFile(io, fptr);
2226 pos = io_seek(fptr, pos, whence);
2227 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2229 return INT2FIX(0);
2232 static int
2233 interpret_seek_whence(VALUE vwhence)
2235 if (vwhence == sym_SET)
2236 return SEEK_SET;
2237 if (vwhence == sym_CUR)
2238 return SEEK_CUR;
2239 if (vwhence == sym_END)
2240 return SEEK_END;
2241 #ifdef SEEK_DATA
2242 if (vwhence == sym_DATA)
2243 return SEEK_DATA;
2244 #endif
2245 #ifdef SEEK_HOLE
2246 if (vwhence == sym_HOLE)
2247 return SEEK_HOLE;
2248 #endif
2249 return NUM2INT(vwhence);
2253 * call-seq:
2254 * seek(offset, whence = IO::SEEK_SET) -> 0
2256 * Seeks to the position given by integer +offset+
2257 * (see {Position}[#class-IO-label-Position])
2258 * and constant +whence+, which is one of:
2260 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2261 * Repositions the stream to its current position plus the given +offset+:
2263 * f = File.open('t.txt')
2264 * f.tell # => 0
2265 * f.seek(20, :CUR) # => 0
2266 * f.tell # => 20
2267 * f.seek(-10, :CUR) # => 0
2268 * f.tell # => 10
2270 * - +:END+ or <tt>IO::SEEK_END</tt>:
2271 * Repositions the stream to its end plus the given +offset+:
2273 * f = File.open('t.txt')
2274 * f.tell # => 0
2275 * f.seek(0, :END) # => 0 # Repositions to stream end.
2276 * f.tell # => 52
2277 * f.seek(-20, :END) # => 0
2278 * f.tell # => 32
2279 * f.seek(-40, :END) # => 0
2280 * f.tell # => 12
2282 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2283 * Repositions the stream to the given +offset+:
2285 * f = File.open('t.txt')
2286 * f.tell # => 0
2287 * f.seek(20, :SET) # => 0
2288 * f.tell # => 20
2289 * f.seek(40, :SET) # => 0
2290 * f.tell # => 40
2292 * Related: IO#pos=, IO#tell.
2296 static VALUE
2297 rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2299 VALUE offset, ptrname;
2300 int whence = SEEK_SET;
2302 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2303 whence = interpret_seek_whence(ptrname);
2306 return rb_io_seek(io, offset, whence);
2310 * call-seq:
2311 * pos = new_position -> new_position
2313 * Seeks to the given +new_position+ (in bytes);
2314 * see {Position}[#class-IO-label-Position]:
2316 * f = File.open('t.txt')
2317 * f.tell # => 0
2318 * f.pos = 20 # => 20
2319 * f.tell # => 20
2321 * Related: IO#seek, IO#tell.
2325 static VALUE
2326 rb_io_set_pos(VALUE io, VALUE offset)
2328 rb_io_t *fptr;
2329 off_t pos;
2331 pos = NUM2OFFT(offset);
2332 GetOpenFile(io, fptr);
2333 pos = io_seek(fptr, pos, SEEK_SET);
2334 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2336 return OFFT2NUM(pos);
2339 static void clear_readconv(rb_io_t *fptr);
2342 * call-seq:
2343 * rewind -> 0
2345 * Repositions the stream to its beginning,
2346 * setting both the position and the line number to zero;
2347 * see {Position}[#class-IO-label-Position]
2348 * and {Line Number}[#class-IO-label-Line+Number]:
2350 * f = File.open('t.txt')
2351 * f.tell # => 0
2352 * f.lineno # => 0
2353 * f.gets # => "First line\n"
2354 * f.tell # => 12
2355 * f.lineno # => 1
2356 * f.rewind # => 0
2357 * f.tell # => 0
2358 * f.lineno # => 0
2360 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2364 static VALUE
2365 rb_io_rewind(VALUE io)
2367 rb_io_t *fptr;
2369 GetOpenFile(io, fptr);
2370 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2371 if (io == ARGF.current_file) {
2372 ARGF.lineno -= fptr->lineno;
2374 fptr->lineno = 0;
2375 if (fptr->readconv) {
2376 clear_readconv(fptr);
2379 return INT2FIX(0);
2382 static int
2383 fptr_wait_readable(rb_io_t *fptr)
2385 int ret = rb_io_maybe_wait_readable(errno, fptr->self, Qnil);
2387 if (ret)
2388 rb_io_check_closed(fptr);
2390 return ret;
2393 static int
2394 io_fillbuf(rb_io_t *fptr)
2396 ssize_t r;
2398 if (fptr->rbuf.ptr == NULL) {
2399 fptr->rbuf.off = 0;
2400 fptr->rbuf.len = 0;
2401 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2402 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2403 #ifdef _WIN32
2404 fptr->rbuf.capa--;
2405 #endif
2407 if (fptr->rbuf.len == 0) {
2408 retry:
2409 r = rb_read_internal(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2411 if (r < 0) {
2412 if (fptr_wait_readable(fptr))
2413 goto retry;
2415 int e = errno;
2416 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2417 if (!NIL_P(fptr->pathv)) {
2418 rb_str_append(path, fptr->pathv);
2421 rb_syserr_fail_path(e, path);
2423 if (r > 0) rb_io_check_closed(fptr);
2424 fptr->rbuf.off = 0;
2425 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2426 if (r == 0)
2427 return -1; /* EOF */
2429 return 0;
2433 * call-seq:
2434 * eof -> true or false
2436 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2437 * see {Position}[#class-IO-label-Position]:
2439 * f = File.open('t.txt')
2440 * f.eof # => false
2441 * f.seek(0, :END) # => 0
2442 * f.eof # => true
2444 * Raises an exception unless the stream is opened for reading;
2445 * see {Mode}[#class-IO-label-Mode].
2447 * If +self+ is a stream such as pipe or socket, this method
2448 * blocks until the other end sends some data or closes it:
2450 * r, w = IO.pipe
2451 * Thread.new { sleep 1; w.close }
2452 * r.eof? # => true # After 1-second wait.
2454 * r, w = IO.pipe
2455 * Thread.new { sleep 1; w.puts "a" }
2456 * r.eof? # => false # After 1-second wait.
2458 * r, w = IO.pipe
2459 * r.eof? # blocks forever
2461 * Note that this method reads data to the input byte buffer. So
2462 * IO#sysread may not behave as you intend with IO#eof?, unless you
2463 * call IO#rewind first (which is not available for some streams).
2465 * I#eof? is an alias for IO#eof.
2469 VALUE
2470 rb_io_eof(VALUE io)
2472 rb_io_t *fptr;
2474 GetOpenFile(io, fptr);
2475 rb_io_check_char_readable(fptr);
2477 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2478 if (READ_DATA_PENDING(fptr)) return Qfalse;
2479 READ_CHECK(fptr);
2480 #if RUBY_CRLF_ENVIRONMENT
2481 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2482 return RBOOL(eof(fptr->fd));;
2484 #endif
2485 return RBOOL(io_fillbuf(fptr) < 0);
2489 * call-seq:
2490 * sync -> true or false
2492 * Returns the current sync mode of the stream.
2493 * When sync mode is true, all output is immediately flushed to the underlying
2494 * operating system and is not buffered by Ruby internally. See also #fsync.
2496 * f = File.open('t.tmp', 'w')
2497 * f.sync # => false
2498 * f.sync = true
2499 * f.sync # => true
2503 static VALUE
2504 rb_io_sync(VALUE io)
2506 rb_io_t *fptr;
2508 io = GetWriteIO(io);
2509 GetOpenFile(io, fptr);
2510 return RBOOL(fptr->mode & FMODE_SYNC);
2513 #ifdef HAVE_FSYNC
2516 * call-seq:
2517 * sync = boolean -> boolean
2519 * Sets the _sync_ _mode_ for the stream to the given value;
2520 * returns the given value.
2522 * Values for the sync mode:
2524 * - +true+: All output is immediately flushed to the
2525 * underlying operating system and is not buffered internally.
2526 * - +false+: Output may be buffered internally.
2528 * Example;
2530 * f = File.open('t.tmp', 'w')
2531 * f.sync # => false
2532 * f.sync = true
2533 * f.sync # => true
2535 * Related: IO#fsync.
2539 static VALUE
2540 rb_io_set_sync(VALUE io, VALUE sync)
2542 rb_io_t *fptr;
2544 io = GetWriteIO(io);
2545 GetOpenFile(io, fptr);
2546 if (RTEST(sync)) {
2547 fptr->mode |= FMODE_SYNC;
2549 else {
2550 fptr->mode &= ~FMODE_SYNC;
2552 return sync;
2556 * call-seq:
2557 * fsync -> 0
2559 * Immediately writes to disk all data buffered in the stream,
2560 * via the operating system's <tt>fsync(2)</tt>.
2562 * Note this difference:
2564 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2565 * but does not guarantee that the operating system actually writes the data to disk.
2566 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2567 * and that data is written to disk.
2569 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2573 static VALUE
2574 rb_io_fsync(VALUE io)
2576 rb_io_t *fptr;
2578 io = GetWriteIO(io);
2579 GetOpenFile(io, fptr);
2581 if (io_fflush(fptr) < 0)
2582 rb_sys_fail_on_write(fptr);
2583 if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
2584 rb_sys_fail_path(fptr->pathv);
2585 return INT2FIX(0);
2587 #else
2588 # define rb_io_fsync rb_f_notimplement
2589 # define rb_io_sync rb_f_notimplement
2590 static VALUE
2591 rb_io_set_sync(VALUE io, VALUE sync)
2593 rb_notimplement();
2594 UNREACHABLE;
2596 #endif
2598 #ifdef HAVE_FDATASYNC
2599 static VALUE
2600 nogvl_fdatasync(void *ptr)
2602 rb_io_t *fptr = ptr;
2604 #ifdef _WIN32
2605 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2606 return 0;
2607 #endif
2608 return (VALUE)fdatasync(fptr->fd);
2612 * call-seq:
2613 * fdatasync -> 0
2615 * Immediately writes to disk all data buffered in the stream,
2616 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2617 * otherwise via <tt>fsync(2)</tt>, if supported;
2618 * otherwise raises an exception.
2622 static VALUE
2623 rb_io_fdatasync(VALUE io)
2625 rb_io_t *fptr;
2627 io = GetWriteIO(io);
2628 GetOpenFile(io, fptr);
2630 if (io_fflush(fptr) < 0)
2631 rb_sys_fail_on_write(fptr);
2633 if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
2634 return INT2FIX(0);
2636 /* fall back */
2637 return rb_io_fsync(io);
2639 #else
2640 #define rb_io_fdatasync rb_io_fsync
2641 #endif
2644 * call-seq:
2645 * fileno -> integer
2647 * Returns the integer file descriptor for the stream:
2649 * $stdin.fileno # => 0
2650 * $stdout.fileno # => 1
2651 * $stderr.fileno # => 2
2652 * File.open('t.txt').fileno # => 10
2654 * IO#to_i is an alias for IO#fileno.
2658 static VALUE
2659 rb_io_fileno(VALUE io)
2661 rb_io_t *fptr = RFILE(io)->fptr;
2662 int fd;
2664 rb_io_check_closed(fptr);
2665 fd = fptr->fd;
2666 return INT2FIX(fd);
2670 rb_io_descriptor(VALUE io)
2672 if (RB_TYPE_P(io, T_FILE)) {
2673 rb_io_t *fptr = RFILE(io)->fptr;
2674 rb_io_check_closed(fptr);
2675 return fptr->fd;
2677 else {
2678 return RB_NUM2INT(rb_funcall(io, id_fileno, 0));
2683 * call-seq:
2684 * pid -> integer or nil
2686 * Returns the process ID of a child process associated with the stream,
2687 * which will have been set by IO#popen, or +nil+ if the stream was not
2688 * created by IO#popen:
2690 * pipe = IO.popen("-")
2691 * if pipe
2692 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2693 * else
2694 * $stderr.puts "In child, pid is #{$$}"
2695 * end
2697 * Output:
2699 * In child, pid is 26209
2700 * In parent, child pid is 26209
2704 static VALUE
2705 rb_io_pid(VALUE io)
2707 rb_io_t *fptr;
2709 GetOpenFile(io, fptr);
2710 if (!fptr->pid)
2711 return Qnil;
2712 return PIDT2NUM(fptr->pid);
2717 * call-seq:
2718 * inspect -> string
2720 * Returns a string representation of +self+:
2722 * f = File.open('t.txt')
2723 * f.inspect # => "#<File:t.txt>"
2727 static VALUE
2728 rb_io_inspect(VALUE obj)
2730 rb_io_t *fptr;
2731 VALUE result;
2732 static const char closed[] = " (closed)";
2734 fptr = RFILE(obj)->fptr;
2735 if (!fptr) return rb_any_to_s(obj);
2736 result = rb_str_new_cstr("#<");
2737 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2738 rb_str_cat2(result, ":");
2739 if (NIL_P(fptr->pathv)) {
2740 if (fptr->fd < 0) {
2741 rb_str_cat(result, closed+1, strlen(closed)-1);
2743 else {
2744 rb_str_catf(result, "fd %d", fptr->fd);
2747 else {
2748 rb_str_append(result, fptr->pathv);
2749 if (fptr->fd < 0) {
2750 rb_str_cat(result, closed, strlen(closed));
2753 return rb_str_cat2(result, ">");
2757 * call-seq:
2758 * to_io -> self
2760 * Returns +self+.
2764 static VALUE
2765 rb_io_to_io(VALUE io)
2767 return io;
2770 /* reading functions */
2771 static long
2772 read_buffered_data(char *ptr, long len, rb_io_t *fptr)
2774 int n;
2776 n = READ_DATA_PENDING_COUNT(fptr);
2777 if (n <= 0) return 0;
2778 if (n > len) n = (int)len;
2779 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
2780 fptr->rbuf.off += n;
2781 fptr->rbuf.len -= n;
2782 return n;
2785 static long
2786 io_bufread(char *ptr, long len, rb_io_t *fptr)
2788 long offset = 0;
2789 long n = len;
2790 long c;
2792 if (READ_DATA_PENDING(fptr) == 0) {
2793 while (n > 0) {
2794 again:
2795 rb_io_check_closed(fptr);
2796 c = rb_read_internal(fptr, ptr+offset, n);
2797 if (c == 0) break;
2798 if (c < 0) {
2799 if (fptr_wait_readable(fptr))
2800 goto again;
2801 return -1;
2803 offset += c;
2804 if ((n -= c) <= 0) break;
2806 return len - n;
2809 while (n > 0) {
2810 c = read_buffered_data(ptr+offset, n, fptr);
2811 if (c > 0) {
2812 offset += c;
2813 if ((n -= c) <= 0) break;
2815 rb_io_check_closed(fptr);
2816 if (io_fillbuf(fptr) < 0) {
2817 break;
2820 return len - n;
2823 static int io_setstrbuf(VALUE *str, long len);
2825 struct bufread_arg {
2826 char *str_ptr;
2827 long len;
2828 rb_io_t *fptr;
2831 static VALUE
2832 bufread_call(VALUE arg)
2834 struct bufread_arg *p = (struct bufread_arg *)arg;
2835 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
2836 return Qundef;
2839 static long
2840 io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
2842 long len;
2843 struct bufread_arg arg;
2845 io_setstrbuf(&str, offset + size);
2846 arg.str_ptr = RSTRING_PTR(str) + offset;
2847 arg.len = size;
2848 arg.fptr = fptr;
2849 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
2850 len = arg.len;
2851 if (len < 0) rb_sys_fail_path(fptr->pathv);
2852 return len;
2855 static long
2856 remain_size(rb_io_t *fptr)
2858 struct stat st;
2859 off_t siz = READ_DATA_PENDING_COUNT(fptr);
2860 off_t pos;
2862 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
2863 #if defined(__HAIKU__)
2864 && (st.st_dev > 3)
2865 #endif
2868 if (io_fflush(fptr) < 0)
2869 rb_sys_fail_on_write(fptr);
2870 pos = lseek(fptr->fd, 0, SEEK_CUR);
2871 if (st.st_size >= pos && pos >= 0) {
2872 siz += st.st_size - pos;
2873 if (siz > LONG_MAX) {
2874 rb_raise(rb_eIOError, "file too big for single read");
2878 else {
2879 siz += BUFSIZ;
2881 return (long)siz;
2884 static VALUE
2885 io_enc_str(VALUE str, rb_io_t *fptr)
2887 rb_enc_associate(str, io_read_encoding(fptr));
2888 return str;
2891 static void
2892 make_readconv(rb_io_t *fptr, int size)
2894 if (!fptr->readconv) {
2895 int ecflags;
2896 VALUE ecopts;
2897 const char *sname, *dname;
2898 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
2899 ecopts = fptr->encs.ecopts;
2900 if (fptr->encs.enc2) {
2901 sname = rb_enc_name(fptr->encs.enc2);
2902 dname = rb_enc_name(fptr->encs.enc);
2904 else {
2905 sname = dname = "";
2907 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
2908 if (!fptr->readconv)
2909 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
2910 fptr->cbuf.off = 0;
2911 fptr->cbuf.len = 0;
2912 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
2913 fptr->cbuf.capa = size;
2914 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
2918 #define MORE_CHAR_SUSPENDED Qtrue
2919 #define MORE_CHAR_FINISHED Qnil
2920 static VALUE
2921 fill_cbuf(rb_io_t *fptr, int ec_flags)
2923 const unsigned char *ss, *sp, *se;
2924 unsigned char *ds, *dp, *de;
2925 rb_econv_result_t res;
2926 int putbackable;
2927 int cbuf_len0;
2928 VALUE exc;
2930 ec_flags |= ECONV_PARTIAL_INPUT;
2932 if (fptr->cbuf.len == fptr->cbuf.capa)
2933 return MORE_CHAR_SUSPENDED; /* cbuf full */
2934 if (fptr->cbuf.len == 0)
2935 fptr->cbuf.off = 0;
2936 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
2937 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
2938 fptr->cbuf.off = 0;
2941 cbuf_len0 = fptr->cbuf.len;
2943 while (1) {
2944 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
2945 se = sp + fptr->rbuf.len;
2946 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
2947 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
2948 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
2949 fptr->rbuf.off += (int)(sp - ss);
2950 fptr->rbuf.len -= (int)(sp - ss);
2951 fptr->cbuf.len += (int)(dp - ds);
2953 putbackable = rb_econv_putbackable(fptr->readconv);
2954 if (putbackable) {
2955 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
2956 fptr->rbuf.off -= putbackable;
2957 fptr->rbuf.len += putbackable;
2960 exc = rb_econv_make_exception(fptr->readconv);
2961 if (!NIL_P(exc))
2962 return exc;
2964 if (cbuf_len0 != fptr->cbuf.len)
2965 return MORE_CHAR_SUSPENDED;
2967 if (res == econv_finished) {
2968 return MORE_CHAR_FINISHED;
2971 if (res == econv_source_buffer_empty) {
2972 if (fptr->rbuf.len == 0) {
2973 READ_CHECK(fptr);
2974 if (io_fillbuf(fptr) < 0) {
2975 if (!fptr->readconv) {
2976 return MORE_CHAR_FINISHED;
2978 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
2979 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
2980 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
2981 fptr->cbuf.len += (int)(dp - ds);
2982 rb_econv_check_error(fptr->readconv);
2983 break;
2988 if (cbuf_len0 != fptr->cbuf.len)
2989 return MORE_CHAR_SUSPENDED;
2991 return MORE_CHAR_FINISHED;
2994 static VALUE
2995 more_char(rb_io_t *fptr)
2997 VALUE v;
2998 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
2999 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3000 rb_exc_raise(v);
3001 return v;
3004 static VALUE
3005 io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3007 VALUE str = Qnil;
3008 if (strp) {
3009 str = *strp;
3010 if (NIL_P(str)) {
3011 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3013 else {
3014 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3016 rb_enc_associate(str, fptr->encs.enc);
3018 fptr->cbuf.off += len;
3019 fptr->cbuf.len -= len;
3020 /* xxx: set coderange */
3021 if (fptr->cbuf.len == 0)
3022 fptr->cbuf.off = 0;
3023 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3024 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3025 fptr->cbuf.off = 0;
3027 return str;
3030 static int
3031 io_setstrbuf(VALUE *str, long len)
3033 #ifdef _WIN32
3034 len = (len + 1) & ~1L; /* round up for wide char */
3035 #endif
3036 if (NIL_P(*str)) {
3037 *str = rb_str_new(0, len);
3038 return TRUE;
3040 else {
3041 VALUE s = StringValue(*str);
3042 long clen = RSTRING_LEN(s);
3043 if (clen >= len) {
3044 rb_str_modify(s);
3045 return FALSE;
3047 len -= clen;
3049 rb_str_modify_expand(*str, len);
3050 return FALSE;
3053 #define MAX_REALLOC_GAP 4096
3054 static void
3055 io_shrink_read_string(VALUE str, long n)
3057 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3058 rb_str_resize(str, n);
3062 static void
3063 io_set_read_length(VALUE str, long n, int shrinkable)
3065 if (RSTRING_LEN(str) != n) {
3066 rb_str_modify(str);
3067 rb_str_set_len(str, n);
3068 if (shrinkable) io_shrink_read_string(str, n);
3072 static VALUE
3073 read_all(rb_io_t *fptr, long siz, VALUE str)
3075 long bytes;
3076 long n;
3077 long pos;
3078 rb_encoding *enc;
3079 int cr;
3080 int shrinkable;
3082 if (NEED_READCONV(fptr)) {
3083 int first = !NIL_P(str);
3084 SET_BINARY_MODE(fptr);
3085 shrinkable = io_setstrbuf(&str,0);
3086 make_readconv(fptr, 0);
3087 while (1) {
3088 VALUE v;
3089 if (fptr->cbuf.len) {
3090 if (first) rb_str_set_len(str, first = 0);
3091 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3093 v = fill_cbuf(fptr, 0);
3094 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3095 if (fptr->cbuf.len) {
3096 if (first) rb_str_set_len(str, first = 0);
3097 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3099 rb_exc_raise(v);
3101 if (v == MORE_CHAR_FINISHED) {
3102 clear_readconv(fptr);
3103 if (first) rb_str_set_len(str, first = 0);
3104 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3105 return io_enc_str(str, fptr);
3110 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3111 bytes = 0;
3112 pos = 0;
3114 enc = io_read_encoding(fptr);
3115 cr = 0;
3117 if (siz == 0) siz = BUFSIZ;
3118 shrinkable = io_setstrbuf(&str, siz);
3119 for (;;) {
3120 READ_CHECK(fptr);
3121 n = io_fread(str, bytes, siz - bytes, fptr);
3122 if (n == 0 && bytes == 0) {
3123 rb_str_set_len(str, 0);
3124 break;
3126 bytes += n;
3127 rb_str_set_len(str, bytes);
3128 if (cr != ENC_CODERANGE_BROKEN)
3129 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3130 if (bytes < siz) break;
3131 siz += BUFSIZ;
3132 rb_str_modify_expand(str, BUFSIZ);
3134 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3135 str = io_enc_str(str, fptr);
3136 ENC_CODERANGE_SET(str, cr);
3137 return str;
3140 void
3141 rb_io_set_nonblock(rb_io_t *fptr)
3143 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3144 rb_sys_fail_path(fptr->pathv);
3148 static VALUE
3149 read_internal_call(VALUE arg)
3151 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3153 VALUE scheduler = rb_fiber_scheduler_current();
3154 if (scheduler != Qnil) {
3155 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3157 if (result != Qundef) {
3158 // This is actually returned as a pseudo-VALUE and later cast to a long:
3159 return (VALUE)rb_fiber_scheduler_io_result_apply(result);
3163 return rb_thread_io_blocking_region(internal_read_func, iis, iis->fptr->fd);
3166 static long
3167 read_internal_locktmp(VALUE str, struct io_internal_read_struct *iis)
3169 return (long)rb_str_locktmp_ensure(str, read_internal_call, (VALUE)iis);
3172 #define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3174 static VALUE
3175 io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3177 rb_io_t *fptr;
3178 VALUE length, str;
3179 long n, len;
3180 struct io_internal_read_struct iis;
3181 int shrinkable;
3183 rb_scan_args(argc, argv, "11", &length, &str);
3185 if ((len = NUM2LONG(length)) < 0) {
3186 rb_raise(rb_eArgError, "negative length %ld given", len);
3189 shrinkable = io_setstrbuf(&str, len);
3191 GetOpenFile(io, fptr);
3192 rb_io_check_byte_readable(fptr);
3194 if (len == 0) {
3195 io_set_read_length(str, 0, shrinkable);
3196 return str;
3199 if (!nonblock)
3200 READ_CHECK(fptr);
3201 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3202 if (n <= 0) {
3203 again:
3204 if (nonblock) {
3205 rb_io_set_nonblock(fptr);
3207 io_setstrbuf(&str, len);
3208 iis.th = rb_thread_current();
3209 iis.fptr = fptr;
3210 iis.nonblock = nonblock;
3211 iis.buf = RSTRING_PTR(str);
3212 iis.capa = len;
3213 n = read_internal_locktmp(str, &iis);
3214 if (n < 0) {
3215 int e = errno;
3216 if (!nonblock && fptr_wait_readable(fptr))
3217 goto again;
3218 if (nonblock && (io_again_p(e))) {
3219 if (no_exception)
3220 return sym_wait_readable;
3221 else
3222 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3223 e, "read would block");
3225 rb_syserr_fail_path(e, fptr->pathv);
3228 io_set_read_length(str, n, shrinkable);
3230 if (n == 0)
3231 return Qnil;
3232 else
3233 return str;
3237 * call-seq:
3238 * readpartial(maxlen) -> string
3239 * readpartial(maxlen, out_string) -> out_string
3241 * Reads up to +maxlen+ bytes from the stream;
3242 * returns a string (either a new string or the given +out_string+).
3243 * Its encoding is:
3245 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3246 * - ASCII-8BIT, otherwise.
3248 * - Contains +maxlen+ bytes from the stream, if available.
3249 * - Otherwise contains all available bytes, if any available.
3250 * - Otherwise is an empty string.
3252 * With the single non-negative integer argument +maxlen+ given,
3253 * returns a new string:
3255 * f = File.new('t.txt')
3256 * f.readpartial(20) # => "First line\nSecond l"
3257 * f.readpartial(20) # => "ine\n\nFourth line\n"
3258 * f.readpartial(20) # => "Fifth line\n"
3259 * f.readpartial(20) # Raises EOFError.
3261 * With both argument +maxlen+ and string argument +out_string+ given,
3262 * returns modified +out_string+:
3264 * f = File.new('t.txt')
3265 * s = 'foo'
3266 * f.readpartial(20, s) # => "First line\nSecond l"
3267 * s = 'bar'
3268 * f.readpartial(0, s) # => ""
3270 * This method is useful for a stream such as a pipe, a socket, or a tty.
3271 * It blocks only when no data is immediately available.
3272 * This means that it blocks only when _all_ of the following are true:
3274 * - The byte buffer in the stream is empty.
3275 * - The content of the stream is empty.
3276 * - The stream is not at EOF.
3278 * When blocked, the method waits for either more data or EOF on the stream:
3280 * - If more data is read, the method returns the data.
3281 * - If EOF is reached, the method raises EOFError.
3283 * When not blocked, the method responds immediately:
3285 * - Returns data from the buffer if there is any.
3286 * - Otherwise returns data from the stream if there is any.
3287 * - Otherwise raises EOFError if the stream has reached EOF.
3289 * Note that this method is similar to sysread. The differences are:
3291 * - If the byte buffer is not empty, read from the byte buffer
3292 * instead of "sysread for buffered IO (IOError)".
3293 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3294 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3295 * readpartial retries the system call.
3297 * The latter means that readpartial is non-blocking-flag insensitive.
3298 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3299 * if the fd is blocking mode.
3301 * Examples:
3303 * # # Returned Buffer Content Pipe Content
3304 * r, w = IO.pipe #
3305 * w << 'abc' # "" "abc".
3306 * r.readpartial(4096) # => "abc" "" ""
3307 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3309 * # # Returned Buffer Content Pipe Content
3310 * r, w = IO.pipe #
3311 * w << 'abc' # "" "abc"
3312 * w.close # "" "abc" EOF
3313 * r.readpartial(4096) # => "abc" "" EOF
3314 * r.readpartial(4096) # raises EOFError
3316 * # # Returned Buffer Content Pipe Content
3317 * r, w = IO.pipe #
3318 * w << "abc\ndef\n" # "" "abc\ndef\n"
3319 * r.gets # => "abc\n" "def\n" ""
3320 * w << "ghi\n" # "def\n" "ghi\n"
3321 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3322 * r.readpartial(4096) # => "ghi\n" "" ""
3326 static VALUE
3327 io_readpartial(int argc, VALUE *argv, VALUE io)
3329 VALUE ret;
3331 ret = io_getpartial(argc, argv, io, Qnil, 0);
3332 if (NIL_P(ret))
3333 rb_eof_error();
3334 return ret;
3337 static VALUE
3338 io_nonblock_eof(int no_exception)
3340 if (!no_exception) {
3341 rb_eof_error();
3343 return Qnil;
3346 /* :nodoc: */
3347 static VALUE
3348 io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3350 rb_io_t *fptr;
3351 long n, len;
3352 struct io_internal_read_struct iis;
3353 int shrinkable;
3355 if ((len = NUM2LONG(length)) < 0) {
3356 rb_raise(rb_eArgError, "negative length %ld given", len);
3359 shrinkable = io_setstrbuf(&str, len);
3360 rb_bool_expected(ex, "exception");
3362 GetOpenFile(io, fptr);
3363 rb_io_check_byte_readable(fptr);
3365 if (len == 0) {
3366 io_set_read_length(str, 0, shrinkable);
3367 return str;
3370 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3371 if (n <= 0) {
3372 rb_io_set_nonblock(fptr);
3373 shrinkable |= io_setstrbuf(&str, len);
3374 iis.fptr = fptr;
3375 iis.nonblock = 1;
3376 iis.buf = RSTRING_PTR(str);
3377 iis.capa = len;
3378 n = read_internal_locktmp(str, &iis);
3379 if (n < 0) {
3380 int e = errno;
3381 if (io_again_p(e)) {
3382 if (!ex) return sym_wait_readable;
3383 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3384 e, "read would block");
3386 rb_syserr_fail_path(e, fptr->pathv);
3389 io_set_read_length(str, n, shrinkable);
3391 if (n == 0) {
3392 if (!ex) return Qnil;
3393 rb_eof_error();
3396 return str;
3399 /* :nodoc: */
3400 static VALUE
3401 io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3403 rb_io_t *fptr;
3404 long n;
3406 if (!RB_TYPE_P(str, T_STRING))
3407 str = rb_obj_as_string(str);
3408 rb_bool_expected(ex, "exception");
3410 io = GetWriteIO(io);
3411 GetOpenFile(io, fptr);
3412 rb_io_check_writable(fptr);
3414 if (io_fflush(fptr) < 0)
3415 rb_sys_fail_on_write(fptr);
3417 rb_io_set_nonblock(fptr);
3418 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3419 RB_GC_GUARD(str);
3421 if (n < 0) {
3422 int e = errno;
3423 if (io_again_p(e)) {
3424 if (!ex) {
3425 return sym_wait_writable;
3427 else {
3428 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3431 rb_syserr_fail_path(e, fptr->pathv);
3434 return LONG2FIX(n);
3438 * call-seq:
3439 * read(maxlen = nil) -> string or nil
3440 * read(maxlen = nil, out_string) -> out_string or nil
3442 * Reads bytes from the stream (in binary mode):
3444 * - If +maxlen+ is +nil+, reads all bytes.
3445 * - Otherwise reads +maxlen+ bytes, if available.
3446 * - Otherwise reads all bytes.
3448 * Returns a string (either a new string or the given +out_string+)
3449 * containing the bytes read.
3450 * The encoding of the string depends on both +maxLen+ and +out_string+:
3452 * - +maxlen+ is +nil+: uses internal encoding of +self+
3453 * (regardless of whether +out_string+ was given).
3454 * - +maxlen+ not +nil+:
3456 * - +out_string+ given: encoding of +out_string+ not modified.
3457 * - +out_string+ not given: ASCII-8BIT is used.
3459 * <b>Without Argument +out_string+</b>
3461 * When argument +out_string+ is omitted,
3462 * the returned value is a new string:
3464 * f = File.new('t.txt')
3465 * f.read
3466 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3467 * f.rewind
3468 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3469 * f.read(30) # => "rth line\r\nFifth line\r\n"
3470 * f.read(30) # => nil
3472 * If +maxlen+ is zero, returns an empty string.
3474 * <b> With Argument +out_string+</b>
3476 * When argument +out_string+ is given,
3477 * the returned value is +out_string+, whose content is replaced:
3479 * f = File.new('t.txt')
3480 * s = 'foo' # => "foo"
3481 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3482 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3483 * f.rewind
3484 * s = 'bar'
3485 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3486 * s # => "First line\r\nSecond line\r\n\r\nFou"
3487 * s = 'baz'
3488 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3489 * s # => "rth line\r\nFifth line\r\n"
3490 * s = 'bat'
3491 * f.read(30, s) # => nil
3492 * s # => ""
3494 * Note that this method behaves like the fread() function in C.
3495 * This means it retries to invoke read(2) system calls to read data
3496 * with the specified maxlen (or until EOF).
3498 * This behavior is preserved even if the stream is in non-blocking mode.
3499 * (This method is non-blocking-flag insensitive as other methods.)
3501 * If you need the behavior like a single read(2) system call,
3502 * consider #readpartial, #read_nonblock, and #sysread.
3506 static VALUE
3507 io_read(int argc, VALUE *argv, VALUE io)
3509 rb_io_t *fptr;
3510 long n, len;
3511 VALUE length, str;
3512 int shrinkable;
3513 #if RUBY_CRLF_ENVIRONMENT
3514 int previous_mode;
3515 #endif
3517 rb_scan_args(argc, argv, "02", &length, &str);
3519 if (NIL_P(length)) {
3520 GetOpenFile(io, fptr);
3521 rb_io_check_char_readable(fptr);
3522 return read_all(fptr, remain_size(fptr), str);
3524 len = NUM2LONG(length);
3525 if (len < 0) {
3526 rb_raise(rb_eArgError, "negative length %ld given", len);
3529 shrinkable = io_setstrbuf(&str,len);
3531 GetOpenFile(io, fptr);
3532 rb_io_check_byte_readable(fptr);
3533 if (len == 0) {
3534 io_set_read_length(str, 0, shrinkable);
3535 return str;
3538 READ_CHECK(fptr);
3539 #if RUBY_CRLF_ENVIRONMENT
3540 previous_mode = set_binary_mode_with_seek_cur(fptr);
3541 #endif
3542 n = io_fread(str, 0, len, fptr);
3543 io_set_read_length(str, n, shrinkable);
3544 #if RUBY_CRLF_ENVIRONMENT
3545 if (previous_mode == O_TEXT) {
3546 setmode(fptr->fd, O_TEXT);
3548 #endif
3549 if (n == 0) return Qnil;
3551 return str;
3554 static void
3555 rscheck(const char *rsptr, long rslen, VALUE rs)
3557 if (!rs) return;
3558 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3559 rb_raise(rb_eRuntimeError, "rs modified");
3562 static int
3563 appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
3565 VALUE str = *strp;
3566 long limit = *lp;
3568 if (NEED_READCONV(fptr)) {
3569 SET_BINARY_MODE(fptr);
3570 make_readconv(fptr, 0);
3571 do {
3572 const char *p, *e;
3573 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3574 if (searchlen) {
3575 p = READ_CHAR_PENDING_PTR(fptr);
3576 if (0 < limit && limit < searchlen)
3577 searchlen = (int)limit;
3578 e = memchr(p, delim, searchlen);
3579 if (e) {
3580 int len = (int)(e-p+1);
3581 if (NIL_P(str))
3582 *strp = str = rb_str_new(p, len);
3583 else
3584 rb_str_buf_cat(str, p, len);
3585 fptr->cbuf.off += len;
3586 fptr->cbuf.len -= len;
3587 limit -= len;
3588 *lp = limit;
3589 return delim;
3592 if (NIL_P(str))
3593 *strp = str = rb_str_new(p, searchlen);
3594 else
3595 rb_str_buf_cat(str, p, searchlen);
3596 fptr->cbuf.off += searchlen;
3597 fptr->cbuf.len -= searchlen;
3598 limit -= searchlen;
3600 if (limit == 0) {
3601 *lp = limit;
3602 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3605 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3606 clear_readconv(fptr);
3607 *lp = limit;
3608 return EOF;
3611 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3612 do {
3613 long pending = READ_DATA_PENDING_COUNT(fptr);
3614 if (pending > 0) {
3615 const char *p = READ_DATA_PENDING_PTR(fptr);
3616 const char *e;
3617 long last;
3619 if (limit > 0 && pending > limit) pending = limit;
3620 e = memchr(p, delim, pending);
3621 if (e) pending = e - p + 1;
3622 if (!NIL_P(str)) {
3623 last = RSTRING_LEN(str);
3624 rb_str_resize(str, last + pending);
3626 else {
3627 last = 0;
3628 *strp = str = rb_str_buf_new(pending);
3629 rb_str_set_len(str, pending);
3631 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3632 limit -= pending;
3633 *lp = limit;
3634 if (e) return delim;
3635 if (limit == 0)
3636 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3638 READ_CHECK(fptr);
3639 } while (io_fillbuf(fptr) >= 0);
3640 *lp = limit;
3641 return EOF;
3644 static inline int
3645 swallow(rb_io_t *fptr, int term)
3647 if (NEED_READCONV(fptr)) {
3648 rb_encoding *enc = io_read_encoding(fptr);
3649 int needconv = rb_enc_mbminlen(enc) != 1;
3650 SET_BINARY_MODE(fptr);
3651 make_readconv(fptr, 0);
3652 do {
3653 size_t cnt;
3654 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3655 const char *p = READ_CHAR_PENDING_PTR(fptr);
3656 int i;
3657 if (!needconv) {
3658 if (*p != term) return TRUE;
3659 i = (int)cnt;
3660 while (--i && *++p == term);
3662 else {
3663 const char *e = p + cnt;
3664 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3665 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3666 i = (int)(e - p);
3668 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3670 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3671 return FALSE;
3674 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3675 do {
3676 size_t cnt;
3677 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3678 char buf[1024];
3679 const char *p = READ_DATA_PENDING_PTR(fptr);
3680 int i;
3681 if (cnt > sizeof buf) cnt = sizeof buf;
3682 if (*p != term) return TRUE;
3683 i = (int)cnt;
3684 while (--i && *++p == term);
3685 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
3686 rb_sys_fail_path(fptr->pathv);
3688 READ_CHECK(fptr);
3689 } while (io_fillbuf(fptr) == 0);
3690 return FALSE;
3693 static VALUE
3694 rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
3696 VALUE str = Qnil;
3697 int len = 0;
3698 long pos = 0;
3699 int cr = 0;
3701 do {
3702 int pending = READ_DATA_PENDING_COUNT(fptr);
3704 if (pending > 0) {
3705 const char *p = READ_DATA_PENDING_PTR(fptr);
3706 const char *e;
3707 int chomplen = 0;
3709 e = memchr(p, '\n', pending);
3710 if (e) {
3711 pending = (int)(e - p + 1);
3712 if (chomp) {
3713 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
3716 if (NIL_P(str)) {
3717 str = rb_str_new(p, pending - chomplen);
3718 fptr->rbuf.off += pending;
3719 fptr->rbuf.len -= pending;
3721 else {
3722 rb_str_resize(str, len + pending - chomplen);
3723 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
3724 fptr->rbuf.off += chomplen;
3725 fptr->rbuf.len -= chomplen;
3726 if (pending == 1 && chomplen == 1 && len > 0) {
3727 if (RSTRING_PTR(str)[len-1] == '\r') {
3728 rb_str_resize(str, --len);
3729 break;
3733 len += pending - chomplen;
3734 if (cr != ENC_CODERANGE_BROKEN)
3735 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
3736 if (e) break;
3738 READ_CHECK(fptr);
3739 } while (io_fillbuf(fptr) >= 0);
3740 if (NIL_P(str)) return Qnil;
3742 str = io_enc_str(str, fptr);
3743 ENC_CODERANGE_SET(str, cr);
3744 fptr->lineno++;
3746 return str;
3749 struct getline_arg {
3750 VALUE io;
3751 VALUE rs;
3752 long limit;
3753 unsigned int chomp: 1;
3756 static void
3757 extract_getline_opts(VALUE opts, struct getline_arg *args)
3759 int chomp = FALSE;
3760 if (!NIL_P(opts)) {
3761 static ID kwds[1];
3762 VALUE vchomp;
3763 if (!kwds[0]) {
3764 kwds[0] = rb_intern_const("chomp");
3766 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
3767 chomp = (vchomp != Qundef) && RTEST(vchomp);
3769 args->chomp = chomp;
3772 static void
3773 extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
3775 VALUE rs = rb_rs, lim = Qnil;
3777 if (argc == 1) {
3778 VALUE tmp = Qnil;
3780 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
3781 rs = tmp;
3783 else {
3784 lim = argv[0];
3787 else if (2 <= argc) {
3788 rs = argv[0], lim = argv[1];
3789 if (!NIL_P(rs))
3790 StringValue(rs);
3792 args->rs = rs;
3793 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
3796 static void
3797 check_getline_args(VALUE *rsp, long *limit, VALUE io)
3799 rb_io_t *fptr;
3800 VALUE rs = *rsp;
3802 if (!NIL_P(rs)) {
3803 rb_encoding *enc_rs, *enc_io;
3805 GetOpenFile(io, fptr);
3806 enc_rs = rb_enc_get(rs);
3807 enc_io = io_read_encoding(fptr);
3808 if (enc_io != enc_rs &&
3809 (rb_enc_str_coderange(rs) != ENC_CODERANGE_7BIT ||
3810 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
3811 if (rs == rb_default_rs) {
3812 rs = rb_enc_str_new(0, 0, enc_io);
3813 rb_str_buf_cat_ascii(rs, "\n");
3814 *rsp = rs;
3816 else {
3817 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
3818 rb_enc_name(enc_io),
3819 rb_enc_name(enc_rs));
3825 static void
3826 prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
3828 VALUE opts;
3829 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
3830 extract_getline_args(argc, argv, args);
3831 extract_getline_opts(opts, args);
3832 check_getline_args(&args->rs, &args->limit, io);
3835 static VALUE
3836 rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
3838 VALUE str = Qnil;
3839 int nolimit = 0;
3840 rb_encoding *enc;
3842 rb_io_check_char_readable(fptr);
3843 if (NIL_P(rs) && limit < 0) {
3844 str = read_all(fptr, 0, Qnil);
3845 if (RSTRING_LEN(str) == 0) return Qnil;
3846 if (chomp) rb_str_chomp_string(str, rb_default_rs);
3848 else if (limit == 0) {
3849 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
3851 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
3852 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
3853 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3854 return rb_io_getline_fast(fptr, enc, chomp);
3856 else {
3857 int c, newline = -1;
3858 const char *rsptr = 0;
3859 long rslen = 0;
3860 int rspara = 0;
3861 int extra_limit = 16;
3862 int chomp_cr = chomp;
3864 SET_BINARY_MODE(fptr);
3865 enc = io_read_encoding(fptr);
3867 if (!NIL_P(rs)) {
3868 rslen = RSTRING_LEN(rs);
3869 if (rslen == 0) {
3870 rsptr = "\n\n";
3871 rslen = 2;
3872 rspara = 1;
3873 swallow(fptr, '\n');
3874 rs = 0;
3875 if (!rb_enc_asciicompat(enc)) {
3876 rs = rb_usascii_str_new(rsptr, rslen);
3877 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
3878 OBJ_FREEZE(rs);
3879 rsptr = RSTRING_PTR(rs);
3880 rslen = RSTRING_LEN(rs);
3883 else {
3884 rsptr = RSTRING_PTR(rs);
3886 newline = (unsigned char)rsptr[rslen - 1];
3887 chomp_cr = chomp && rslen == 1 && newline == '\n';
3890 /* MS - Optimization */
3891 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
3892 const char *s, *p, *pp, *e;
3894 if (c == newline) {
3895 if (RSTRING_LEN(str) < rslen) continue;
3896 s = RSTRING_PTR(str);
3897 e = RSTRING_END(str);
3898 p = e - rslen;
3899 pp = rb_enc_left_char_head(s, p, e, enc);
3900 if (pp != p) continue;
3901 if (!rspara) rscheck(rsptr, rslen, rs);
3902 if (memcmp(p, rsptr, rslen) == 0) {
3903 if (chomp) {
3904 if (chomp_cr && p > s && *(p-1) == '\r') --p;
3905 rb_str_set_len(str, p - s);
3907 break;
3910 if (limit == 0) {
3911 s = RSTRING_PTR(str);
3912 p = RSTRING_END(str);
3913 pp = rb_enc_left_char_head(s, p-1, p, enc);
3914 if (extra_limit &&
3915 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
3916 /* relax the limit while incomplete character.
3917 * extra_limit limits the relax length */
3918 limit = 1;
3919 extra_limit--;
3921 else {
3922 nolimit = 1;
3923 break;
3928 if (rspara && c != EOF)
3929 swallow(fptr, '\n');
3930 if (!NIL_P(str))
3931 str = io_enc_str(str, fptr);
3934 if (!NIL_P(str) && !nolimit) {
3935 fptr->lineno++;
3938 return str;
3941 static VALUE
3942 rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
3944 rb_io_t *fptr;
3945 int old_lineno, new_lineno;
3946 VALUE str;
3948 GetOpenFile(io, fptr);
3949 old_lineno = fptr->lineno;
3950 str = rb_io_getline_0(rs, limit, chomp, fptr);
3951 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
3952 if (io == ARGF.current_file) {
3953 ARGF.lineno += new_lineno - old_lineno;
3954 ARGF.last_lineno = ARGF.lineno;
3956 else {
3957 ARGF.last_lineno = new_lineno;
3961 return str;
3964 static VALUE
3965 rb_io_getline(int argc, VALUE *argv, VALUE io)
3967 struct getline_arg args;
3969 prepare_getline_args(argc, argv, &args, io);
3970 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
3973 VALUE
3974 rb_io_gets(VALUE io)
3976 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
3979 VALUE
3980 rb_io_gets_internal(VALUE io)
3982 rb_io_t *fptr;
3983 GetOpenFile(io, fptr);
3984 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
3988 * call-seq:
3989 * gets(sep = $/, **line_opts) -> string or nil
3990 * gets(limit, **line_opts) -> string or nil
3991 * gets(sep, limit, **line_opts) -> string or nil
3993 * Reads and returns a line from the stream
3994 * (see {Lines}[#class-IO-label-Lines])
3995 * assigns the return value to <tt>$_</tt>.
3997 * With no arguments given, returns the next line
3998 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4000 * f = File.open('t.txt')
4001 * f.gets # => "First line\n"
4002 * $_ # => "First line\n"
4003 * f.gets # => "\n"
4004 * f.gets # => "Fourth line\n"
4005 * f.gets # => "Fifth line\n"
4006 * f.gets # => nil
4008 * With only string argument +sep+ given,
4009 * returns the next line as determined by line separator +sep+,
4010 * or +nil+ if none;
4011 * see {Line Separator}[#class-IO-label-Line+Separator]:
4013 * f = File.new('t.txt')
4014 * f.gets('l') # => "First l"
4015 * f.gets('li') # => "ine\nSecond li"
4016 * f.gets('lin') # => "ne\n\nFourth lin"
4017 * f.gets # => "e\n"
4019 * The two special values for +sep+ are honored:
4021 * f = File.new('t.txt')
4022 * # Get all.
4023 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4024 * f.rewind
4025 * # Get paragraph (up to two line separators).
4026 * f.gets('') # => "First line\nSecond line\n\n"
4028 * With only integer argument +limit+ given,
4029 * limits the number of bytes in the line;
4030 * see {Line Limit}}[#class-IO-label-Line+Limit]:
4032 * # No more than one line.
4033 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4034 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4035 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4037 * With arguments +sep+ and +limit+ given,
4038 * combines the two behaviors:
4040 * - Returns the next line as determined by line separator +sep+,
4041 * or +nil+ if none.
4042 * - But returns no more bytes than are allowed by the limit.
4044 * For all forms above, trailing optional keyword arguments may be given;
4045 * see {Line Options}[#class-IO-label-Line+Options]:
4047 * f = File.open('t.txt')
4048 * # Chomp the lines.
4049 * f.gets(chomp: true) # => "First line"
4050 * f.gets(chomp: true) # => "Second line"
4051 * f.gets(chomp: true) # => ""
4052 * f.gets(chomp: true) # => "Fourth line"
4053 * f.gets(chomp: true) # => "Fifth line"
4054 * f.gets(chomp: true) # => nil
4058 static VALUE
4059 rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4061 VALUE str;
4063 str = rb_io_getline(argc, argv, io);
4064 rb_lastline_set(str);
4066 return str;
4070 * call-seq:
4071 * lineno -> integer
4073 * Returns the current line number for the stream.
4074 * See {Line Number}[#class-IO-label-Line+Number].
4078 static VALUE
4079 rb_io_lineno(VALUE io)
4081 rb_io_t *fptr;
4083 GetOpenFile(io, fptr);
4084 rb_io_check_char_readable(fptr);
4085 return INT2NUM(fptr->lineno);
4089 * call-seq:
4090 * lineno = integer -> integer
4092 * Sets and returns the line number for the stream.
4093 * See {Line Number}[#class-IO-label-Line+Number].
4097 static VALUE
4098 rb_io_set_lineno(VALUE io, VALUE lineno)
4100 rb_io_t *fptr;
4102 GetOpenFile(io, fptr);
4103 rb_io_check_char_readable(fptr);
4104 fptr->lineno = NUM2INT(lineno);
4105 return lineno;
4109 * call-seq:
4110 * readline(sep = $/, **line_opts) -> string
4111 * readline(limit, **line_opts) -> string
4112 * readline(sep, limit, **line_opts) -> string
4114 * Reads a line as with IO#gets, but raises EOFError if already at end-of-file.
4118 static VALUE
4119 rb_io_readline(int argc, VALUE *argv, VALUE io)
4121 VALUE line = rb_io_gets_m(argc, argv, io);
4123 if (NIL_P(line)) {
4124 rb_eof_error();
4126 return line;
4129 static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4132 * call-seq:
4133 * readlines(sep = $/, **line_opts) -> array
4134 * readlines(limit, **line_ops) -> array
4135 * readlines(sep, limit, **line_opts) -> array
4137 * Reads and returns all remaining line from the stream
4138 * (see {Lines}[#class-IO-label-Lines]);
4139 * does not modify <tt>$_</tt>.
4141 * With no arguments given, returns lines
4142 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4144 * f = File.new('t.txt')
4145 * f.readlines
4146 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4147 * f.readlines # => []
4149 * With only string argument +sep+ given,
4150 * returns lines as determined by line separator +sep+,
4151 * or +nil+ if none;
4152 * see {Line Separator}[#class-IO-label-Line+Separator]:
4154 * f = File.new('t.txt')
4155 * f.readlines('li')
4156 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4158 * The two special values for +sep+ are honored:
4160 * f = File.new('t.txt')
4161 * # Get all into one string.
4162 * f.readlines(nil)
4163 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4164 * # Get paragraphs (up to two line separators).
4165 * f.rewind
4166 * f.readlines('')
4167 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4169 * With only integer argument +limit+ given,
4170 * limits the number of bytes in each line;
4171 * see {Line Limit}}[#class-IO-label-Line+Limit]:
4173 * f = File.new('t.txt')
4174 * f.readlines(8)
4175 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4177 * With arguments +sep+ and +limit+ given,
4178 * combines the two behaviors:
4180 * - Returns lines as determined by line separator +sep+.
4181 * - But returns no more bytes in a line than are allowed by the limit.
4183 * For all forms above, trailing optional keyword arguments may be given;
4184 * see {Line Options}[#class-IO-label-Line+Options]:
4186 * f = File.new('t.txt')
4187 * f.readlines(chomp: true)
4188 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4192 static VALUE
4193 rb_io_readlines(int argc, VALUE *argv, VALUE io)
4195 struct getline_arg args;
4197 prepare_getline_args(argc, argv, &args, io);
4198 return io_readlines(&args, io);
4201 static VALUE
4202 io_readlines(const struct getline_arg *arg, VALUE io)
4204 VALUE line, ary;
4206 if (arg->limit == 0)
4207 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4208 ary = rb_ary_new();
4209 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4210 rb_ary_push(ary, line);
4212 return ary;
4216 * call-seq:
4217 * each_line(sep = $/, **line_opts) {|line| ... } -> self
4218 * each_line(limit, **line_opts) {|line| ... } -> self
4219 * each_line(sep, limit, **line_opts) {|line| ... } -> self
4220 * each_line -> enumerator
4222 * Calls the block with each remaining line read from the stream;
4223 * does nothing if already at end-of-file;
4224 * returns +self+.
4226 * With no arguments given, reads lines
4227 * as determined by line separator <tt>$/</tt>:
4229 * f = File.new('t.txt')
4230 * f.each_line {|line| p line }
4231 * f.each_line {|line| fail 'Cannot happen' }
4233 * Output:
4235 * "First line\n"
4236 * "Second line\n"
4237 * "\n"
4238 * "Fourth line\n"
4239 * "Fifth line\n"
4241 * With only string argument +sep+ given,
4242 * reads lines as determined by line separator +sep+;
4243 * see {Line Separator}[#class-IO-label-Line+Separator]:
4245 * f = File.new('t.txt')
4246 * f.each_line('li') {|line| p line }
4248 * Output:
4250 * "First li"
4251 * "ne\nSecond li"
4252 * "ne\n\nFourth li"
4253 * "ne\nFifth li"
4254 * "ne\n"
4256 * The two special values for +sep+ are honored:
4258 * f = File.new('t.txt')
4259 * # Get all into one string.
4260 * f.each_line(nil) {|line| p line }
4262 * Output:
4264 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4266 * f.rewind
4267 * # Get paragraphs (up to two line separators).
4268 * f.each_line('') {|line| p line }
4270 * Output:
4272 * "First line\nSecond line\n\n"
4273 * "Fourth line\nFifth line\n"
4275 * With only integer argument +limit+ given,
4276 * limits the number of bytes in each line;
4277 * see {Line Limit}}[#class-IO-label-Line+Limit]:
4279 * f = File.new('t.txt')
4280 * f.each_line(8) {|line| p line }
4282 * Output:
4284 * "First li"
4285 * "ne\n"
4286 * "Second l"
4287 * "ine\n"
4288 * "\n"
4289 * "Fourth l"
4290 * "ine\n"
4291 * "Fifth li"
4292 * "ne\n"
4294 * With arguments +sep+ and +limit+ given,
4295 * combines the two behaviors:
4297 * - Calls with the next line as determined by line separator +sep+.
4298 * - But returns no more bytes than are allowed by the limit.
4300 * For all forms above, trailing optional keyword arguments may be given;
4301 * see {Line Options}[#class-IO-label-Line+Options]:
4303 * f = File.new('t.txt')
4304 * f.each_line(chomp: true) {|line| p line }
4306 * Output:
4308 * "First line"
4309 * "Second line"
4310 * ""
4311 * "Fourth line"
4312 * "Fifth line"
4314 * Returns an Enumerator if no block is given.
4316 * IO#each is an alias for IO#each_line.
4320 static VALUE
4321 rb_io_each_line(int argc, VALUE *argv, VALUE io)
4323 VALUE str;
4324 struct getline_arg args;
4326 RETURN_ENUMERATOR(io, argc, argv);
4327 prepare_getline_args(argc, argv, &args, io);
4328 if (args.limit == 0)
4329 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4330 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4331 rb_yield(str);
4333 return io;
4337 * call-seq:
4338 * each_byte {|byte| ... } -> self
4339 * each_byte -> enumerator
4341 * Calls the given block with each byte (0..255) in the stream; returns +self+:
4343 * f = File.new('t.rus')
4344 * a = []
4345 * f.each_byte {|b| a << b }
4346 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4348 * Returns an Enumerator if no block is given.
4350 * Related: IO#each_char, IO#each_codepoint.
4354 static VALUE
4355 rb_io_each_byte(VALUE io)
4357 rb_io_t *fptr;
4359 RETURN_ENUMERATOR(io, 0, 0);
4360 GetOpenFile(io, fptr);
4362 do {
4363 while (fptr->rbuf.len > 0) {
4364 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4365 fptr->rbuf.len--;
4366 rb_yield(INT2FIX(*p & 0xff));
4367 rb_io_check_byte_readable(fptr);
4368 errno = 0;
4370 READ_CHECK(fptr);
4371 } while (io_fillbuf(fptr) >= 0);
4372 return io;
4375 static VALUE
4376 io_getc(rb_io_t *fptr, rb_encoding *enc)
4378 int r, n, cr = 0;
4379 VALUE str;
4381 if (NEED_READCONV(fptr)) {
4382 rb_encoding *read_enc = io_read_encoding(fptr);
4384 str = Qnil;
4385 SET_BINARY_MODE(fptr);
4386 make_readconv(fptr, 0);
4388 while (1) {
4389 if (fptr->cbuf.len) {
4390 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4391 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4392 read_enc);
4393 if (!MBCLEN_NEEDMORE_P(r))
4394 break;
4395 if (fptr->cbuf.len == fptr->cbuf.capa) {
4396 rb_raise(rb_eIOError, "too long character");
4400 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4401 if (fptr->cbuf.len == 0) {
4402 clear_readconv(fptr);
4403 return Qnil;
4405 /* return an unit of an incomplete character just before EOF */
4406 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4407 fptr->cbuf.off += 1;
4408 fptr->cbuf.len -= 1;
4409 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4410 ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
4411 return str;
4414 if (MBCLEN_INVALID_P(r)) {
4415 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4416 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4417 read_enc);
4418 io_shift_cbuf(fptr, r, &str);
4419 cr = ENC_CODERANGE_BROKEN;
4421 else {
4422 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4423 cr = ENC_CODERANGE_VALID;
4424 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4425 ISASCII(RSTRING_PTR(str)[0])) {
4426 cr = ENC_CODERANGE_7BIT;
4429 str = io_enc_str(str, fptr);
4430 ENC_CODERANGE_SET(str, cr);
4431 return str;
4434 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4435 if (io_fillbuf(fptr) < 0) {
4436 return Qnil;
4438 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4439 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4440 fptr->rbuf.off += 1;
4441 fptr->rbuf.len -= 1;
4442 cr = ENC_CODERANGE_7BIT;
4444 else {
4445 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4446 if (MBCLEN_CHARFOUND_P(r) &&
4447 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4448 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4449 fptr->rbuf.off += n;
4450 fptr->rbuf.len -= n;
4451 cr = ENC_CODERANGE_VALID;
4453 else if (MBCLEN_NEEDMORE_P(r)) {
4454 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4455 fptr->rbuf.len = 0;
4456 getc_needmore:
4457 if (io_fillbuf(fptr) != -1) {
4458 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4459 fptr->rbuf.off++;
4460 fptr->rbuf.len--;
4461 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4462 if (MBCLEN_NEEDMORE_P(r)) {
4463 goto getc_needmore;
4465 else if (MBCLEN_CHARFOUND_P(r)) {
4466 cr = ENC_CODERANGE_VALID;
4470 else {
4471 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4472 fptr->rbuf.off++;
4473 fptr->rbuf.len--;
4476 if (!cr) cr = ENC_CODERANGE_BROKEN;
4477 str = io_enc_str(str, fptr);
4478 ENC_CODERANGE_SET(str, cr);
4479 return str;
4483 * call-seq:
4484 * each_char {|c| ... } -> self
4485 * each_char -> enumerator
4487 * Calls the given block with each character in the stream; returns +self+:
4489 * f = File.new('t.rus')
4490 * a = []
4491 * f.each_char {|c| a << c.ord }
4492 * a # => [1090, 1077, 1089, 1090]
4494 * Returns an Enumerator if no block is given.
4496 * Related: IO#each_byte, IO#each_codepoint.
4500 static VALUE
4501 rb_io_each_char(VALUE io)
4503 rb_io_t *fptr;
4504 rb_encoding *enc;
4505 VALUE c;
4507 RETURN_ENUMERATOR(io, 0, 0);
4508 GetOpenFile(io, fptr);
4509 rb_io_check_char_readable(fptr);
4511 enc = io_input_encoding(fptr);
4512 READ_CHECK(fptr);
4513 while (!NIL_P(c = io_getc(fptr, enc))) {
4514 rb_yield(c);
4516 return io;
4520 * call-seq:
4521 * each_codepoint {|c| ... } -> self
4522 * each_codepoint -> enumerator
4524 * Calls the given block with each codepoint in the stream; returns +self+:
4526 * f = File.new('t.rus')
4527 * a = []
4528 * f.each_codepoint {|c| a << c }
4529 * a # => [1090, 1077, 1089, 1090]
4531 * Returns an Enumerator if no block is given.
4533 * Related: IO#each_byte, IO#each_char.
4537 static VALUE
4538 rb_io_each_codepoint(VALUE io)
4540 rb_io_t *fptr;
4541 rb_encoding *enc;
4542 unsigned int c;
4543 int r, n;
4545 RETURN_ENUMERATOR(io, 0, 0);
4546 GetOpenFile(io, fptr);
4547 rb_io_check_char_readable(fptr);
4549 READ_CHECK(fptr);
4550 if (NEED_READCONV(fptr)) {
4551 SET_BINARY_MODE(fptr);
4552 r = 1; /* no invalid char yet */
4553 for (;;) {
4554 make_readconv(fptr, 0);
4555 for (;;) {
4556 if (fptr->cbuf.len) {
4557 if (fptr->encs.enc)
4558 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4559 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4560 fptr->encs.enc);
4561 else
4562 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4563 if (!MBCLEN_NEEDMORE_P(r))
4564 break;
4565 if (fptr->cbuf.len == fptr->cbuf.capa) {
4566 rb_raise(rb_eIOError, "too long character");
4569 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4570 clear_readconv(fptr);
4571 if (!MBCLEN_CHARFOUND_P(r)) {
4572 enc = fptr->encs.enc;
4573 goto invalid;
4575 return io;
4578 if (MBCLEN_INVALID_P(r)) {
4579 enc = fptr->encs.enc;
4580 goto invalid;
4582 n = MBCLEN_CHARFOUND_LEN(r);
4583 if (fptr->encs.enc) {
4584 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4585 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4586 fptr->encs.enc);
4588 else {
4589 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4591 fptr->cbuf.off += n;
4592 fptr->cbuf.len -= n;
4593 rb_yield(UINT2NUM(c));
4594 rb_io_check_byte_readable(fptr);
4597 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4598 enc = io_input_encoding(fptr);
4599 while (io_fillbuf(fptr) >= 0) {
4600 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4601 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4602 if (MBCLEN_CHARFOUND_P(r) &&
4603 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4604 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4605 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4606 fptr->rbuf.off += n;
4607 fptr->rbuf.len -= n;
4608 rb_yield(UINT2NUM(c));
4610 else if (MBCLEN_INVALID_P(r)) {
4611 goto invalid;
4613 else if (MBCLEN_NEEDMORE_P(r)) {
4614 char cbuf[8], *p = cbuf;
4615 int more = MBCLEN_NEEDMORE_LEN(r);
4616 if (more > numberof(cbuf)) goto invalid;
4617 more += n = fptr->rbuf.len;
4618 if (more > numberof(cbuf)) goto invalid;
4619 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4620 (p += n, (more -= n) > 0)) {
4621 if (io_fillbuf(fptr) < 0) goto invalid;
4622 if ((n = fptr->rbuf.len) > more) n = more;
4624 r = rb_enc_precise_mbclen(cbuf, p, enc);
4625 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4626 c = rb_enc_codepoint(cbuf, p, enc);
4627 rb_yield(UINT2NUM(c));
4629 else {
4630 continue;
4632 rb_io_check_byte_readable(fptr);
4634 return io;
4636 invalid:
4637 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4638 UNREACHABLE_RETURN(Qundef);
4642 * call-seq:
4643 * getc -> character or nil
4645 * Reads and returns the next 1-character string from the stream;
4646 * returns +nil+ if already at end-of-file:
4648 * f = File.open('t.txt')
4649 * f.getc # => "F"
4650 * f = File.open('t.rus')
4651 * f.getc.ord # => 1090
4653 * Related: IO#readchar (may raise EOFError).
4657 static VALUE
4658 rb_io_getc(VALUE io)
4660 rb_io_t *fptr;
4661 rb_encoding *enc;
4663 GetOpenFile(io, fptr);
4664 rb_io_check_char_readable(fptr);
4666 enc = io_input_encoding(fptr);
4667 READ_CHECK(fptr);
4668 return io_getc(fptr, enc);
4672 * call-seq:
4673 * readchar -> string
4675 * Reads and returns the next 1-character string from the stream;
4676 * raises EOFError if already at end-of-file:
4678 * f = File.open('t.txt')
4679 * f.readchar # => "F"
4680 * f = File.open('t.rus')
4681 * f.readchar.ord # => 1090
4683 * Related: IO#getc (will not raise EOFError).
4687 static VALUE
4688 rb_io_readchar(VALUE io)
4690 VALUE c = rb_io_getc(io);
4692 if (NIL_P(c)) {
4693 rb_eof_error();
4695 return c;
4699 * call-seq:
4700 * getbyte -> integer or nil
4702 * Reads and returns the next byte (in range 0..255) from the stream;
4703 * returns +nil+ if already at end-of-file:
4705 * f = File.open('t.txt')
4706 * f.getbyte # => 70
4707 * f = File.open('t.rus')
4708 * f.getbyte # => 209
4710 * Related: IO#readbyte (may raise EOFError).
4714 VALUE
4715 rb_io_getbyte(VALUE io)
4717 rb_io_t *fptr;
4718 int c;
4720 GetOpenFile(io, fptr);
4721 rb_io_check_byte_readable(fptr);
4722 READ_CHECK(fptr);
4723 VALUE r_stdout = rb_ractor_stdout();
4724 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
4725 rb_io_t *ofp;
4726 GetOpenFile(r_stdout, ofp);
4727 if (ofp->mode & FMODE_TTY) {
4728 rb_io_flush(r_stdout);
4731 if (io_fillbuf(fptr) < 0) {
4732 return Qnil;
4734 fptr->rbuf.off++;
4735 fptr->rbuf.len--;
4736 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
4737 return INT2FIX(c & 0xff);
4741 * call-seq:
4742 * readbyte -> integer
4744 * Reads and returns the next byte (in range 0..255) from the stream;
4745 * raises EOFError if already at end-of-file:
4747 * f = File.open('t.txt')
4748 * f.readbyte # => 70
4749 * f = File.open('t.rus')
4750 * f.readbyte # => 209
4752 * Related: IO#getbyte (will not raise EOFError).
4756 static VALUE
4757 rb_io_readbyte(VALUE io)
4759 VALUE c = rb_io_getbyte(io);
4761 if (NIL_P(c)) {
4762 rb_eof_error();
4764 return c;
4768 * call-seq:
4769 * ungetbyte(integer) -> nil
4770 * ungetbyte(string) -> nil
4772 * Pushes back ("unshifts") the given data onto the stream's buffer,
4773 * placing the data so that it is next to be read; returns +nil+.
4775 * Note that:
4777 * - Calling the method hs no effect with unbuffered reads (such as IO#sysread).
4778 * - Calling #rewind on the stream discards the pushed-back data.
4780 * When argument +integer+ is given, uses only its low-order byte:
4782 * File.write('t.tmp', '012')
4783 * f = File.open('t.tmp')
4784 * f.ungetbyte(0x41) # => nil
4785 * f.read # => "A012"
4786 * f.rewind
4787 * f.ungetbyte(0x4243) # => nil
4788 * f.read # => "C012"
4790 * When argument +string+ is given, uses all bytes:
4792 * File.write('t.tmp', '012')
4793 * f = File.open('t.tmp')
4794 * f.ungetbyte('A') # => nil
4795 * f.read # => "A012"
4796 * f.rewind
4797 * f.ungetbyte('BCDE') # => nil
4798 * f.read # => "BCDE012"
4802 VALUE
4803 rb_io_ungetbyte(VALUE io, VALUE b)
4805 rb_io_t *fptr;
4807 GetOpenFile(io, fptr);
4808 rb_io_check_byte_readable(fptr);
4809 switch (TYPE(b)) {
4810 case T_NIL:
4811 return Qnil;
4812 case T_FIXNUM:
4813 case T_BIGNUM: ;
4814 VALUE v = rb_int_modulo(b, INT2FIX(256));
4815 unsigned char c = NUM2INT(v) & 0xFF;
4816 b = rb_str_new((const char *)&c, 1);
4817 break;
4818 default:
4819 SafeStringValue(b);
4821 io_ungetbyte(b, fptr);
4822 return Qnil;
4826 * call-seq:
4827 * ungetc(integer) -> nil
4828 * ungetc(string) -> nil
4830 * Pushes back ("unshifts") the given data onto the stream's buffer,
4831 * placing the data so that it is next to be read; returns +nil+.
4833 * Note that:
4835 * - Calling the method hs no effect with unbuffered reads (such as IO#sysread).
4836 * - Calling #rewind on the stream discards the pushed-back data.
4838 * When argument +integer+ is given, interprets the integer as a character:
4840 * File.write('t.tmp', '012')
4841 * f = File.open('t.tmp')
4842 * f.ungetc(0x41) # => nil
4843 * f.read # => "A012"
4844 * f.rewind
4845 * f.ungetc(0x0442) # => nil
4846 * f.getc.ord # => 1090
4848 * When argument +string+ is given, uses all characters:
4850 * File.write('t.tmp', '012')
4851 * f = File.open('t.tmp')
4852 * f.ungetc('A') # => nil
4853 * f.read # => "A012"
4854 * f.rewind
4855 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
4856 * f.getc.ord # => 1090
4857 * f.getc.ord # => 1077
4858 * f.getc.ord # => 1089
4859 * f.getc.ord # => 1090
4863 VALUE
4864 rb_io_ungetc(VALUE io, VALUE c)
4866 rb_io_t *fptr;
4867 long len;
4869 GetOpenFile(io, fptr);
4870 rb_io_check_char_readable(fptr);
4871 if (FIXNUM_P(c)) {
4872 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
4874 else if (RB_BIGNUM_TYPE_P(c)) {
4875 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
4877 else {
4878 SafeStringValue(c);
4880 if (NEED_READCONV(fptr)) {
4881 SET_BINARY_MODE(fptr);
4882 len = RSTRING_LEN(c);
4883 #if SIZEOF_LONG > SIZEOF_INT
4884 if (len > INT_MAX)
4885 rb_raise(rb_eIOError, "ungetc failed");
4886 #endif
4887 make_readconv(fptr, (int)len);
4888 if (fptr->cbuf.capa - fptr->cbuf.len < len)
4889 rb_raise(rb_eIOError, "ungetc failed");
4890 if (fptr->cbuf.off < len) {
4891 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
4892 fptr->cbuf.ptr+fptr->cbuf.off,
4893 char, fptr->cbuf.len);
4894 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
4896 fptr->cbuf.off -= (int)len;
4897 fptr->cbuf.len += (int)len;
4898 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
4900 else {
4901 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4902 io_ungetbyte(c, fptr);
4904 return Qnil;
4908 * call-seq:
4909 * isatty -> true or false
4911 * Returns +true+ if the stream is associated with a terminal device (tty),
4912 * +false+ otherwise:
4914 * File.new('t.txt').isatty #=> false
4915 * File.new('/dev/tty').isatty #=> true
4917 * IO#tty? is an alias for IO#isatty.
4921 static VALUE
4922 rb_io_isatty(VALUE io)
4924 rb_io_t *fptr;
4926 GetOpenFile(io, fptr);
4927 return RBOOL(isatty(fptr->fd) != 0);
4930 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
4932 * call-seq:
4933 * close_on_exec? -> true or false
4935 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
4937 * f = File.open('t.txt')
4938 * f.close_on_exec? # => true
4939 * f.close_on_exec = false
4940 * f.close_on_exec? # => false
4944 static VALUE
4945 rb_io_close_on_exec_p(VALUE io)
4947 rb_io_t *fptr;
4948 VALUE write_io;
4949 int fd, ret;
4951 write_io = GetWriteIO(io);
4952 if (io != write_io) {
4953 GetOpenFile(write_io, fptr);
4954 if (fptr && 0 <= (fd = fptr->fd)) {
4955 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
4956 if (!(ret & FD_CLOEXEC)) return Qfalse;
4960 GetOpenFile(io, fptr);
4961 if (fptr && 0 <= (fd = fptr->fd)) {
4962 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
4963 if (!(ret & FD_CLOEXEC)) return Qfalse;
4965 return Qtrue;
4967 #else
4968 #define rb_io_close_on_exec_p rb_f_notimplement
4969 #endif
4971 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
4973 * call-seq:
4974 * self.close_on_exec = bool -> true or false
4976 * Sets a close-on-exec flag.
4978 * f = open("/dev/null")
4979 * f.close_on_exec = true
4980 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
4981 * f.closed? #=> false
4983 * Ruby sets close-on-exec flags of all file descriptors by default
4984 * since Ruby 2.0.0.
4985 * So you don't need to set by yourself.
4986 * Also, unsetting a close-on-exec flag can cause file descriptor leak
4987 * if another thread use fork() and exec() (via system() method for example).
4988 * If you really needs file descriptor inheritance to child process,
4989 * use spawn()'s argument such as fd=>fd.
4992 static VALUE
4993 rb_io_set_close_on_exec(VALUE io, VALUE arg)
4995 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
4996 rb_io_t *fptr;
4997 VALUE write_io;
4998 int fd, ret;
5000 write_io = GetWriteIO(io);
5001 if (io != write_io) {
5002 GetOpenFile(write_io, fptr);
5003 if (fptr && 0 <= (fd = fptr->fd)) {
5004 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5005 if ((ret & FD_CLOEXEC) != flag) {
5006 ret = (ret & ~FD_CLOEXEC) | flag;
5007 ret = fcntl(fd, F_SETFD, ret);
5008 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5014 GetOpenFile(io, fptr);
5015 if (fptr && 0 <= (fd = fptr->fd)) {
5016 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5017 if ((ret & FD_CLOEXEC) != flag) {
5018 ret = (ret & ~FD_CLOEXEC) | flag;
5019 ret = fcntl(fd, F_SETFD, ret);
5020 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5023 return Qnil;
5025 #else
5026 #define rb_io_set_close_on_exec rb_f_notimplement
5027 #endif
5029 #define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
5030 #define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5032 static VALUE
5033 finish_writeconv(rb_io_t *fptr, int noalloc)
5035 unsigned char *ds, *dp, *de;
5036 rb_econv_result_t res;
5038 if (!fptr->wbuf.ptr) {
5039 unsigned char buf[1024];
5040 long r;
5042 res = econv_destination_buffer_full;
5043 while (res == econv_destination_buffer_full) {
5044 ds = dp = buf;
5045 de = buf + sizeof(buf);
5046 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5047 while (dp-ds) {
5048 retry:
5049 r = rb_write_internal(fptr, ds, dp-ds);
5050 if (r == dp-ds)
5051 break;
5052 if (0 <= r) {
5053 ds += r;
5055 if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) {
5056 if (fptr->fd < 0)
5057 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5058 goto retry;
5060 return noalloc ? Qtrue : INT2NUM(errno);
5062 if (res == econv_invalid_byte_sequence ||
5063 res == econv_incomplete_input ||
5064 res == econv_undefined_conversion) {
5065 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5069 return Qnil;
5072 res = econv_destination_buffer_full;
5073 while (res == econv_destination_buffer_full) {
5074 if (fptr->wbuf.len == fptr->wbuf.capa) {
5075 if (io_fflush(fptr) < 0)
5076 return noalloc ? Qtrue : INT2NUM(errno);
5079 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5080 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5081 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5082 fptr->wbuf.len += (int)(dp - ds);
5083 if (res == econv_invalid_byte_sequence ||
5084 res == econv_incomplete_input ||
5085 res == econv_undefined_conversion) {
5086 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5089 return Qnil;
5092 struct finish_writeconv_arg {
5093 rb_io_t *fptr;
5094 int noalloc;
5097 static VALUE
5098 finish_writeconv_sync(VALUE arg)
5100 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5101 return finish_writeconv(p->fptr, p->noalloc);
5104 static void*
5105 nogvl_close(void *ptr)
5107 int *fd = ptr;
5109 return (void*)(intptr_t)close(*fd);
5112 static int
5113 maygvl_close(int fd, int keepgvl)
5115 if (keepgvl)
5116 return close(fd);
5119 * close() may block for certain file types (NFS, SO_LINGER sockets,
5120 * inotify), so let other threads run.
5122 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
5125 static void*
5126 nogvl_fclose(void *ptr)
5128 FILE *file = ptr;
5130 return (void*)(intptr_t)fclose(file);
5133 static int
5134 maygvl_fclose(FILE *file, int keepgvl)
5136 if (keepgvl)
5137 return fclose(file);
5139 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
5142 static void free_io_buffer(rb_io_buffer_t *buf);
5143 static void clear_codeconv(rb_io_t *fptr);
5145 static void
5146 fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5147 struct list_head *busy)
5149 VALUE err = Qnil;
5150 int fd = fptr->fd;
5151 FILE *stdio_file = fptr->stdio_file;
5152 int mode = fptr->mode;
5154 if (fptr->writeconv) {
5155 if (fptr->write_lock && !noraise) {
5156 struct finish_writeconv_arg arg;
5157 arg.fptr = fptr;
5158 arg.noalloc = noraise;
5159 err = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5161 else {
5162 err = finish_writeconv(fptr, noraise);
5165 if (fptr->wbuf.len) {
5166 if (noraise) {
5167 io_flush_buffer_sync(fptr);
5169 else {
5170 if (io_fflush(fptr) < 0 && NIL_P(err))
5171 err = INT2NUM(errno);
5175 int done = 0;
5177 if (IS_PREP_STDIO(fptr) || fd <= 2) {
5178 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5179 done = 1;
5182 fptr->fd = -1;
5183 fptr->stdio_file = 0;
5184 fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
5186 // Ensure waiting_fd users do not hit EBADF.
5187 if (busy) {
5188 // Wait for them to exit before we call close().
5189 do rb_thread_schedule(); while (!list_empty(busy));
5192 // Disable for now.
5193 // if (!done && fd >= 0) {
5194 // VALUE scheduler = rb_fiber_scheduler_current();
5195 // if (scheduler != Qnil) {
5196 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5197 // if (result != Qundef) done = 1;
5198 // }
5199 // }
5201 if (!done && stdio_file) {
5202 // stdio_file is deallocated anyway even if fclose failed.
5203 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(err))
5204 if (!noraise) err = INT2NUM(errno);
5206 done = 1;
5209 if (!done && fd >= 0) {
5210 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5211 // We assumes it is closed.
5213 keepgvl |= !(mode & FMODE_WRITABLE);
5214 keepgvl |= noraise;
5215 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(err))
5216 if (!noraise) err = INT2NUM(errno);
5218 done = 1;
5221 if (!NIL_P(err) && !noraise) {
5222 if (RB_INTEGER_TYPE_P(err))
5223 rb_syserr_fail_path(NUM2INT(err), fptr->pathv);
5224 else
5225 rb_exc_raise(err);
5229 static void
5230 fptr_finalize(rb_io_t *fptr, int noraise)
5232 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5233 free_io_buffer(&fptr->rbuf);
5234 free_io_buffer(&fptr->wbuf);
5235 clear_codeconv(fptr);
5238 static void
5239 rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5241 if (fptr->finalize) {
5242 (*fptr->finalize)(fptr, noraise);
5244 else {
5245 fptr_finalize(fptr, noraise);
5249 static void
5250 free_io_buffer(rb_io_buffer_t *buf)
5252 if (buf->ptr) {
5253 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5254 buf->ptr = NULL;
5258 static void
5259 clear_readconv(rb_io_t *fptr)
5261 if (fptr->readconv) {
5262 rb_econv_close(fptr->readconv);
5263 fptr->readconv = NULL;
5265 free_io_buffer(&fptr->cbuf);
5268 static void
5269 clear_writeconv(rb_io_t *fptr)
5271 if (fptr->writeconv) {
5272 rb_econv_close(fptr->writeconv);
5273 fptr->writeconv = NULL;
5275 fptr->writeconv_initialized = 0;
5278 static void
5279 clear_codeconv(rb_io_t *fptr)
5281 clear_readconv(fptr);
5282 clear_writeconv(fptr);
5285 void
5286 rb_io_fptr_finalize_internal(void *ptr)
5288 rb_io_t *fptr = ptr;
5290 if (!ptr) return;
5291 fptr->pathv = Qnil;
5292 if (0 <= fptr->fd)
5293 rb_io_fptr_cleanup(fptr, TRUE);
5294 fptr->write_lock = 0;
5295 free_io_buffer(&fptr->rbuf);
5296 free_io_buffer(&fptr->wbuf);
5297 clear_codeconv(fptr);
5298 free(fptr);
5301 #undef rb_io_fptr_finalize
5303 rb_io_fptr_finalize(rb_io_t *fptr)
5305 if (!fptr) {
5306 return 0;
5308 else {
5309 rb_io_fptr_finalize_internal(fptr);
5310 return 1;
5313 #define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5315 RUBY_FUNC_EXPORTED size_t
5316 rb_io_memsize(const rb_io_t *fptr)
5318 size_t size = sizeof(rb_io_t);
5319 size += fptr->rbuf.capa;
5320 size += fptr->wbuf.capa;
5321 size += fptr->cbuf.capa;
5322 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5323 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5324 return size;
5327 #ifdef _WIN32
5328 /* keep GVL while closing to prevent crash on Windows */
5329 # define KEEPGVL TRUE
5330 #else
5331 # define KEEPGVL FALSE
5332 #endif
5334 int rb_notify_fd_close(int fd, struct list_head *);
5335 static rb_io_t *
5336 io_close_fptr(VALUE io)
5338 rb_io_t *fptr;
5339 VALUE write_io;
5340 rb_io_t *write_fptr;
5341 struct list_head busy;
5343 list_head_init(&busy);
5344 write_io = GetWriteIO(io);
5345 if (io != write_io) {
5346 write_fptr = RFILE(write_io)->fptr;
5347 if (write_fptr && 0 <= write_fptr->fd) {
5348 rb_io_fptr_cleanup(write_fptr, TRUE);
5352 fptr = RFILE(io)->fptr;
5353 if (!fptr) return 0;
5354 if (fptr->fd < 0) return 0;
5356 if (rb_notify_fd_close(fptr->fd, &busy)) {
5357 /* calls close(fptr->fd): */
5358 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5360 rb_io_fptr_cleanup(fptr, FALSE);
5361 return fptr;
5364 static void
5365 fptr_waitpid(rb_io_t *fptr, int nohang)
5367 int status;
5368 if (fptr->pid) {
5369 rb_last_status_clear();
5370 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5371 fptr->pid = 0;
5375 VALUE
5376 rb_io_close(VALUE io)
5378 rb_io_t *fptr = io_close_fptr(io);
5379 if (fptr) fptr_waitpid(fptr, 0);
5380 return Qnil;
5384 * call-seq:
5385 * close -> nil
5387 * Closes the stream, if it is open, after flushing any buffered writes
5388 * to the operating system; does nothing if the stream is already closed.
5389 * A stream is automatically closed when claimed by the garbage collector.
5391 * If the stream was opened by IO.popen, #close sets global variable <tt>$?</tt>.
5395 static VALUE
5396 rb_io_close_m(VALUE io)
5398 rb_io_t *fptr = rb_io_get_fptr(io);
5399 if (fptr->fd < 0) {
5400 return Qnil;
5402 rb_io_close(io);
5403 return Qnil;
5406 static VALUE
5407 io_call_close(VALUE io)
5409 rb_check_funcall(io, rb_intern("close"), 0, 0);
5410 return io;
5413 static VALUE
5414 ignore_closed_stream(VALUE io, VALUE exc)
5416 enum {mesg_len = sizeof(closed_stream)-1};
5417 VALUE mesg = rb_attr_get(exc, idMesg);
5418 if (!RB_TYPE_P(mesg, T_STRING) ||
5419 RSTRING_LEN(mesg) != mesg_len ||
5420 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5421 rb_exc_raise(exc);
5423 return io;
5426 static VALUE
5427 io_close(VALUE io)
5429 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5430 if (closed != Qundef && RTEST(closed)) return io;
5431 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5432 rb_eIOError, (VALUE)0);
5433 return io;
5437 * call-seq:
5438 * closed? -> true or false
5440 * Returns +true+ if the stream is closed for both reading and writing,
5441 * +false+ otherwise:
5443 * f = File.new('t.txt')
5444 * f.close # => nil
5445 * f.closed? # => true
5446 * f = IO.popen('/bin/sh','r+')
5447 * f.close_write # => nil
5448 * f.closed? # => false
5449 * f.close_read # => nil
5450 * f.closed? # => true
5455 static VALUE
5456 rb_io_closed(VALUE io)
5458 rb_io_t *fptr;
5459 VALUE write_io;
5460 rb_io_t *write_fptr;
5462 write_io = GetWriteIO(io);
5463 if (io != write_io) {
5464 write_fptr = RFILE(write_io)->fptr;
5465 if (write_fptr && 0 <= write_fptr->fd) {
5466 return Qfalse;
5470 fptr = rb_io_get_fptr(io);
5471 return RBOOL(0 > fptr->fd);
5475 * call-seq:
5476 * close_read -> nil
5478 * Closes the read end of a duplexed stream (i.e., one that is both readable
5479 * and writable, such as a pipe); does nothing if already closed:
5481 * f = IO.popen('/bin/sh','r+')
5482 * f.close_read
5483 * f.readlines # Raises IOError
5485 * Raises an exception if the stream is not duplexed.
5489 static VALUE
5490 rb_io_close_read(VALUE io)
5492 rb_io_t *fptr;
5493 VALUE write_io;
5495 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5496 if (fptr->fd < 0) return Qnil;
5497 if (is_socket(fptr->fd, fptr->pathv)) {
5498 #ifndef SHUT_RD
5499 # define SHUT_RD 0
5500 #endif
5501 if (shutdown(fptr->fd, SHUT_RD) < 0)
5502 rb_sys_fail_path(fptr->pathv);
5503 fptr->mode &= ~FMODE_READABLE;
5504 if (!(fptr->mode & FMODE_WRITABLE))
5505 return rb_io_close(io);
5506 return Qnil;
5509 write_io = GetWriteIO(io);
5510 if (io != write_io) {
5511 rb_io_t *wfptr;
5512 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5513 wfptr->pid = fptr->pid;
5514 fptr->pid = 0;
5515 RFILE(io)->fptr = wfptr;
5516 /* bind to write_io temporarily to get rid of memory/fd leak */
5517 fptr->tied_io_for_writing = 0;
5518 RFILE(write_io)->fptr = fptr;
5519 rb_io_fptr_cleanup(fptr, FALSE);
5520 /* should not finalize fptr because another thread may be reading it */
5521 return Qnil;
5524 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5525 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5527 return rb_io_close(io);
5531 * call-seq:
5532 * close_write -> nil
5534 * Closes the write end of a duplexed stream (i.e., one that is both readable
5535 * and writable, such as a pipe); does nothing if already closed:
5537 * f = IO.popen('/bin/sh', 'r+')
5538 * f.close_write
5539 * f.print 'nowhere' # Raises IOError.
5543 static VALUE
5544 rb_io_close_write(VALUE io)
5546 rb_io_t *fptr;
5547 VALUE write_io;
5549 write_io = GetWriteIO(io);
5550 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5551 if (fptr->fd < 0) return Qnil;
5552 if (is_socket(fptr->fd, fptr->pathv)) {
5553 #ifndef SHUT_WR
5554 # define SHUT_WR 1
5555 #endif
5556 if (shutdown(fptr->fd, SHUT_WR) < 0)
5557 rb_sys_fail_path(fptr->pathv);
5558 fptr->mode &= ~FMODE_WRITABLE;
5559 if (!(fptr->mode & FMODE_READABLE))
5560 return rb_io_close(write_io);
5561 return Qnil;
5564 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
5565 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
5568 if (io != write_io) {
5569 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5570 fptr->tied_io_for_writing = 0;
5572 rb_io_close(write_io);
5573 return Qnil;
5577 * call-seq:
5578 * sysseek(offset, whence = IO::SEEK_SET) -> integer
5580 * Behaves like IO#seek, except that it:
5582 * - Uses low-level system functions.
5583 * - Returns the new position.
5587 static VALUE
5588 rb_io_sysseek(int argc, VALUE *argv, VALUE io)
5590 VALUE offset, ptrname;
5591 int whence = SEEK_SET;
5592 rb_io_t *fptr;
5593 off_t pos;
5595 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
5596 whence = interpret_seek_whence(ptrname);
5598 pos = NUM2OFFT(offset);
5599 GetOpenFile(io, fptr);
5600 if ((fptr->mode & FMODE_READABLE) &&
5601 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5602 rb_raise(rb_eIOError, "sysseek for buffered IO");
5604 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
5605 rb_warn("sysseek for buffered IO");
5607 errno = 0;
5608 pos = lseek(fptr->fd, pos, whence);
5609 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
5611 return OFFT2NUM(pos);
5615 * call-seq:
5616 * syswrite(object) -> integer
5618 * Writes the given +object+ to self, which must be opened for writing (see Modes);
5619 * returns the number bytes written.
5620 * If +object+ is not a string is converted via method to_s:
5622 * f = File.new('t.tmp', 'w')
5623 * f.syswrite('foo') # => 3
5624 * f.syswrite(30) # => 2
5625 * f.syswrite(:foo) # => 3
5627 * This methods should not be used with other stream-writer methods.
5631 static VALUE
5632 rb_io_syswrite(VALUE io, VALUE str)
5634 VALUE tmp;
5635 rb_io_t *fptr;
5636 long n, len;
5637 const char *ptr;
5639 if (!RB_TYPE_P(str, T_STRING))
5640 str = rb_obj_as_string(str);
5642 io = GetWriteIO(io);
5643 GetOpenFile(io, fptr);
5644 rb_io_check_writable(fptr);
5646 if (fptr->wbuf.len) {
5647 rb_warn("syswrite for buffered IO");
5650 tmp = rb_str_tmp_frozen_acquire(str);
5651 RSTRING_GETMEM(tmp, ptr, len);
5652 n = rb_write_internal(fptr, ptr, len);
5653 if (n < 0) rb_sys_fail_path(fptr->pathv);
5654 rb_str_tmp_frozen_release(str, tmp);
5656 return LONG2FIX(n);
5660 * call-seq:
5661 * sysread(maxlen) -> string
5662 * sysread(maxlen, out_string) -> string
5664 * Behaves like IO#readpartial, except that it uses low-level system functions.
5666 * This method should not be used with other stream-reader methods.
5670 static VALUE
5671 rb_io_sysread(int argc, VALUE *argv, VALUE io)
5673 VALUE len, str;
5674 rb_io_t *fptr;
5675 long n, ilen;
5676 struct io_internal_read_struct iis;
5677 int shrinkable;
5679 rb_scan_args(argc, argv, "11", &len, &str);
5680 ilen = NUM2LONG(len);
5682 shrinkable = io_setstrbuf(&str, ilen);
5683 if (ilen == 0) return str;
5685 GetOpenFile(io, fptr);
5686 rb_io_check_byte_readable(fptr);
5688 if (READ_DATA_BUFFERED(fptr)) {
5689 rb_raise(rb_eIOError, "sysread for buffered IO");
5692 rb_io_check_closed(fptr);
5694 io_setstrbuf(&str, ilen);
5695 iis.th = rb_thread_current();
5696 iis.fptr = fptr;
5697 iis.nonblock = 0;
5698 iis.buf = RSTRING_PTR(str);
5699 iis.capa = ilen;
5700 n = read_internal_locktmp(str, &iis);
5702 if (n < 0) {
5703 rb_sys_fail_path(fptr->pathv);
5706 io_set_read_length(str, n, shrinkable);
5708 if (n == 0 && ilen > 0) {
5709 rb_eof_error();
5712 return str;
5715 #if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
5716 struct prdwr_internal_arg {
5717 int fd;
5718 void *buf;
5719 size_t count;
5720 off_t offset;
5722 #endif /* HAVE_PREAD || HAVE_PWRITE */
5724 #if defined(HAVE_PREAD)
5725 static VALUE
5726 internal_pread_func(void *arg)
5728 struct prdwr_internal_arg *p = arg;
5729 return (VALUE)pread(p->fd, p->buf, p->count, p->offset);
5732 static VALUE
5733 pread_internal_call(VALUE arg)
5735 struct prdwr_internal_arg *p = (struct prdwr_internal_arg *)arg;
5736 return rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
5740 * call-seq:
5741 * pread(maxlen, offset) -> string
5742 * pread(maxlen, offset, out_string) -> string
5744 * Behaves like IO#readpartial, except that it:
5746 * - Reads at the given +offset+ (in bytes).
5747 * - Disregards, and does not modify, the stream's position
5748 * (see {Position}[#class-IO-label-Position]).
5749 * - Bypasses any user space buffering in the stream.
5751 * Because this method does not disturb the stream's state
5752 * (its position, in particular), +pread+ allows multiple threads and processes
5753 * to use the same \IO object for reading at various offsets.
5755 * f = File.open('t.txt')
5756 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
5757 * f.pos # => 52
5758 * # Read 12 bytes at offset 0.
5759 * f.pread(12, 0) # => "First line\n"
5760 * # Read 9 bytes at offset 8.
5761 * f.pread(9, 8) # => "ne\nSecon"
5763 * Not available on some platforms.
5766 static VALUE
5767 rb_io_pread(int argc, VALUE *argv, VALUE io)
5769 VALUE len, offset, str;
5770 rb_io_t *fptr;
5771 ssize_t n;
5772 struct prdwr_internal_arg arg;
5773 int shrinkable;
5775 rb_scan_args(argc, argv, "21", &len, &offset, &str);
5776 arg.count = NUM2SIZET(len);
5777 arg.offset = NUM2OFFT(offset);
5779 shrinkable = io_setstrbuf(&str, (long)arg.count);
5780 if (arg.count == 0) return str;
5781 arg.buf = RSTRING_PTR(str);
5783 GetOpenFile(io, fptr);
5784 rb_io_check_byte_readable(fptr);
5786 arg.fd = fptr->fd;
5787 rb_io_check_closed(fptr);
5789 rb_str_locktmp(str);
5790 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
5792 if (n < 0) {
5793 rb_sys_fail_path(fptr->pathv);
5795 io_set_read_length(str, n, shrinkable);
5796 if (n == 0 && arg.count > 0) {
5797 rb_eof_error();
5800 return str;
5802 #else
5803 # define rb_io_pread rb_f_notimplement
5804 #endif /* HAVE_PREAD */
5806 #if defined(HAVE_PWRITE)
5807 static VALUE
5808 internal_pwrite_func(void *ptr)
5810 struct prdwr_internal_arg *arg = ptr;
5812 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
5816 * call-seq:
5817 * pwrite(object, offset) -> integer
5819 * Behaves like IO#write, except that it:
5821 * - Writes at the given +offset+ (in bytes).
5822 * - Disregards, and does not modify, the stream's position
5823 * (see {Position}[#class-IO-label-Position]).
5824 * - Bypasses any user space buffering in the stream.
5826 * Because this method does not disturb the stream's state
5827 * (its position, in particular), +pwrite+ allows multiple threads and processes
5828 * to use the same \IO object for writing at various offsets.
5830 * f = File.open('t.tmp', 'w+')
5831 * # Write 6 bytes at offset 3.
5832 * f.pwrite('ABCDEF', 3) # => 6
5833 * f.rewind
5834 * f.read # => "\u0000\u0000\u0000ABCDEF"
5836 * Not available on some platforms.
5839 static VALUE
5840 rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
5842 rb_io_t *fptr;
5843 ssize_t n;
5844 struct prdwr_internal_arg arg;
5845 VALUE tmp;
5847 if (!RB_TYPE_P(str, T_STRING))
5848 str = rb_obj_as_string(str);
5850 arg.offset = NUM2OFFT(offset);
5852 io = GetWriteIO(io);
5853 GetOpenFile(io, fptr);
5854 rb_io_check_writable(fptr);
5855 arg.fd = fptr->fd;
5857 tmp = rb_str_tmp_frozen_acquire(str);
5858 arg.buf = RSTRING_PTR(tmp);
5859 arg.count = (size_t)RSTRING_LEN(tmp);
5861 n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
5862 if (n < 0) rb_sys_fail_path(fptr->pathv);
5863 rb_str_tmp_frozen_release(str, tmp);
5865 return SSIZET2NUM(n);
5867 #else
5868 # define rb_io_pwrite rb_f_notimplement
5869 #endif /* HAVE_PWRITE */
5871 VALUE
5872 rb_io_binmode(VALUE io)
5874 rb_io_t *fptr;
5876 GetOpenFile(io, fptr);
5877 if (fptr->readconv)
5878 rb_econv_binmode(fptr->readconv);
5879 if (fptr->writeconv)
5880 rb_econv_binmode(fptr->writeconv);
5881 fptr->mode |= FMODE_BINMODE;
5882 fptr->mode &= ~FMODE_TEXTMODE;
5883 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
5884 #ifdef O_BINARY
5885 if (!fptr->readconv) {
5886 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
5888 else {
5889 setmode(fptr->fd, O_BINARY);
5891 #endif
5892 return io;
5895 static void
5896 io_ascii8bit_binmode(rb_io_t *fptr)
5898 if (fptr->readconv) {
5899 rb_econv_close(fptr->readconv);
5900 fptr->readconv = NULL;
5902 if (fptr->writeconv) {
5903 rb_econv_close(fptr->writeconv);
5904 fptr->writeconv = NULL;
5906 fptr->mode |= FMODE_BINMODE;
5907 fptr->mode &= ~FMODE_TEXTMODE;
5908 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
5910 fptr->encs.enc = rb_ascii8bit_encoding();
5911 fptr->encs.enc2 = NULL;
5912 fptr->encs.ecflags = 0;
5913 fptr->encs.ecopts = Qnil;
5914 clear_codeconv(fptr);
5917 VALUE
5918 rb_io_ascii8bit_binmode(VALUE io)
5920 rb_io_t *fptr;
5922 GetOpenFile(io, fptr);
5923 io_ascii8bit_binmode(fptr);
5925 return io;
5929 * call-seq:
5930 * binmode -> self
5932 * Sets the stream's data mode as binary
5933 * (see {Data Mode}[#class-IO-label-Data+Mode]).
5935 * A stream's data mode may not be changed from binary to text.
5939 static VALUE
5940 rb_io_binmode_m(VALUE io)
5942 VALUE write_io;
5944 rb_io_ascii8bit_binmode(io);
5946 write_io = GetWriteIO(io);
5947 if (write_io != io)
5948 rb_io_ascii8bit_binmode(write_io);
5949 return io;
5953 * call-seq:
5954 * binmode? -> true or false
5956 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
5957 * See {Data Mode}[#class-IO-label-Data+Mode].
5960 static VALUE
5961 rb_io_binmode_p(VALUE io)
5963 rb_io_t *fptr;
5964 GetOpenFile(io, fptr);
5965 return RBOOL(fptr->mode & FMODE_BINMODE);
5968 static const char*
5969 rb_io_fmode_modestr(int fmode)
5971 if (fmode & FMODE_APPEND) {
5972 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
5973 return MODE_BTMODE("a+", "ab+", "at+");
5975 return MODE_BTMODE("a", "ab", "at");
5977 switch (fmode & FMODE_READWRITE) {
5978 default:
5979 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
5980 case FMODE_READABLE:
5981 return MODE_BTMODE("r", "rb", "rt");
5982 case FMODE_WRITABLE:
5983 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
5984 case FMODE_READWRITE:
5985 if (fmode & FMODE_CREATE) {
5986 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
5988 return MODE_BTMODE("r+", "rb+", "rt+");
5992 static const char bom_prefix[] = "bom|";
5993 static const char utf_prefix[] = "utf-";
5994 enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
5995 enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
5997 static int
5998 io_encname_bom_p(const char *name, long len)
6000 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6004 rb_io_modestr_fmode(const char *modestr)
6006 int fmode = 0;
6007 const char *m = modestr, *p = NULL;
6009 switch (*m++) {
6010 case 'r':
6011 fmode |= FMODE_READABLE;
6012 break;
6013 case 'w':
6014 fmode |= FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE;
6015 break;
6016 case 'a':
6017 fmode |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
6018 break;
6019 default:
6020 goto error;
6023 while (*m) {
6024 switch (*m++) {
6025 case 'b':
6026 fmode |= FMODE_BINMODE;
6027 break;
6028 case 't':
6029 fmode |= FMODE_TEXTMODE;
6030 break;
6031 case '+':
6032 fmode |= FMODE_READWRITE;
6033 break;
6034 case 'x':
6035 if (modestr[0] != 'w')
6036 goto error;
6037 fmode |= FMODE_EXCL;
6038 break;
6039 default:
6040 goto error;
6041 case ':':
6042 p = strchr(m, ':');
6043 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6044 fmode |= FMODE_SETENC_BY_BOM;
6045 goto finished;
6049 finished:
6050 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6051 goto error;
6053 return fmode;
6055 error:
6056 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6057 UNREACHABLE_RETURN(Qundef);
6061 rb_io_oflags_fmode(int oflags)
6063 int fmode = 0;
6065 switch (oflags & O_ACCMODE) {
6066 case O_RDONLY:
6067 fmode = FMODE_READABLE;
6068 break;
6069 case O_WRONLY:
6070 fmode = FMODE_WRITABLE;
6071 break;
6072 case O_RDWR:
6073 fmode = FMODE_READWRITE;
6074 break;
6077 if (oflags & O_APPEND) {
6078 fmode |= FMODE_APPEND;
6080 if (oflags & O_TRUNC) {
6081 fmode |= FMODE_TRUNC;
6083 if (oflags & O_CREAT) {
6084 fmode |= FMODE_CREATE;
6086 if (oflags & O_EXCL) {
6087 fmode |= FMODE_EXCL;
6089 #ifdef O_BINARY
6090 if (oflags & O_BINARY) {
6091 fmode |= FMODE_BINMODE;
6093 #endif
6095 return fmode;
6098 static int
6099 rb_io_fmode_oflags(int fmode)
6101 int oflags = 0;
6103 switch (fmode & FMODE_READWRITE) {
6104 case FMODE_READABLE:
6105 oflags |= O_RDONLY;
6106 break;
6107 case FMODE_WRITABLE:
6108 oflags |= O_WRONLY;
6109 break;
6110 case FMODE_READWRITE:
6111 oflags |= O_RDWR;
6112 break;
6115 if (fmode & FMODE_APPEND) {
6116 oflags |= O_APPEND;
6118 if (fmode & FMODE_TRUNC) {
6119 oflags |= O_TRUNC;
6121 if (fmode & FMODE_CREATE) {
6122 oflags |= O_CREAT;
6124 if (fmode & FMODE_EXCL) {
6125 oflags |= O_EXCL;
6127 #ifdef O_BINARY
6128 if (fmode & FMODE_BINMODE) {
6129 oflags |= O_BINARY;
6131 #endif
6133 return oflags;
6137 rb_io_modestr_oflags(const char *modestr)
6139 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6142 static const char*
6143 rb_io_oflags_modestr(int oflags)
6145 #ifdef O_BINARY
6146 # define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6147 #else
6148 # define MODE_BINARY(a,b) (a)
6149 #endif
6150 int accmode;
6151 if (oflags & O_EXCL) {
6152 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6154 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6155 if (oflags & O_APPEND) {
6156 if (accmode == O_WRONLY) {
6157 return MODE_BINARY("a", "ab");
6159 if (accmode == O_RDWR) {
6160 return MODE_BINARY("a+", "ab+");
6163 switch (accmode) {
6164 default:
6165 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6166 case O_RDONLY:
6167 return MODE_BINARY("r", "rb");
6168 case O_WRONLY:
6169 return MODE_BINARY("w", "wb");
6170 case O_RDWR:
6171 if (oflags & O_TRUNC) {
6172 return MODE_BINARY("w+", "wb+");
6174 return MODE_BINARY("r+", "rb+");
6179 * Convert external/internal encodings to enc/enc2
6180 * NULL => use default encoding
6181 * Qnil => no encoding specified (internal only)
6183 static void
6184 rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6186 int default_ext = 0;
6188 if (ext == NULL) {
6189 ext = rb_default_external_encoding();
6190 default_ext = 1;
6192 if (ext == rb_ascii8bit_encoding()) {
6193 /* If external is ASCII-8BIT, no transcoding */
6194 intern = NULL;
6196 else if (intern == NULL) {
6197 intern = rb_default_internal_encoding();
6199 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6200 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6201 /* No internal encoding => use external + no transcoding */
6202 *enc = (default_ext && intern != ext) ? NULL : ext;
6203 *enc2 = NULL;
6205 else {
6206 *enc = intern;
6207 *enc2 = ext;
6211 static void
6212 unsupported_encoding(const char *name, rb_encoding *enc)
6214 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6217 static void
6218 parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6219 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6221 const char *p;
6222 char encname[ENCODING_MAXNAMELEN+1];
6223 int idx, idx2;
6224 int fmode = fmode_p ? *fmode_p : 0;
6225 rb_encoding *ext_enc, *int_enc;
6226 long len;
6228 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6230 p = strrchr(estr, ':');
6231 len = p ? (p++ - estr) : (long)strlen(estr);
6232 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6233 estr += bom_prefix_len;
6234 len -= bom_prefix_len;
6235 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6236 fmode |= FMODE_SETENC_BY_BOM;
6238 else {
6239 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6240 fmode &= ~FMODE_SETENC_BY_BOM;
6243 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6244 idx = -1;
6246 else {
6247 if (p) {
6248 memcpy(encname, estr, len);
6249 encname[len] = '\0';
6250 estr = encname;
6252 idx = rb_enc_find_index(estr);
6254 if (fmode_p) *fmode_p = fmode;
6256 if (idx >= 0)
6257 ext_enc = rb_enc_from_index(idx);
6258 else {
6259 if (idx != -2)
6260 unsupported_encoding(estr, estr_enc);
6261 ext_enc = NULL;
6264 int_enc = NULL;
6265 if (p) {
6266 if (*p == '-' && *(p+1) == '\0') {
6267 /* Special case - "-" => no transcoding */
6268 int_enc = (rb_encoding *)Qnil;
6270 else {
6271 idx2 = rb_enc_find_index(p);
6272 if (idx2 < 0)
6273 unsupported_encoding(p, estr_enc);
6274 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6275 int_enc = (rb_encoding *)Qnil;
6277 else
6278 int_enc = rb_enc_from_index(idx2);
6282 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6286 rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6288 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6289 int extracted = 0;
6290 rb_encoding *extencoding = NULL;
6291 rb_encoding *intencoding = NULL;
6293 if (!NIL_P(opt)) {
6294 VALUE v;
6295 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6296 if (v != Qnil) encoding = v;
6297 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6298 if (v != Qnil) extenc = v;
6299 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6300 if (v != Qundef) intenc = v;
6302 if ((extenc != Qundef || intenc != Qundef) && !NIL_P(encoding)) {
6303 if (!NIL_P(ruby_verbose)) {
6304 int idx = rb_to_encoding_index(encoding);
6305 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6306 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6307 encoding, extenc == Qundef ? "internal" : "external");
6309 encoding = Qnil;
6311 if (extenc != Qundef && !NIL_P(extenc)) {
6312 extencoding = rb_to_encoding(extenc);
6314 if (intenc != Qundef) {
6315 if (NIL_P(intenc)) {
6316 /* internal_encoding: nil => no transcoding */
6317 intencoding = (rb_encoding *)Qnil;
6319 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6320 char *p = StringValueCStr(tmp);
6322 if (*p == '-' && *(p+1) == '\0') {
6323 /* Special case - "-" => no transcoding */
6324 intencoding = (rb_encoding *)Qnil;
6326 else {
6327 intencoding = rb_to_encoding(intenc);
6330 else {
6331 intencoding = rb_to_encoding(intenc);
6333 if (extencoding == intencoding) {
6334 intencoding = (rb_encoding *)Qnil;
6337 if (!NIL_P(encoding)) {
6338 extracted = 1;
6339 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6340 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6341 enc_p, enc2_p, fmode_p);
6343 else {
6344 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6347 else if (extenc != Qundef || intenc != Qundef) {
6348 extracted = 1;
6349 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6351 return extracted;
6354 typedef struct rb_io_enc_t convconfig_t;
6356 static void
6357 validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6359 int fmode = *fmode_p;
6361 if ((fmode & FMODE_READABLE) &&
6362 !enc2 &&
6363 !(fmode & FMODE_BINMODE) &&
6364 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6365 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6367 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6368 rb_raise(rb_eArgError, "newline decorator with binary mode");
6370 if (!(fmode & FMODE_BINMODE) &&
6371 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6372 fmode |= FMODE_TEXTMODE;
6373 *fmode_p = fmode;
6375 #if !DEFAULT_TEXTMODE
6376 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6377 fmode &= ~FMODE_TEXTMODE;
6378 *fmode_p = fmode;
6380 #endif
6383 static void
6384 extract_binmode(VALUE opthash, int *fmode)
6386 if (!NIL_P(opthash)) {
6387 VALUE v;
6388 v = rb_hash_aref(opthash, sym_textmode);
6389 if (!NIL_P(v)) {
6390 if (*fmode & FMODE_TEXTMODE)
6391 rb_raise(rb_eArgError, "textmode specified twice");
6392 if (*fmode & FMODE_BINMODE)
6393 rb_raise(rb_eArgError, "both textmode and binmode specified");
6394 if (RTEST(v))
6395 *fmode |= FMODE_TEXTMODE;
6397 v = rb_hash_aref(opthash, sym_binmode);
6398 if (!NIL_P(v)) {
6399 if (*fmode & FMODE_BINMODE)
6400 rb_raise(rb_eArgError, "binmode specified twice");
6401 if (*fmode & FMODE_TEXTMODE)
6402 rb_raise(rb_eArgError, "both textmode and binmode specified");
6403 if (RTEST(v))
6404 *fmode |= FMODE_BINMODE;
6407 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6408 rb_raise(rb_eArgError, "both textmode and binmode specified");
6412 void
6413 rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6414 int *oflags_p, int *fmode_p, convconfig_t *convconfig_p)
6416 VALUE vmode;
6417 int oflags, fmode;
6418 rb_encoding *enc, *enc2;
6419 int ecflags;
6420 VALUE ecopts;
6421 int has_enc = 0, has_vmode = 0;
6422 VALUE intmode;
6424 vmode = *vmode_p;
6426 /* Set to defaults */
6427 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6429 vmode_handle:
6430 if (NIL_P(vmode)) {
6431 fmode = FMODE_READABLE;
6432 oflags = O_RDONLY;
6434 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6435 vmode = intmode;
6436 oflags = NUM2INT(intmode);
6437 fmode = rb_io_oflags_fmode(oflags);
6439 else {
6440 const char *p;
6442 SafeStringValue(vmode);
6443 p = StringValueCStr(vmode);
6444 fmode = rb_io_modestr_fmode(p);
6445 oflags = rb_io_fmode_oflags(fmode);
6446 p = strchr(p, ':');
6447 if (p) {
6448 has_enc = 1;
6449 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6451 else {
6452 rb_encoding *e;
6454 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6455 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6459 if (NIL_P(opthash)) {
6460 ecflags = (fmode & FMODE_READABLE) ?
6461 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6462 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6463 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6464 ecflags |= (fmode & FMODE_WRITABLE) ?
6465 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6466 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6467 #endif
6468 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6469 ecopts = Qnil;
6470 if (fmode & FMODE_BINMODE) {
6471 #ifdef O_BINARY
6472 oflags |= O_BINARY;
6473 #endif
6474 if (!has_enc)
6475 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6477 #if DEFAULT_TEXTMODE
6478 else if (NIL_P(vmode)) {
6479 fmode |= DEFAULT_TEXTMODE;
6481 #endif
6483 else {
6484 VALUE v;
6485 if (!has_vmode) {
6486 v = rb_hash_aref(opthash, sym_mode);
6487 if (!NIL_P(v)) {
6488 if (!NIL_P(vmode)) {
6489 rb_raise(rb_eArgError, "mode specified twice");
6491 has_vmode = 1;
6492 vmode = v;
6493 goto vmode_handle;
6496 v = rb_hash_aref(opthash, sym_flags);
6497 if (!NIL_P(v)) {
6498 v = rb_to_int(v);
6499 oflags |= NUM2INT(v);
6500 vmode = INT2NUM(oflags);
6501 fmode = rb_io_oflags_fmode(oflags);
6503 extract_binmode(opthash, &fmode);
6504 if (fmode & FMODE_BINMODE) {
6505 #ifdef O_BINARY
6506 oflags |= O_BINARY;
6507 #endif
6508 if (!has_enc)
6509 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6511 #if DEFAULT_TEXTMODE
6512 else if (NIL_P(vmode)) {
6513 fmode |= DEFAULT_TEXTMODE;
6515 #endif
6516 v = rb_hash_aref(opthash, sym_perm);
6517 if (!NIL_P(v)) {
6518 if (vperm_p) {
6519 if (!NIL_P(*vperm_p)) {
6520 rb_raise(rb_eArgError, "perm specified twice");
6522 *vperm_p = v;
6524 else {
6525 /* perm no use, just ignore */
6528 ecflags = (fmode & FMODE_READABLE) ?
6529 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6530 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6531 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6532 ecflags |= (fmode & FMODE_WRITABLE) ?
6533 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6534 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6535 #endif
6537 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6538 if (has_enc) {
6539 rb_raise(rb_eArgError, "encoding specified twice");
6542 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6543 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
6546 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6548 *vmode_p = vmode;
6550 *oflags_p = oflags;
6551 *fmode_p = fmode;
6552 convconfig_p->enc = enc;
6553 convconfig_p->enc2 = enc2;
6554 convconfig_p->ecflags = ecflags;
6555 convconfig_p->ecopts = ecopts;
6558 struct sysopen_struct {
6559 VALUE fname;
6560 int oflags;
6561 mode_t perm;
6564 static void *
6565 sysopen_func(void *ptr)
6567 const struct sysopen_struct *data = ptr;
6568 const char *fname = RSTRING_PTR(data->fname);
6569 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
6572 static inline int
6573 rb_sysopen_internal(struct sysopen_struct *data)
6575 int fd;
6576 fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
6577 if (0 <= fd)
6578 rb_update_max_fd(fd);
6579 return fd;
6582 static int
6583 rb_sysopen(VALUE fname, int oflags, mode_t perm)
6585 int fd;
6586 struct sysopen_struct data;
6588 data.fname = rb_str_encode_ospath(fname);
6589 StringValueCStr(data.fname);
6590 data.oflags = oflags;
6591 data.perm = perm;
6593 fd = rb_sysopen_internal(&data);
6594 if (fd < 0) {
6595 int e = errno;
6596 if (rb_gc_for_fd(e)) {
6597 fd = rb_sysopen_internal(&data);
6599 if (fd < 0) {
6600 rb_syserr_fail_path(e, fname);
6603 return fd;
6606 FILE *
6607 rb_fdopen(int fd, const char *modestr)
6609 FILE *file;
6611 #if defined(__sun)
6612 errno = 0;
6613 #endif
6614 file = fdopen(fd, modestr);
6615 if (!file) {
6616 int e = errno;
6617 #if defined(__sun)
6618 if (e == 0) {
6619 rb_gc();
6620 errno = 0;
6621 file = fdopen(fd, modestr);
6623 else
6624 #endif
6625 if (rb_gc_for_fd(e)) {
6626 file = fdopen(fd, modestr);
6628 if (!file) {
6629 #ifdef _WIN32
6630 if (e == 0) e = EINVAL;
6631 #elif defined(__sun)
6632 if (e == 0) e = EMFILE;
6633 #endif
6634 rb_syserr_fail(e, 0);
6638 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
6639 #ifdef USE_SETVBUF
6640 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
6641 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
6642 #endif
6643 return file;
6646 static int
6647 io_check_tty(rb_io_t *fptr)
6649 int t = isatty(fptr->fd);
6650 if (t)
6651 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
6652 return t;
6655 static VALUE rb_io_internal_encoding(VALUE);
6656 static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
6658 static int
6659 io_strip_bom(VALUE io)
6661 VALUE b1, b2, b3, b4;
6662 rb_io_t *fptr;
6664 GetOpenFile(io, fptr);
6665 if (!(fptr->mode & FMODE_READABLE)) return 0;
6666 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
6667 switch (b1) {
6668 case INT2FIX(0xEF):
6669 if (NIL_P(b2 = rb_io_getbyte(io))) break;
6670 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
6671 if (b3 == INT2FIX(0xBF)) {
6672 return rb_utf8_encindex();
6674 rb_io_ungetbyte(io, b3);
6676 rb_io_ungetbyte(io, b2);
6677 break;
6679 case INT2FIX(0xFE):
6680 if (NIL_P(b2 = rb_io_getbyte(io))) break;
6681 if (b2 == INT2FIX(0xFF)) {
6682 return ENCINDEX_UTF_16BE;
6684 rb_io_ungetbyte(io, b2);
6685 break;
6687 case INT2FIX(0xFF):
6688 if (NIL_P(b2 = rb_io_getbyte(io))) break;
6689 if (b2 == INT2FIX(0xFE)) {
6690 b3 = rb_io_getbyte(io);
6691 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
6692 if (b4 == INT2FIX(0)) {
6693 return ENCINDEX_UTF_32LE;
6695 rb_io_ungetbyte(io, b4);
6697 rb_io_ungetbyte(io, b3);
6698 return ENCINDEX_UTF_16LE;
6700 rb_io_ungetbyte(io, b2);
6701 break;
6703 case INT2FIX(0):
6704 if (NIL_P(b2 = rb_io_getbyte(io))) break;
6705 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
6706 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
6707 if (b4 == INT2FIX(0xFF)) {
6708 return ENCINDEX_UTF_32BE;
6710 rb_io_ungetbyte(io, b4);
6712 rb_io_ungetbyte(io, b3);
6714 rb_io_ungetbyte(io, b2);
6715 break;
6717 rb_io_ungetbyte(io, b1);
6718 return 0;
6721 static rb_encoding *
6722 io_set_encoding_by_bom(VALUE io)
6724 int idx = io_strip_bom(io);
6725 rb_io_t *fptr;
6726 rb_encoding *extenc = NULL;
6728 GetOpenFile(io, fptr);
6729 if (idx) {
6730 extenc = rb_enc_from_index(idx);
6731 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
6732 rb_io_internal_encoding(io), Qnil);
6734 else {
6735 fptr->encs.enc2 = NULL;
6737 return extenc;
6740 static VALUE
6741 rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
6742 const convconfig_t *convconfig, mode_t perm)
6744 VALUE pathv;
6745 rb_io_t *fptr;
6746 convconfig_t cc;
6747 if (!convconfig) {
6748 /* Set to default encodings */
6749 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
6750 cc.ecflags = 0;
6751 cc.ecopts = Qnil;
6752 convconfig = &cc;
6754 validate_enc_binmode(&fmode, convconfig->ecflags,
6755 convconfig->enc, convconfig->enc2);
6757 MakeOpenFile(io, fptr);
6758 fptr->mode = fmode;
6759 fptr->encs = *convconfig;
6760 pathv = rb_str_new_frozen(filename);
6761 #ifdef O_TMPFILE
6762 if (!(oflags & O_TMPFILE)) {
6763 fptr->pathv = pathv;
6765 #else
6766 fptr->pathv = pathv;
6767 #endif
6768 fptr->fd = rb_sysopen(pathv, oflags, perm);
6769 io_check_tty(fptr);
6770 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
6772 return io;
6775 static VALUE
6776 rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
6778 int fmode = rb_io_modestr_fmode(modestr);
6779 const char *p = strchr(modestr, ':');
6780 convconfig_t convconfig;
6782 if (p) {
6783 parse_mode_enc(p+1, rb_usascii_encoding(),
6784 &convconfig.enc, &convconfig.enc2, &fmode);
6785 convconfig.ecflags = 0;
6786 convconfig.ecopts = Qnil;
6788 else {
6789 rb_encoding *e;
6790 /* Set to default encodings */
6792 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6793 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
6794 convconfig.ecflags = 0;
6795 convconfig.ecopts = Qnil;
6798 return rb_file_open_generic(io, filename,
6799 rb_io_fmode_oflags(fmode),
6800 fmode,
6801 &convconfig,
6802 0666);
6805 VALUE
6806 rb_file_open_str(VALUE fname, const char *modestr)
6808 FilePathValue(fname);
6809 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
6812 VALUE
6813 rb_file_open(const char *fname, const char *modestr)
6815 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
6818 #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
6819 static struct pipe_list {
6820 rb_io_t *fptr;
6821 struct pipe_list *next;
6822 } *pipe_list;
6824 static void
6825 pipe_add_fptr(rb_io_t *fptr)
6827 struct pipe_list *list;
6829 list = ALLOC(struct pipe_list);
6830 list->fptr = fptr;
6831 list->next = pipe_list;
6832 pipe_list = list;
6835 static void
6836 pipe_del_fptr(rb_io_t *fptr)
6838 struct pipe_list **prev = &pipe_list;
6839 struct pipe_list *tmp;
6841 while ((tmp = *prev) != 0) {
6842 if (tmp->fptr == fptr) {
6843 *prev = tmp->next;
6844 free(tmp);
6845 return;
6847 prev = &tmp->next;
6851 #if defined (_WIN32) || defined(__CYGWIN__)
6852 static void
6853 pipe_atexit(void)
6855 struct pipe_list *list = pipe_list;
6856 struct pipe_list *tmp;
6858 while (list) {
6859 tmp = list->next;
6860 rb_io_fptr_finalize(list->fptr);
6861 list = tmp;
6864 #endif
6866 static void
6867 pipe_finalize(rb_io_t *fptr, int noraise)
6869 #if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
6870 int status = 0;
6871 if (fptr->stdio_file) {
6872 status = pclose(fptr->stdio_file);
6874 fptr->fd = -1;
6875 fptr->stdio_file = 0;
6876 rb_last_status_set(status, fptr->pid);
6877 #else
6878 fptr_finalize(fptr, noraise);
6879 #endif
6880 pipe_del_fptr(fptr);
6882 #endif
6884 static void
6885 fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
6887 #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
6888 void (*const old_finalize)(struct rb_io_t*,int) = fptr->finalize;
6890 if (old_finalize == orig->finalize) return;
6891 #endif
6893 fptr->finalize = orig->finalize;
6895 #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
6896 if (old_finalize != pipe_finalize) {
6897 struct pipe_list *list;
6898 for (list = pipe_list; list; list = list->next) {
6899 if (list->fptr == fptr) break;
6901 if (!list) pipe_add_fptr(fptr);
6903 else {
6904 pipe_del_fptr(fptr);
6906 #endif
6909 void
6910 rb_io_synchronized(rb_io_t *fptr)
6912 rb_io_check_initialized(fptr);
6913 fptr->mode |= FMODE_SYNC;
6916 void
6917 rb_io_unbuffered(rb_io_t *fptr)
6919 rb_io_synchronized(fptr);
6923 rb_pipe(int *pipes)
6925 int ret;
6926 ret = rb_cloexec_pipe(pipes);
6927 if (ret < 0) {
6928 if (rb_gc_for_fd(errno)) {
6929 ret = rb_cloexec_pipe(pipes);
6932 if (ret == 0) {
6933 rb_update_max_fd(pipes[0]);
6934 rb_update_max_fd(pipes[1]);
6936 return ret;
6939 #ifdef _WIN32
6940 #define HAVE_SPAWNV 1
6941 #define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
6942 #define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
6943 #endif
6945 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
6946 struct popen_arg {
6947 VALUE execarg_obj;
6948 struct rb_execarg *eargp;
6949 int modef;
6950 int pair[2];
6951 int write_pair[2];
6953 #endif
6955 #ifdef HAVE_WORKING_FORK
6956 # ifndef __EMSCRIPTEN__
6957 static void
6958 popen_redirect(struct popen_arg *p)
6960 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
6961 close(p->write_pair[1]);
6962 if (p->write_pair[0] != 0) {
6963 dup2(p->write_pair[0], 0);
6964 close(p->write_pair[0]);
6966 close(p->pair[0]);
6967 if (p->pair[1] != 1) {
6968 dup2(p->pair[1], 1);
6969 close(p->pair[1]);
6972 else if (p->modef & FMODE_READABLE) {
6973 close(p->pair[0]);
6974 if (p->pair[1] != 1) {
6975 dup2(p->pair[1], 1);
6976 close(p->pair[1]);
6979 else {
6980 close(p->pair[1]);
6981 if (p->pair[0] != 0) {
6982 dup2(p->pair[0], 0);
6983 close(p->pair[0]);
6987 # endif
6989 #if defined(__linux__)
6990 /* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
6991 * Since /proc may not be available, linux_get_maxfd is just a hint.
6992 * This function, linux_get_maxfd, must be async-signal-safe.
6993 * I.e. opendir() is not usable.
6995 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
6996 * However they are easy to re-implement in async-signal-safe manner.
6997 * (Also note that there is missing/memcmp.c.)
6999 static int
7000 linux_get_maxfd(void)
7002 int fd;
7003 char buf[4096], *p, *np, *e;
7004 ssize_t ss;
7005 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7006 if (fd < 0) return fd;
7007 ss = read(fd, buf, sizeof(buf));
7008 if (ss < 0) goto err;
7009 p = buf;
7010 e = buf + ss;
7011 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7012 (np = memchr(p, '\n', e-p)) != NULL) {
7013 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7014 int fdsize;
7015 p += sizeof("FDSize:")-1;
7016 *np = '\0';
7017 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7018 close(fd);
7019 return fdsize;
7021 p = np+1;
7023 /* fall through */
7025 err:
7026 close(fd);
7027 return (int)ss;
7029 #endif
7031 /* This function should be async-signal-safe. */
7032 void
7033 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7035 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7036 int fd, ret;
7037 int max = (int)max_file_descriptor;
7038 # ifdef F_MAXFD
7039 /* F_MAXFD is available since NetBSD 2.0. */
7040 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7041 if (ret != -1)
7042 maxhint = max = ret;
7043 # elif defined(__linux__)
7044 ret = linux_get_maxfd();
7045 if (maxhint < ret)
7046 maxhint = ret;
7047 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7048 # endif
7049 if (max < maxhint)
7050 max = maxhint;
7051 for (fd = lowfd; fd <= max; fd++) {
7052 if (!NIL_P(noclose_fds) &&
7053 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7054 continue;
7055 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7056 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7057 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7059 # define CONTIGUOUS_CLOSED_FDS 20
7060 if (ret != -1) {
7061 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7062 max = fd + CONTIGUOUS_CLOSED_FDS;
7065 #endif
7068 # ifndef __EMSCRIPTEN__
7069 static int
7070 popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7072 struct popen_arg *p = (struct popen_arg*)pp;
7074 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7076 # endif
7077 #endif
7079 #if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7080 static VALUE
7081 rb_execarg_fixup_v(VALUE execarg_obj)
7083 rb_execarg_parent_start(execarg_obj);
7084 return Qnil;
7086 #else
7087 char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7088 #endif
7090 #ifndef __EMSCRIPTEN__
7091 static VALUE
7092 pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7093 const convconfig_t *convconfig)
7095 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7096 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7097 rb_pid_t pid = 0;
7098 rb_io_t *fptr;
7099 VALUE port;
7100 rb_io_t *write_fptr;
7101 VALUE write_port;
7102 #if defined(HAVE_WORKING_FORK)
7103 int status;
7104 char errmsg[80] = { '\0' };
7105 #endif
7106 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7107 int state;
7108 struct popen_arg arg;
7109 #endif
7110 int e = 0;
7111 #if defined(HAVE_SPAWNV)
7112 # if defined(HAVE_SPAWNVE)
7113 # define DO_SPAWN(cmd, args, envp) ((args) ? \
7114 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7115 spawne(P_NOWAIT, (cmd), (envp)))
7116 # else
7117 # define DO_SPAWN(cmd, args, envp) ((args) ? \
7118 spawnv(P_NOWAIT, (cmd), (args)) : \
7119 spawn(P_NOWAIT, (cmd)))
7120 # endif
7121 # if !defined(HAVE_WORKING_FORK)
7122 char **args = NULL;
7123 # if defined(HAVE_SPAWNVE)
7124 char **envp = NULL;
7125 # endif
7126 # endif
7127 #endif
7128 #if !defined(HAVE_WORKING_FORK)
7129 struct rb_execarg sarg, *sargp = &sarg;
7130 #endif
7131 FILE *fp = 0;
7132 int fd = -1;
7133 int write_fd = -1;
7134 #if !defined(HAVE_WORKING_FORK)
7135 const char *cmd = 0;
7137 if (prog)
7138 cmd = StringValueCStr(prog);
7139 #endif
7141 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7142 arg.execarg_obj = execarg_obj;
7143 arg.eargp = eargp;
7144 arg.modef = fmode;
7145 arg.pair[0] = arg.pair[1] = -1;
7146 arg.write_pair[0] = arg.write_pair[1] = -1;
7147 # if !defined(HAVE_WORKING_FORK)
7148 if (eargp && !eargp->use_shell) {
7149 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7151 # endif
7152 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7153 case FMODE_READABLE|FMODE_WRITABLE:
7154 if (rb_pipe(arg.write_pair) < 0)
7155 rb_sys_fail_str(prog);
7156 if (rb_pipe(arg.pair) < 0) {
7157 e = errno;
7158 close(arg.write_pair[0]);
7159 close(arg.write_pair[1]);
7160 rb_syserr_fail_str(e, prog);
7162 if (eargp) {
7163 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7164 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7166 break;
7167 case FMODE_READABLE:
7168 if (rb_pipe(arg.pair) < 0)
7169 rb_sys_fail_str(prog);
7170 if (eargp)
7171 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7172 break;
7173 case FMODE_WRITABLE:
7174 if (rb_pipe(arg.pair) < 0)
7175 rb_sys_fail_str(prog);
7176 if (eargp)
7177 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7178 break;
7179 default:
7180 rb_sys_fail_str(prog);
7182 if (!NIL_P(execarg_obj)) {
7183 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7184 if (state) {
7185 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7186 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7187 if (0 <= arg.pair[0]) close(arg.pair[0]);
7188 if (0 <= arg.pair[1]) close(arg.pair[1]);
7189 rb_execarg_parent_end(execarg_obj);
7190 rb_jump_tag(state);
7193 # if defined(HAVE_WORKING_FORK)
7194 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7195 # else
7196 rb_execarg_run_options(eargp, sargp, NULL, 0);
7197 # if defined(HAVE_SPAWNVE)
7198 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7199 # endif
7200 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7201 /* exec failed */
7202 switch (e = errno) {
7203 case EAGAIN:
7204 # if EWOULDBLOCK != EAGAIN
7205 case EWOULDBLOCK:
7206 # endif
7207 rb_thread_sleep(1);
7208 continue;
7210 break;
7212 if (eargp)
7213 rb_execarg_run_options(sargp, NULL, NULL, 0);
7214 # endif
7215 rb_execarg_parent_end(execarg_obj);
7217 else {
7218 # if defined(HAVE_WORKING_FORK)
7219 pid = rb_call_proc__fork();
7220 if (pid == 0) { /* child */
7221 popen_redirect(&arg);
7222 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7223 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7224 return Qnil;
7226 # else
7227 rb_notimplement();
7228 # endif
7231 /* parent */
7232 if (pid < 0) {
7233 # if defined(HAVE_WORKING_FORK)
7234 e = errno;
7235 # endif
7236 close(arg.pair[0]);
7237 close(arg.pair[1]);
7238 if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) {
7239 close(arg.write_pair[0]);
7240 close(arg.write_pair[1]);
7242 # if defined(HAVE_WORKING_FORK)
7243 if (errmsg[0])
7244 rb_syserr_fail(e, errmsg);
7245 # endif
7246 rb_syserr_fail_str(e, prog);
7248 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7249 close(arg.pair[1]);
7250 fd = arg.pair[0];
7251 close(arg.write_pair[0]);
7252 write_fd = arg.write_pair[1];
7254 else if (fmode & FMODE_READABLE) {
7255 close(arg.pair[1]);
7256 fd = arg.pair[0];
7258 else {
7259 close(arg.pair[0]);
7260 fd = arg.pair[1];
7262 #else
7263 cmd = rb_execarg_commandline(eargp, &prog);
7264 if (!NIL_P(execarg_obj)) {
7265 rb_execarg_parent_start(execarg_obj);
7266 rb_execarg_run_options(eargp, sargp, NULL, 0);
7268 fp = popen(cmd, modestr);
7269 e = errno;
7270 if (eargp) {
7271 rb_execarg_parent_end(execarg_obj);
7272 rb_execarg_run_options(sargp, NULL, NULL, 0);
7274 if (!fp) rb_syserr_fail_path(e, prog);
7275 fd = fileno(fp);
7276 #endif
7278 port = io_alloc(rb_cIO);
7279 MakeOpenFile(port, fptr);
7280 fptr->fd = fd;
7281 fptr->stdio_file = fp;
7282 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7283 if (convconfig) {
7284 fptr->encs = *convconfig;
7285 #if RUBY_CRLF_ENVIRONMENT
7286 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
7287 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7289 #endif
7291 else {
7292 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7293 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7295 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7296 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7297 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7299 #endif
7301 fptr->pid = pid;
7303 if (0 <= write_fd) {
7304 write_port = io_alloc(rb_cIO);
7305 MakeOpenFile(write_port, write_fptr);
7306 write_fptr->fd = write_fd;
7307 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7308 fptr->mode &= ~FMODE_WRITABLE;
7309 fptr->tied_io_for_writing = write_port;
7310 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7313 #if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7314 fptr->finalize = pipe_finalize;
7315 pipe_add_fptr(fptr);
7316 #endif
7317 return port;
7319 #else
7320 static VALUE
7321 pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7322 const convconfig_t *convconfig)
7324 rb_raise(rb_eNotImpError, "popen() is not available");
7326 #endif
7328 static int
7329 is_popen_fork(VALUE prog)
7331 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7332 #if !defined(HAVE_WORKING_FORK)
7333 rb_raise(rb_eNotImpError,
7334 "fork() function is unimplemented on this machine");
7335 #else
7336 return TRUE;
7337 #endif
7339 return FALSE;
7342 static VALUE
7343 pipe_open_s(VALUE prog, const char *modestr, int fmode,
7344 const convconfig_t *convconfig)
7346 int argc = 1;
7347 VALUE *argv = &prog;
7348 VALUE execarg_obj = Qnil;
7350 if (!is_popen_fork(prog))
7351 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7352 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7355 static VALUE
7356 pipe_close(VALUE io)
7358 rb_io_t *fptr = io_close_fptr(io);
7359 if (fptr) {
7360 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7362 return Qnil;
7365 static VALUE popen_finish(VALUE port, VALUE klass);
7368 * call-seq:
7369 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7370 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7372 * Executes the given command +cmd+ as a subprocess
7373 * whose $stdin and $stdout are connected to a new stream +io+.
7375 * If no block is given, returns the new stream,
7376 * which depending on given +mode+ may be open for reading, writing, or both.
7377 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7379 * If a block is given, the stream is passed to the block
7380 * (again, open for reading, writing, or both);
7381 * when the block exits, the stream is closed,
7382 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7384 * Optional argument +mode+ may be any valid \IO mode.
7385 * See {Modes}[#class-IO-label-Modes].
7387 * Required argument +cmd+ determines which of the following occurs:
7389 * - The process forks.
7390 * - A specified program runs in a shell.
7391 * - A specified program runs with specified arguments.
7392 * - A specified program runs with specified arguments and a specified +argv0+.
7394 * Each of these is detailed below.
7396 * The optional hash argument +env+ specifies name/value pairs that are to be added
7397 * to the environment variables for the subprocess:
7399 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7400 * pipe.puts 'puts ENV["FOO"]'
7401 * pipe.close_write
7402 * pipe.gets
7403 * end => "bar\n"
7405 * The optional keyword arguments +opts+ may be {\IO open options}[#class-IO-label-Open+Options]
7406 * and options for Kernel#spawn.
7408 * <b>Forked \Process</b>
7410 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7411 * IO.popen('-') do |pipe|
7412 * if pipe
7413 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7414 * else
7415 * $stderr.puts "In child, pid is #{$$}\n"
7416 * end
7417 * end
7419 * Output:
7421 * In parent, child pid is 26253
7422 * In child, pid is 26253
7424 * Note that this is not supported on all platforms.
7426 * <b>Shell Subprocess</b>
7428 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7429 * the program named +cmd+ is run as a shell command:
7431 * IO.popen('uname') do |pipe|
7432 * pipe.readlines
7433 * end
7435 * Output:
7437 * ["Linux\n"]
7439 * Another example:
7441 * IO.popen('/bin/sh', 'r+') do |pipe|
7442 * pipe.puts('ls')
7443 * pipe.close_write
7444 * $stderr.puts pipe.readlines.size
7445 * end
7447 * Output:
7449 * 213
7451 * <b>Program Subprocess</b>
7453 * When argument +cmd+ is an array of strings,
7454 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7456 * IO.popen(['du', '..', '.']) do |pipe|
7457 * $stderr.puts pipe.readlines.size
7458 * end
7460 * Output:
7462 * 1111
7464 * <b>Program Subprocess with <tt>argv0</tt></b>
7466 * When argument +cmd+ is an array whose first element is a 2-element string array
7467 * and whose remaining elements (if any) are strings:
7469 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7470 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7471 * - <tt>cmd[1..-1] (the strings in the outer array) are the program's arguments.
7473 * Example (sets <tt>$0</tt> to 'foo'):
7475 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7477 * <b>Some Special Examples</b>
7479 * # Set IO encoding.
7480 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7481 * euc_jp_string = nkf_io.read
7484 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7485 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7486 * ls_result_with_error = io.read
7487 * end
7489 * # Use mixture of spawn options and IO options.
7490 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7491 * ls_result_with_error = io.read
7492 * end
7494 * f = IO.popen("uname")
7495 * p f.readlines
7496 * f.close
7497 * puts "Parent is #{Process.pid}"
7498 * IO.popen("date") {|f| puts f.gets }
7499 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7500 * p $?
7501 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7502 * f.puts "bar"; f.close_write; puts f.gets
7505 * Output (from last section):
7507 * ["Linux\n"]
7508 * Parent is 21346
7509 * Thu Jan 15 22:41:19 JST 2009
7510 * 21346 is here, f is #<IO:fd 3>
7511 * 21352 is here, f is nil
7512 * #<Process::Status: pid 21352 exit 0>
7513 * <foo>bar;zot;
7515 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7519 static VALUE
7520 rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7522 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7524 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7525 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7526 switch (argc) {
7527 case 2:
7528 pmode = argv[1];
7529 case 1:
7530 pname = argv[0];
7531 break;
7532 default:
7534 int ex = !NIL_P(opt);
7535 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7538 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7541 VALUE
7542 rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7544 const char *modestr;
7545 VALUE tmp, execarg_obj = Qnil;
7546 int oflags, fmode;
7547 convconfig_t convconfig;
7549 tmp = rb_check_array_type(pname);
7550 if (!NIL_P(tmp)) {
7551 long len = RARRAY_LEN(tmp);
7552 #if SIZEOF_LONG > SIZEOF_INT
7553 if (len > INT_MAX) {
7554 rb_raise(rb_eArgError, "too many arguments");
7556 #endif
7557 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7558 RB_GC_GUARD(tmp);
7560 else {
7561 SafeStringValue(pname);
7562 execarg_obj = Qnil;
7563 if (!is_popen_fork(pname))
7564 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7566 if (!NIL_P(execarg_obj)) {
7567 if (!NIL_P(opt))
7568 opt = rb_execarg_extract_options(execarg_obj, opt);
7569 if (!NIL_P(env))
7570 rb_execarg_setenv(execarg_obj, env);
7572 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
7573 modestr = rb_io_oflags_modestr(oflags);
7575 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7578 static VALUE
7579 popen_finish(VALUE port, VALUE klass)
7581 if (NIL_P(port)) {
7582 /* child */
7583 if (rb_block_given_p()) {
7584 rb_yield(Qnil);
7585 rb_io_flush(rb_ractor_stdout());
7586 rb_io_flush(rb_ractor_stderr());
7587 _exit(0);
7589 return Qnil;
7591 RBASIC_SET_CLASS(port, klass);
7592 if (rb_block_given_p()) {
7593 return rb_ensure(rb_yield, port, pipe_close, port);
7595 return port;
7598 static void
7599 rb_scan_open_args(int argc, const VALUE *argv,
7600 VALUE *fname_p, int *oflags_p, int *fmode_p,
7601 convconfig_t *convconfig_p, mode_t *perm_p)
7603 VALUE opt, fname, vmode, vperm;
7604 int oflags, fmode;
7605 mode_t perm;
7607 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
7608 FilePathValue(fname);
7610 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
7612 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
7614 *fname_p = fname;
7615 *oflags_p = oflags;
7616 *fmode_p = fmode;
7617 *perm_p = perm;
7620 static VALUE
7621 rb_open_file(int argc, const VALUE *argv, VALUE io)
7623 VALUE fname;
7624 int oflags, fmode;
7625 convconfig_t convconfig;
7626 mode_t perm;
7628 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
7629 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
7631 return io;
7635 * Document-method: File::open
7637 * call-seq:
7638 * File.open(path, mode = 'r', perm = 0666, **opts]) -> file
7639 * File.open(path, mode = 'r', perm = 0666, **opts]) {|f| ... } -> object
7641 * Creates a new \File object, via File.new with the given arguments.
7643 * With no block given, returns the \File object.
7645 * With a block given, calls the block with the \File object
7646 * and returns the block's value.
7651 * Document-method: IO::open
7653 * call-seq:
7654 * IO.open(fd, mode = 'r', **opts]) -> io
7655 * IO.open(fd, mode = 'r', **opts]) {|io| ... } -> object
7657 * Creates a new \IO object, via IO.new with the given arguments.
7659 * With no block given, returns the \IO object.
7661 * With a block given, calls the block with the \IO object
7662 * and returns the block's value.
7666 static VALUE
7667 rb_io_s_open(int argc, VALUE *argv, VALUE klass)
7669 VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
7671 if (rb_block_given_p()) {
7672 return rb_ensure(rb_yield, io, io_close, io);
7675 return io;
7679 * call-seq:
7680 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
7682 * Opens the file at the given path with the given mode and permissions;
7683 * returns the integer file descriptor.
7685 * If the file is to be readable, it must exist;
7686 * if the file is to be writable and does not exist,
7687 * it is created with the given permissions:
7689 * File.write('t.tmp', '') # => 0
7690 * IO.sysopen('t.tmp') # => 8
7691 * IO.sysopen('t.tmp', 'w') # => 9
7696 static VALUE
7697 rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
7699 VALUE fname, vmode, vperm;
7700 VALUE intmode;
7701 int oflags, fd;
7702 mode_t perm;
7704 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
7705 FilePathValue(fname);
7707 if (NIL_P(vmode))
7708 oflags = O_RDONLY;
7709 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
7710 oflags = NUM2INT(intmode);
7711 else {
7712 SafeStringValue(vmode);
7713 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
7715 if (NIL_P(vperm)) perm = 0666;
7716 else perm = NUM2MODET(vperm);
7718 RB_GC_GUARD(fname) = rb_str_new4(fname);
7719 fd = rb_sysopen(fname, oflags, perm);
7720 return INT2NUM(fd);
7723 static VALUE
7724 check_pipe_command(VALUE filename_or_command)
7726 char *s = RSTRING_PTR(filename_or_command);
7727 long l = RSTRING_LEN(filename_or_command);
7728 char *e = s + l;
7729 int chlen;
7731 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
7732 VALUE cmd = rb_str_new(s+chlen, l-chlen);
7733 return cmd;
7735 return Qnil;
7739 * call-seq:
7740 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
7741 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
7743 * Creates an IO object connected to the given stream, file, or subprocess.
7745 * Required string argument +path+ determines which of the following occurs:
7747 * - The file at the specified +path+ is opened.
7748 * - The process forks.
7749 * - A subprocess is created.
7751 * Each of these is detailed below.
7753 * <b>File Opened</b>
7755 * If +path+ does _not_ start with a pipe character (<tt>'|'</tt>),
7756 * a file stream is opened with <tt>File.open(path, mode, perm, opts)</tt>.
7758 * With no block given, file stream is returned:
7760 * open('t.txt') # => #<File:t.txt>
7762 * With a block given, calls the block with the open file stream,
7763 * then closes the stream:
7765 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
7767 * Output:
7769 * #<File:t.txt>
7771 * See File.open for details.
7773 * <b>Process Forked</b>
7775 * If +path+ is the 2-character string <tt>'|-'</tt>, the process forks
7776 * and the child process is connected to the parent.
7778 * With no block given:
7780 * io = open('|-')
7781 * if io
7782 * $stderr.puts "In parent, child pid is #{io.pid}."
7783 * else
7784 * $stderr.puts "In child, pid is #{$$}."
7785 * end
7787 * Output:
7789 * In parent, child pid is 27903.
7790 * In child, pid is 27903.
7792 * With a block given:
7794 * open('|-') do |io|
7795 * if io
7796 * $stderr.puts "In parent, child pid is #{io.pid}."
7797 * else
7798 * $stderr.puts "In child, pid is #{$$}."
7799 * end
7800 * end
7802 * Output:
7804 * In parent, child pid is 28427.
7805 * In child, pid is 28427.
7807 * <b>Subprocess Created</b>
7809 * If +path+ is <tt>'|command'</tt> (<tt>'command' != '-'</tt>),
7810 * a new subprocess runs the command; its open stream is returned.
7811 * Note that the command may be processed by shell if it contains
7812 * shell metacharacters.
7814 * With no block given:
7816 * io = open('|echo "Hi!"') # => #<IO:fd 12>
7817 * print io.gets
7818 * io.close
7820 * Output:
7822 * "Hi!"
7824 * With a block given, calls the block with the stream, then closes the stream:
7826 * open('|echo "Hi!"') do |io|
7827 * print io.gets
7828 * end
7830 * Output:
7832 * "Hi!"
7836 static VALUE
7837 rb_f_open(int argc, VALUE *argv, VALUE _)
7839 ID to_open = 0;
7840 int redirect = FALSE;
7842 if (argc >= 1) {
7843 CONST_ID(to_open, "to_open");
7844 if (rb_respond_to(argv[0], to_open)) {
7845 redirect = TRUE;
7847 else {
7848 VALUE tmp = argv[0];
7849 FilePathValue(tmp);
7850 if (NIL_P(tmp)) {
7851 redirect = TRUE;
7853 else {
7854 VALUE cmd = check_pipe_command(tmp);
7855 if (!NIL_P(cmd)) {
7856 argv[0] = cmd;
7857 return rb_io_s_popen(argc, argv, rb_cIO);
7862 if (redirect) {
7863 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
7865 if (rb_block_given_p()) {
7866 return rb_ensure(rb_yield, io, io_close, io);
7868 return io;
7870 return rb_io_s_open(argc, argv, rb_cFile);
7873 static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const convconfig_t *, mode_t);
7875 static VALUE
7876 rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
7878 int oflags, fmode;
7879 convconfig_t convconfig;
7880 mode_t perm;
7882 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
7883 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
7884 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
7887 static VALUE
7888 rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
7889 const convconfig_t *convconfig, mode_t perm)
7891 VALUE cmd;
7892 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
7893 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
7895 else {
7896 return rb_file_open_generic(io_alloc(klass), filename,
7897 oflags, fmode, convconfig, perm);
7901 static VALUE
7902 io_reopen(VALUE io, VALUE nfile)
7904 rb_io_t *fptr, *orig;
7905 int fd, fd2;
7906 off_t pos = 0;
7908 nfile = rb_io_get_io(nfile);
7909 GetOpenFile(io, fptr);
7910 GetOpenFile(nfile, orig);
7912 if (fptr == orig) return io;
7913 if (IS_PREP_STDIO(fptr)) {
7914 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
7915 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
7916 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
7917 rb_raise(rb_eArgError,
7918 "%s can't change access mode from \"%s\" to \"%s\"",
7919 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
7920 rb_io_fmode_modestr(orig->mode));
7923 if (fptr->mode & FMODE_WRITABLE) {
7924 if (io_fflush(fptr) < 0)
7925 rb_sys_fail_on_write(fptr);
7927 else {
7928 flush_before_seek(fptr);
7930 if (orig->mode & FMODE_READABLE) {
7931 pos = io_tell(orig);
7933 if (orig->mode & FMODE_WRITABLE) {
7934 if (io_fflush(orig) < 0)
7935 rb_sys_fail_on_write(fptr);
7938 /* copy rb_io_t structure */
7939 fptr->mode = orig->mode | (fptr->mode & FMODE_PREP);
7940 fptr->pid = orig->pid;
7941 fptr->lineno = orig->lineno;
7942 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
7943 else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
7944 fptr_copy_finalizer(fptr, orig);
7946 fd = fptr->fd;
7947 fd2 = orig->fd;
7948 if (fd != fd2) {
7949 if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->stdio_file) {
7950 /* need to keep FILE objects of stdin, stdout and stderr */
7951 if (rb_cloexec_dup2(fd2, fd) < 0)
7952 rb_sys_fail_path(orig->pathv);
7953 rb_update_max_fd(fd);
7955 else {
7956 fclose(fptr->stdio_file);
7957 fptr->stdio_file = 0;
7958 fptr->fd = -1;
7959 if (rb_cloexec_dup2(fd2, fd) < 0)
7960 rb_sys_fail_path(orig->pathv);
7961 rb_update_max_fd(fd);
7962 fptr->fd = fd;
7964 rb_thread_fd_close(fd);
7965 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
7966 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
7967 rb_sys_fail_path(fptr->pathv);
7969 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
7970 rb_sys_fail_path(orig->pathv);
7975 if (fptr->mode & FMODE_BINMODE) {
7976 rb_io_binmode(io);
7979 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
7980 return io;
7983 #ifdef _WIN32
7984 int rb_freopen(VALUE fname, const char *mode, FILE *fp);
7985 #else
7986 static int
7987 rb_freopen(VALUE fname, const char *mode, FILE *fp)
7989 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
7990 RB_GC_GUARD(fname);
7991 return errno;
7993 return 0;
7995 #endif
7998 * call-seq:
7999 * ios.reopen(other_IO) -> ios
8000 * ios.reopen(path, mode [, opt]) -> ios
8002 * Reassociates <em>ios</em> with the I/O stream given in
8003 * <i>other_IO</i> or to a new stream opened on <i>path</i>. This may
8004 * dynamically change the actual class of this stream.
8005 * The +mode+ and +opt+ parameters accept the same values as IO.open.
8007 * f1 = File.new("testfile")
8008 * f2 = File.new("testfile")
8009 * f2.readlines[0] #=> "This is line one\n"
8010 * f2.reopen(f1) #=> #<File:testfile>
8011 * f2.readlines[0] #=> "This is line one\n"
8014 static VALUE
8015 rb_io_reopen(int argc, VALUE *argv, VALUE file)
8017 VALUE fname, nmode, opt;
8018 int oflags;
8019 rb_io_t *fptr;
8021 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8022 VALUE tmp = rb_io_check_io(fname);
8023 if (!NIL_P(tmp)) {
8024 return io_reopen(file, tmp);
8028 FilePathValue(fname);
8029 rb_io_taint_check(file);
8030 fptr = RFILE(file)->fptr;
8031 if (!fptr) {
8032 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8035 if (!NIL_P(nmode) || !NIL_P(opt)) {
8036 int fmode;
8037 convconfig_t convconfig;
8039 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8040 if (IS_PREP_STDIO(fptr) &&
8041 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8042 (fptr->mode & FMODE_READWRITE)) {
8043 rb_raise(rb_eArgError,
8044 "%s can't change access mode from \"%s\" to \"%s\"",
8045 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8046 rb_io_fmode_modestr(fmode));
8048 fptr->mode = fmode;
8049 fptr->encs = convconfig;
8051 else {
8052 oflags = rb_io_fmode_oflags(fptr->mode);
8055 fptr->pathv = fname;
8056 if (fptr->fd < 0) {
8057 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8058 fptr->stdio_file = 0;
8059 return file;
8062 if (fptr->mode & FMODE_WRITABLE) {
8063 if (io_fflush(fptr) < 0)
8064 rb_sys_fail_on_write(fptr);
8066 fptr->rbuf.off = fptr->rbuf.len = 0;
8068 if (fptr->stdio_file) {
8069 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8070 rb_io_oflags_modestr(oflags),
8071 fptr->stdio_file);
8072 if (e) rb_syserr_fail_path(e, fptr->pathv);
8073 fptr->fd = fileno(fptr->stdio_file);
8074 rb_fd_fix_cloexec(fptr->fd);
8075 #ifdef USE_SETVBUF
8076 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8077 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8078 #endif
8079 if (fptr->stdio_file == stderr) {
8080 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8081 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8083 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8084 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8085 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8088 else {
8089 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8090 int err = 0;
8091 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8092 err = errno;
8093 (void)close(tmpfd);
8094 if (err) {
8095 rb_syserr_fail_path(err, fptr->pathv);
8099 return file;
8102 /* :nodoc: */
8103 static VALUE
8104 rb_io_init_copy(VALUE dest, VALUE io)
8106 rb_io_t *fptr, *orig;
8107 int fd;
8108 VALUE write_io;
8109 off_t pos;
8111 io = rb_io_get_io(io);
8112 if (!OBJ_INIT_COPY(dest, io)) return dest;
8113 GetOpenFile(io, orig);
8114 MakeOpenFile(dest, fptr);
8116 rb_io_flush(io);
8118 /* copy rb_io_t structure */
8119 fptr->mode = orig->mode & ~FMODE_PREP;
8120 fptr->encs = orig->encs;
8121 fptr->pid = orig->pid;
8122 fptr->lineno = orig->lineno;
8123 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8124 fptr_copy_finalizer(fptr, orig);
8126 fd = ruby_dup(orig->fd);
8127 fptr->fd = fd;
8128 pos = io_tell(orig);
8129 if (0 <= pos)
8130 io_seek(fptr, pos, SEEK_SET);
8131 if (fptr->mode & FMODE_BINMODE) {
8132 rb_io_binmode(dest);
8135 write_io = GetWriteIO(io);
8136 if (io != write_io) {
8137 write_io = rb_obj_dup(write_io);
8138 fptr->tied_io_for_writing = write_io;
8139 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8142 return dest;
8146 * call-seq:
8147 * ios.printf(format_string [, obj, ...]) -> nil
8149 * Formats and writes to <em>ios</em>, converting parameters under
8150 * control of the format string. See Kernel#sprintf for details.
8153 VALUE
8154 rb_io_printf(int argc, const VALUE *argv, VALUE out)
8156 rb_io_write(out, rb_f_sprintf(argc, argv));
8157 return Qnil;
8161 * call-seq:
8162 * printf(io, string [, obj ... ]) -> nil
8163 * printf(string [, obj ... ]) -> nil
8165 * Equivalent to:
8166 * io.write(sprintf(string, obj, ...))
8167 * or
8168 * $stdout.write(sprintf(string, obj, ...))
8171 static VALUE
8172 rb_f_printf(int argc, VALUE *argv, VALUE _)
8174 VALUE out;
8176 if (argc == 0) return Qnil;
8177 if (RB_TYPE_P(argv[0], T_STRING)) {
8178 out = rb_ractor_stdout();
8180 else {
8181 out = argv[0];
8182 argv++;
8183 argc--;
8185 rb_io_write(out, rb_f_sprintf(argc, argv));
8187 return Qnil;
8190 static void
8191 deprecated_str_setter(VALUE val, ID id, VALUE *var)
8193 rb_str_setter(val, id, &val);
8194 if (!NIL_P(val)) {
8195 rb_warn_deprecated("`%s'", NULL, rb_id2name(id));
8197 *var = val;
8201 * call-seq:
8202 * ios.print -> nil
8203 * ios.print(obj, ...) -> nil
8205 * Writes the given object(s) to <em>ios</em>. Returns +nil+.
8207 * The stream must be opened for writing.
8208 * Each given object that isn't a string will be converted by calling
8209 * its <code>to_s</code> method.
8210 * When called without arguments, prints the contents of <code>$_</code>.
8212 * If the output field separator (<code>$,</code>) is not +nil+,
8213 * it is inserted between objects.
8214 * If the output record separator (<code>$\\</code>) is not +nil+,
8215 * it is appended to the output.
8217 * $stdout.print("This is ", 100, " percent.\n")
8219 * <em>produces:</em>
8221 * This is 100 percent.
8224 VALUE
8225 rb_io_print(int argc, const VALUE *argv, VALUE out)
8227 int i;
8228 VALUE line;
8230 /* if no argument given, print `$_' */
8231 if (argc == 0) {
8232 argc = 1;
8233 line = rb_lastline_get();
8234 argv = &line;
8236 if (argc > 1 && !NIL_P(rb_output_fs)) {
8237 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8239 for (i=0; i<argc; i++) {
8240 if (!NIL_P(rb_output_fs) && i>0) {
8241 rb_io_write(out, rb_output_fs);
8243 rb_io_write(out, argv[i]);
8245 if (argc > 0 && !NIL_P(rb_output_rs)) {
8246 rb_io_write(out, rb_output_rs);
8249 return Qnil;
8253 * call-seq:
8254 * print(obj, ...) -> nil
8256 * Prints each object in turn to <code>$stdout</code>. If the output
8257 * field separator (<code>$,</code>) is not +nil+, its
8258 * contents will appear between each field. If the output record
8259 * separator (<code>$\\</code>) is not +nil+, it will be
8260 * appended to the output. If no arguments are given, prints
8261 * <code>$_</code>. Objects that aren't strings will be converted by
8262 * calling their <code>to_s</code> method.
8264 * print "cat", [1,2,3], 99, "\n"
8265 * $, = ", "
8266 * $\ = "\n"
8267 * print "cat", [1,2,3], 99
8269 * <em>produces:</em>
8271 * cat12399
8272 * cat, 1, 2, 3, 99
8275 static VALUE
8276 rb_f_print(int argc, const VALUE *argv, VALUE _)
8278 rb_io_print(argc, argv, rb_ractor_stdout());
8279 return Qnil;
8283 * call-seq:
8284 * ios.putc(obj) -> obj
8286 * If <i>obj</i> is Numeric, write the character whose code is the
8287 * least-significant byte of <i>obj</i>. If <i>obj</i> is String,
8288 * write the first character of <i>obj</i> to <em>ios</em>. Otherwise,
8289 * raise TypeError.
8291 * $stdout.putc "A"
8292 * $stdout.putc 65
8294 * <em>produces:</em>
8296 * AA
8299 static VALUE
8300 rb_io_putc(VALUE io, VALUE ch)
8302 VALUE str;
8303 if (RB_TYPE_P(ch, T_STRING)) {
8304 str = rb_str_substr(ch, 0, 1);
8306 else {
8307 char c = NUM2CHR(ch);
8308 str = rb_str_new(&c, 1);
8310 rb_io_write(io, str);
8311 return ch;
8314 #define forward(obj, id, argc, argv) \
8315 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8316 #define forward_public(obj, id, argc, argv) \
8317 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8318 #define forward_current(id, argc, argv) \
8319 forward_public(ARGF.current_file, id, argc, argv)
8322 * call-seq:
8323 * putc(int) -> int
8325 * Equivalent to:
8327 * $stdout.putc(int)
8329 * See IO#putc for important information regarding multi-byte characters.
8333 static VALUE
8334 rb_f_putc(VALUE recv, VALUE ch)
8336 VALUE r_stdout = rb_ractor_stdout();
8337 if (recv == r_stdout) {
8338 return rb_io_putc(recv, ch);
8340 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8345 rb_str_end_with_asciichar(VALUE str, int c)
8347 long len = RSTRING_LEN(str);
8348 const char *ptr = RSTRING_PTR(str);
8349 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8350 int n;
8352 if (len == 0) return 0;
8353 if ((n = rb_enc_mbminlen(enc)) == 1) {
8354 return ptr[len - 1] == c;
8356 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8359 static VALUE
8360 io_puts_ary(VALUE ary, VALUE out, int recur)
8362 VALUE tmp;
8363 long i;
8365 if (recur) {
8366 tmp = rb_str_new2("[...]");
8367 rb_io_puts(1, &tmp, out);
8368 return Qtrue;
8370 ary = rb_check_array_type(ary);
8371 if (NIL_P(ary)) return Qfalse;
8372 for (i=0; i<RARRAY_LEN(ary); i++) {
8373 tmp = RARRAY_AREF(ary, i);
8374 rb_io_puts(1, &tmp, out);
8376 return Qtrue;
8380 * call-seq:
8381 * puts(*objects) -> nil
8383 * Writes the given +objects+ to the stream, which must be open for writing;
8384 * returns +nil+.\
8385 * Writes a newline after each that does not already end with a newline sequence.
8386 * If called without arguments, writes a newline.
8388 * Note that each added newline is the character <tt>"\n"<//tt>,
8389 * not the output record separator (<tt>$\\</tt>).
8391 * Treatment for each object:
8393 * - \String: writes the string.
8394 * - Neither string nor array: writes <tt>object.to_s</tt>.
8395 * - \Array: writes each element of the array; arrays may be nested.
8397 * To keep these examples brief, we define this helper method:
8399 * def show(*objects)
8400 * # Puts objects to file.
8401 * f = File.new('t.tmp', 'w+')
8402 * f.puts(objects)
8403 * # Return file content.
8404 * f.rewind
8405 * p f.read
8406 * end
8408 * # Strings without newlines.
8409 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8410 * # Strings, some with newlines.
8411 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8413 * # Neither strings nor arrays:
8414 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8415 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8417 * # Array of strings.
8418 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8419 * # Nested arrays.
8420 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8424 VALUE
8425 rb_io_puts(int argc, const VALUE *argv, VALUE out)
8427 int i, n;
8428 VALUE line, args[2];
8430 /* if no argument given, print newline. */
8431 if (argc == 0) {
8432 rb_io_write(out, rb_default_rs);
8433 return Qnil;
8435 for (i=0; i<argc; i++) {
8436 if (RB_TYPE_P(argv[i], T_STRING)) {
8437 line = argv[i];
8438 goto string;
8440 if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8441 continue;
8443 line = rb_obj_as_string(argv[i]);
8444 string:
8445 n = 0;
8446 args[n++] = line;
8447 if (RSTRING_LEN(line) == 0 ||
8448 !rb_str_end_with_asciichar(line, '\n')) {
8449 args[n++] = rb_default_rs;
8451 rb_io_writev(out, n, args);
8454 return Qnil;
8458 * call-seq:
8459 * puts(*objects) -> nil
8461 * Equivalent to
8463 * $stdout.puts(objects)
8466 static VALUE
8467 rb_f_puts(int argc, VALUE *argv, VALUE recv)
8469 VALUE r_stdout = rb_ractor_stdout();
8470 if (recv == r_stdout) {
8471 return rb_io_puts(argc, argv, recv);
8473 return forward(r_stdout, rb_intern("puts"), argc, argv);
8476 static VALUE
8477 rb_p_write(VALUE str)
8479 VALUE args[2];
8480 args[0] = str;
8481 args[1] = rb_default_rs;
8482 VALUE r_stdout = rb_ractor_stdout();
8483 if (RB_TYPE_P(r_stdout, T_FILE) &&
8484 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
8485 io_writev(2, args, r_stdout);
8487 else {
8488 rb_io_writev(r_stdout, 2, args);
8490 return Qnil;
8493 void
8494 rb_p(VALUE obj) /* for debug print within C code */
8496 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
8499 static VALUE
8500 rb_p_result(int argc, const VALUE *argv)
8502 VALUE ret = Qnil;
8504 if (argc == 1) {
8505 ret = argv[0];
8507 else if (argc > 1) {
8508 ret = rb_ary_new4(argc, argv);
8510 VALUE r_stdout = rb_ractor_stdout();
8511 if (RB_TYPE_P(r_stdout, T_FILE)) {
8512 rb_io_flush(r_stdout);
8514 return ret;
8518 * call-seq:
8519 * p(object) -> obj
8520 * p(*objects) -> array of objects
8521 * p -> nil
8523 * For each object +obj+, executes:
8525 * $stdout.write(obj.inspect, "\n")
8527 * With one object given, returns the object;
8528 * with multiple objects given, returns an array containing the objects;
8529 * with no object given, returns +nil+.
8531 * Examples:
8533 * r = Range.new(0, 4)
8534 * p r # => 0..4
8535 * p [r, r, r] # => [0..4, 0..4, 0..4]
8536 * p # => nil
8538 * Output:
8540 * 0..4
8541 * [0..4, 0..4, 0..4]
8545 static VALUE
8546 rb_f_p(int argc, VALUE *argv, VALUE self)
8548 int i;
8549 for (i=0; i<argc; i++) {
8550 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
8551 rb_uninterruptible(rb_p_write, inspected);
8553 return rb_p_result(argc, argv);
8557 * call-seq:
8558 * display(port = $>) -> nil
8560 * Writes +self+ on the given port:
8562 * 1.display
8563 * "cat".display
8564 * [ 4, 5, 6 ].display
8565 * puts
8567 * Output:
8569 * 1cat[4, 5, 6]
8573 static VALUE
8574 rb_obj_display(int argc, VALUE *argv, VALUE self)
8576 VALUE out;
8578 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
8579 rb_io_write(out, self);
8581 return Qnil;
8584 static int
8585 rb_stderr_to_original_p(VALUE err)
8587 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
8590 void
8591 rb_write_error2(const char *mesg, long len)
8593 VALUE out = rb_ractor_stderr();
8594 if (rb_stderr_to_original_p(out)) {
8595 #ifdef _WIN32
8596 if (isatty(fileno(stderr))) {
8597 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
8599 #endif
8600 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
8601 /* failed to write to stderr, what can we do? */
8602 return;
8605 else {
8606 rb_io_write(out, rb_str_new(mesg, len));
8610 void
8611 rb_write_error(const char *mesg)
8613 rb_write_error2(mesg, strlen(mesg));
8616 void
8617 rb_write_error_str(VALUE mesg)
8619 VALUE out = rb_ractor_stderr();
8620 /* a stopgap measure for the time being */
8621 if (rb_stderr_to_original_p(out)) {
8622 size_t len = (size_t)RSTRING_LEN(mesg);
8623 #ifdef _WIN32
8624 if (isatty(fileno(stderr))) {
8625 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
8627 #endif
8628 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
8629 RB_GC_GUARD(mesg);
8630 return;
8633 else {
8634 /* may unlock GVL, and */
8635 rb_io_write(out, mesg);
8640 rb_stderr_tty_p(void)
8642 if (rb_stderr_to_original_p(rb_ractor_stderr()))
8643 return isatty(fileno(stderr));
8644 return 0;
8647 static void
8648 must_respond_to(ID mid, VALUE val, ID id)
8650 if (!rb_respond_to(val, mid)) {
8651 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
8652 rb_id2str(id), rb_id2str(mid),
8653 rb_obj_class(val));
8657 static void
8658 stdin_setter(VALUE val, ID id, VALUE *ptr)
8660 rb_ractor_stdin_set(val);
8663 static VALUE
8664 stdin_getter(ID id, VALUE *ptr)
8666 return rb_ractor_stdin();
8669 static void
8670 stdout_setter(VALUE val, ID id, VALUE *ptr)
8672 must_respond_to(id_write, val, id);
8673 rb_ractor_stdout_set(val);
8676 static VALUE
8677 stdout_getter(ID id, VALUE *ptr)
8679 return rb_ractor_stdout();
8682 static void
8683 stderr_setter(VALUE val, ID id, VALUE *ptr)
8685 must_respond_to(id_write, val, id);
8686 rb_ractor_stderr_set(val);
8689 static VALUE
8690 stderr_getter(ID id, VALUE *ptr)
8692 return rb_ractor_stderr();
8695 static VALUE
8696 prep_io(int fd, int fmode, VALUE klass, const char *path)
8698 rb_io_t *fp;
8699 VALUE io = io_alloc(klass);
8701 MakeOpenFile(io, fp);
8702 fp->self = io;
8703 fp->fd = fd;
8704 fp->mode = fmode;
8705 if (!io_check_tty(fp)) {
8706 #ifdef __CYGWIN__
8707 fp->mode |= FMODE_BINMODE;
8708 setmode(fd, O_BINARY);
8709 #endif
8711 if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
8712 rb_update_max_fd(fd);
8714 return io;
8717 VALUE
8718 rb_io_fdopen(int fd, int oflags, const char *path)
8720 VALUE klass = rb_cIO;
8722 if (path && strcmp(path, "-")) klass = rb_cFile;
8723 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
8726 static VALUE
8727 prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
8729 rb_io_t *fptr;
8730 VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
8732 GetOpenFile(io, fptr);
8733 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
8734 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
8735 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
8736 if (fmode & FMODE_READABLE) {
8737 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
8739 #endif
8740 fptr->stdio_file = f;
8742 return io;
8745 VALUE
8746 rb_io_prep_stdin(void)
8748 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
8751 VALUE
8752 rb_io_prep_stdout(void)
8754 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
8757 VALUE
8758 rb_io_prep_stderr(void)
8760 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
8763 FILE *
8764 rb_io_stdio_file(rb_io_t *fptr)
8766 if (!fptr->stdio_file) {
8767 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
8768 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
8770 return fptr->stdio_file;
8773 static inline void
8774 rb_io_buffer_init(rb_io_buffer_t *buf)
8776 buf->ptr = NULL;
8777 buf->off = 0;
8778 buf->len = 0;
8779 buf->capa = 0;
8782 static inline rb_io_t *
8783 rb_io_fptr_new(void)
8785 rb_io_t *fp = ALLOC(rb_io_t);
8786 fp->self = Qnil;
8787 fp->fd = -1;
8788 fp->stdio_file = NULL;
8789 fp->mode = 0;
8790 fp->pid = 0;
8791 fp->lineno = 0;
8792 fp->pathv = Qnil;
8793 fp->finalize = 0;
8794 rb_io_buffer_init(&fp->wbuf);
8795 rb_io_buffer_init(&fp->rbuf);
8796 rb_io_buffer_init(&fp->cbuf);
8797 fp->readconv = NULL;
8798 fp->writeconv = NULL;
8799 fp->writeconv_asciicompat = Qnil;
8800 fp->writeconv_pre_ecflags = 0;
8801 fp->writeconv_pre_ecopts = Qnil;
8802 fp->writeconv_initialized = 0;
8803 fp->tied_io_for_writing = 0;
8804 fp->encs.enc = NULL;
8805 fp->encs.enc2 = NULL;
8806 fp->encs.ecflags = 0;
8807 fp->encs.ecopts = Qnil;
8808 fp->write_lock = 0;
8809 return fp;
8812 rb_io_t *
8813 rb_io_make_open_file(VALUE obj)
8815 rb_io_t *fp = 0;
8817 Check_Type(obj, T_FILE);
8818 if (RFILE(obj)->fptr) {
8819 rb_io_close(obj);
8820 rb_io_fptr_finalize(RFILE(obj)->fptr);
8821 RFILE(obj)->fptr = 0;
8823 fp = rb_io_fptr_new();
8824 fp->self = obj;
8825 RFILE(obj)->fptr = fp;
8826 return fp;
8830 * call-seq:
8831 * IO.new(fd [, mode] [, opt]) -> io
8833 * Returns a new IO object (a stream) for the given integer file descriptor
8834 * +fd+ and +mode+ string. +opt+ may be used to specify parts of +mode+ in a
8835 * more readable fashion. See also IO.sysopen and IO.for_fd.
8837 * IO.new is called by various File and IO opening methods such as IO::open,
8838 * Kernel#open, and File::open.
8840 * === Open Mode
8842 * When +mode+ is an integer it must be combination of the modes defined in
8843 * File::Constants (+File::RDONLY+, <code>File::WRONLY|File::CREAT</code>).
8844 * See the open(2) man page for more information.
8846 * When +mode+ is a string it must be in one of the following forms:
8848 * fmode
8849 * fmode ":" ext_enc
8850 * fmode ":" ext_enc ":" int_enc
8851 * fmode ":" "BOM|UTF-*"
8853 * +fmode+ is an IO open mode string, +ext_enc+ is the external encoding for
8854 * the IO and +int_enc+ is the internal encoding.
8856 * ==== IO Open Mode
8858 * Ruby allows the following open modes:
8860 * "r" Read-only, starts at beginning of file (default mode).
8862 * "r+" Read-write, starts at beginning of file.
8864 * "w" Write-only, truncates existing file
8865 * to zero length or creates a new file for writing.
8867 * "w+" Read-write, truncates existing file to zero length
8868 * or creates a new file for reading and writing.
8870 * "a" Write-only, each write call appends data at end of file.
8871 * Creates a new file for writing if file does not exist.
8873 * "a+" Read-write, each write call appends data at end of file.
8874 * Creates a new file for reading and writing if file does
8875 * not exist.
8877 * The following modes must be used separately, and along with one or more of
8878 * the modes seen above.
8880 * "b" Binary file mode
8881 * Suppresses EOL <-> CRLF conversion on Windows. And
8882 * sets external encoding to ASCII-8BIT unless explicitly
8883 * specified.
8885 * "t" Text file mode
8887 * The exclusive access mode ("x") can be used together with "w" to ensure
8888 * the file is created. Errno::EEXIST is raised when it already exists.
8889 * It may not be supported with all kinds of streams (e.g. pipes).
8891 * When the open mode of original IO is read only, the mode cannot be
8892 * changed to be writable. Similarly, the open mode cannot be changed from
8893 * write only to readable.
8895 * When such a change is attempted the error is raised in different locations
8896 * according to the platform.
8898 * === IO Encoding
8900 * When +ext_enc+ is specified, strings read will be tagged by the encoding
8901 * when reading, and strings output will be converted to the specified
8902 * encoding when writing.
8904 * When +ext_enc+ and +int_enc+ are specified read strings will be converted
8905 * from +ext_enc+ to +int_enc+ upon input, and written strings will be
8906 * converted from +int_enc+ to +ext_enc+ upon output. See Encoding for
8907 * further details of transcoding on input and output.
8909 * If "BOM|UTF-8", "BOM|UTF-16LE" or "BOM|UTF16-BE" are used, Ruby checks for
8910 * a Unicode BOM in the input document to help determine the encoding. For
8911 * UTF-16 encodings the file open mode must be binary. When present, the BOM
8912 * is stripped and the external encoding from the BOM is used. When the BOM
8913 * is missing the given Unicode encoding is used as +ext_enc+. (The BOM-set
8914 * encoding option is case insensitive, so "bom|utf-8" is also valid.)
8916 * === Options
8918 * +opt+ can be used instead of +mode+ for improved readability. The
8919 * following keys are supported:
8921 * :mode ::
8922 * Same as +mode+ parameter
8924 * :flags ::
8925 * Specifies file open flags as integer.
8926 * If +mode+ parameter is given, this parameter will be bitwise-ORed.
8928 * :\external_encoding ::
8929 * External encoding for the IO.
8931 * :\internal_encoding ::
8932 * Internal encoding for the IO. "-" is a synonym for the default internal
8933 * encoding.
8935 * If the value is +nil+ no conversion occurs.
8937 * :encoding ::
8938 * Specifies external and internal encodings as "extern:intern".
8940 * :textmode ::
8941 * If the value is truth value, same as "t" in argument +mode+.
8943 * :binmode ::
8944 * If the value is truth value, same as "b" in argument +mode+.
8946 * :autoclose ::
8947 * If the value is +false+, the +fd+ will be kept open after this IO
8948 * instance gets finalized.
8950 * Also, +opt+ can have same keys in String#encode for controlling conversion
8951 * between the external encoding and the internal encoding.
8953 * === Example 1
8955 * fd = IO.sysopen("/dev/tty", "w")
8956 * a = IO.new(fd,"w")
8957 * $stderr.puts "Hello"
8958 * a.puts "World"
8960 * Produces:
8962 * Hello
8963 * World
8965 * === Example 2
8967 * require 'fcntl'
8969 * fd = STDERR.fcntl(Fcntl::F_DUPFD)
8970 * io = IO.new(fd, mode: 'w:UTF-16LE', cr_newline: true)
8971 * io.puts "Hello, World!"
8973 * fd = STDERR.fcntl(Fcntl::F_DUPFD)
8974 * io = IO.new(fd, mode: 'w', cr_newline: true,
8975 * external_encoding: Encoding::UTF_16LE)
8976 * io.puts "Hello, World!"
8978 * Both of above print "Hello, World!" in UTF-16LE to standard error output
8979 * with converting EOL generated by #puts to CR.
8982 static VALUE
8983 rb_io_initialize(int argc, VALUE *argv, VALUE io)
8985 VALUE fnum, vmode;
8986 rb_io_t *fp;
8987 int fd, fmode, oflags = O_RDONLY;
8988 convconfig_t convconfig;
8989 VALUE opt;
8990 #if defined(HAVE_FCNTL) && defined(F_GETFL)
8991 int ofmode;
8992 #else
8993 struct stat st;
8994 #endif
8997 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
8998 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9000 fd = NUM2INT(fnum);
9001 if (rb_reserved_fd_p(fd)) {
9002 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9004 #if defined(HAVE_FCNTL) && defined(F_GETFL)
9005 oflags = fcntl(fd, F_GETFL);
9006 if (oflags == -1) rb_sys_fail(0);
9007 #else
9008 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9009 #endif
9010 rb_update_max_fd(fd);
9011 #if defined(HAVE_FCNTL) && defined(F_GETFL)
9012 ofmode = rb_io_oflags_fmode(oflags);
9013 if (NIL_P(vmode)) {
9014 fmode = ofmode;
9016 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9017 VALUE error = INT2FIX(EINVAL);
9018 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
9020 #endif
9021 if (!NIL_P(opt) && rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9022 fmode |= FMODE_PREP;
9024 MakeOpenFile(io, fp);
9025 fp->self = io;
9026 fp->fd = fd;
9027 fp->mode = fmode;
9028 fp->encs = convconfig;
9029 clear_codeconv(fp);
9030 io_check_tty(fp);
9031 if (fileno(stdin) == fd)
9032 fp->stdio_file = stdin;
9033 else if (fileno(stdout) == fd)
9034 fp->stdio_file = stdout;
9035 else if (fileno(stderr) == fd)
9036 fp->stdio_file = stderr;
9038 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9039 return io;
9043 * call-seq:
9044 * ios.set_encoding_by_bom -> encoding or nil
9046 * Checks if +ios+ starts with a BOM, and then consumes it and sets
9047 * the external encoding. Returns the result encoding if found, or
9048 * nil. If +ios+ is not binmode or its encoding has been set
9049 * already, an exception will be raised.
9051 * File.write("bom.txt", "\u{FEFF}abc")
9052 * ios = File.open("bom.txt", "rb")
9053 * ios.set_encoding_by_bom #=> #<Encoding:UTF-8>
9055 * File.write("nobom.txt", "abc")
9056 * ios = File.open("nobom.txt", "rb")
9057 * ios.set_encoding_by_bom #=> nil
9060 static VALUE
9061 rb_io_set_encoding_by_bom(VALUE io)
9063 rb_io_t *fptr;
9065 GetOpenFile(io, fptr);
9066 if (!(fptr->mode & FMODE_BINMODE)) {
9067 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9069 if (fptr->encs.enc2) {
9070 rb_raise(rb_eArgError, "encoding conversion is set");
9072 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9073 rb_raise(rb_eArgError, "encoding is set to %s already",
9074 rb_enc_name(fptr->encs.enc));
9076 if (!io_set_encoding_by_bom(io)) return Qnil;
9077 return rb_enc_from_encoding(fptr->encs.enc);
9081 * call-seq:
9082 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9084 * Opens the file at the given +path+ according to the given +mode+;
9085 * creates and returns a new \File object for that file.
9087 * The new \File object is buffered mode (or non-sync mode), unless
9088 * +filename+ is a tty.
9089 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9091 * Argument +path+ must be a valid file path:
9093 * File.new('/etc/fstab')
9094 * File.new('t.txt')
9096 * Optional argument +mode+ (defaults to 'r') must specify a valid mode
9097 * see {\IO Modes}[#class-IO-label-Modes]:
9099 * File.new('t.tmp', 'w')
9100 * File.new('t.tmp', File::RDONLY)
9102 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9103 * see {File Permissions}[#class-File-label-Permissions]:
9105 * File.new('t.tmp', File::CREAT, 0644)
9106 * File.new('t.tmp', File::CREAT, 0444)
9108 * Optional argument +opts+ must specify valid open options
9109 * see {IO Open Options}[#class-IO-label-Open+Options]:
9111 * File.new('t.tmp', autoclose: true)
9112 * File.new('t.tmp', internal_encoding: nil)
9116 static VALUE
9117 rb_file_initialize(int argc, VALUE *argv, VALUE io)
9119 if (RFILE(io)->fptr) {
9120 rb_raise(rb_eRuntimeError, "reinitializing File");
9122 if (0 < argc && argc < 3) {
9123 VALUE fd = rb_check_to_int(argv[0]);
9125 if (!NIL_P(fd)) {
9126 argv[0] = fd;
9127 return rb_io_initialize(argc, argv, io);
9130 rb_open_file(argc, argv, io);
9132 return io;
9135 /* :nodoc: */
9136 static VALUE
9137 rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9139 if (rb_block_given_p()) {
9140 VALUE cname = rb_obj_as_string(klass);
9142 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9143 cname, cname);
9145 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9150 * call-seq:
9151 * IO.for_fd(fd, mode [, opt]) -> io
9153 * Synonym for IO.new.
9157 static VALUE
9158 rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9160 VALUE io = rb_obj_alloc(klass);
9161 rb_io_initialize(argc, argv, io);
9162 return io;
9166 * call-seq:
9167 * ios.autoclose? -> true or false
9169 * Returns +true+ if the underlying file descriptor of _ios_ will be
9170 * closed automatically at its finalization, otherwise +false+.
9173 static VALUE
9174 rb_io_autoclose_p(VALUE io)
9176 rb_io_t *fptr = RFILE(io)->fptr;
9177 rb_io_check_closed(fptr);
9178 return RBOOL(!(fptr->mode & FMODE_PREP));
9182 * call-seq:
9183 * io.autoclose = bool -> true or false
9185 * Sets auto-close flag.
9187 * f = open("/dev/null")
9188 * IO.for_fd(f.fileno)
9189 * # ...
9190 * f.gets # may cause Errno::EBADF
9192 * f = open("/dev/null")
9193 * IO.for_fd(f.fileno).autoclose = false
9194 * # ...
9195 * f.gets # won't cause Errno::EBADF
9198 static VALUE
9199 rb_io_set_autoclose(VALUE io, VALUE autoclose)
9201 rb_io_t *fptr;
9202 GetOpenFile(io, fptr);
9203 if (!RTEST(autoclose))
9204 fptr->mode |= FMODE_PREP;
9205 else
9206 fptr->mode &= ~FMODE_PREP;
9207 return autoclose;
9210 static void
9211 argf_mark(void *ptr)
9213 struct argf *p = ptr;
9214 rb_gc_mark(p->filename);
9215 rb_gc_mark(p->current_file);
9216 rb_gc_mark(p->argv);
9217 rb_gc_mark(p->inplace);
9218 rb_gc_mark(p->encs.ecopts);
9221 static size_t
9222 argf_memsize(const void *ptr)
9224 const struct argf *p = ptr;
9225 size_t size = sizeof(*p);
9226 return size;
9229 static const rb_data_type_t argf_type = {
9230 "ARGF",
9231 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9232 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9235 static inline void
9236 argf_init(struct argf *p, VALUE v)
9238 p->filename = Qnil;
9239 p->current_file = Qnil;
9240 p->lineno = 0;
9241 p->argv = v;
9244 static VALUE
9245 argf_alloc(VALUE klass)
9247 struct argf *p;
9248 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9250 argf_init(p, Qnil);
9251 return argf;
9254 #undef rb_argv
9256 /* :nodoc: */
9257 static VALUE
9258 argf_initialize(VALUE argf, VALUE argv)
9260 memset(&ARGF, 0, sizeof(ARGF));
9261 argf_init(&ARGF, argv);
9263 return argf;
9266 /* :nodoc: */
9267 static VALUE
9268 argf_initialize_copy(VALUE argf, VALUE orig)
9270 if (!OBJ_INIT_COPY(argf, orig)) return argf;
9271 ARGF = argf_of(orig);
9272 ARGF.argv = rb_obj_dup(ARGF.argv);
9273 return argf;
9277 * call-seq:
9278 * ARGF.lineno = integer -> integer
9280 * Sets the line number of +ARGF+ as a whole to the given +Integer+.
9282 * +ARGF+ sets the line number automatically as you read data, so normally
9283 * you will not need to set it explicitly. To access the current line number
9284 * use +ARGF.lineno+.
9286 * For example:
9288 * ARGF.lineno #=> 0
9289 * ARGF.readline #=> "This is line 1\n"
9290 * ARGF.lineno #=> 1
9291 * ARGF.lineno = 0 #=> 0
9292 * ARGF.lineno #=> 0
9294 static VALUE
9295 argf_set_lineno(VALUE argf, VALUE val)
9297 ARGF.lineno = NUM2INT(val);
9298 ARGF.last_lineno = ARGF.lineno;
9299 return Qnil;
9303 * call-seq:
9304 * ARGF.lineno -> integer
9306 * Returns the current line number of ARGF as a whole. This value
9307 * can be set manually with +ARGF.lineno=+.
9309 * For example:
9311 * ARGF.lineno #=> 0
9312 * ARGF.readline #=> "This is line 1\n"
9313 * ARGF.lineno #=> 1
9315 static VALUE
9316 argf_lineno(VALUE argf)
9318 return INT2FIX(ARGF.lineno);
9321 static VALUE
9322 argf_forward(int argc, VALUE *argv, VALUE argf)
9324 return forward_current(rb_frame_this_func(), argc, argv);
9327 #define next_argv() argf_next_argv(argf)
9328 #define ARGF_GENERIC_INPUT_P() \
9329 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
9330 #define ARGF_FORWARD(argc, argv) do {\
9331 if (ARGF_GENERIC_INPUT_P())\
9332 return argf_forward((argc), (argv), argf);\
9333 } while (0)
9334 #define NEXT_ARGF_FORWARD(argc, argv) do {\
9335 if (!next_argv()) return Qnil;\
9336 ARGF_FORWARD((argc), (argv));\
9337 } while (0)
9339 static void
9340 argf_close(VALUE argf)
9342 VALUE file = ARGF.current_file;
9343 if (file == rb_stdin) return;
9344 if (RB_TYPE_P(file, T_FILE)) {
9345 rb_io_set_write_io(file, Qnil);
9347 io_close(file);
9348 ARGF.init_p = -1;
9351 static int
9352 argf_next_argv(VALUE argf)
9354 char *fn;
9355 rb_io_t *fptr;
9356 int stdout_binmode = 0;
9357 int fmode;
9359 VALUE r_stdout = rb_ractor_stdout();
9361 if (RB_TYPE_P(r_stdout, T_FILE)) {
9362 GetOpenFile(r_stdout, fptr);
9363 if (fptr->mode & FMODE_BINMODE)
9364 stdout_binmode = 1;
9367 if (ARGF.init_p == 0) {
9368 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
9369 ARGF.next_p = 1;
9371 else {
9372 ARGF.next_p = -1;
9374 ARGF.init_p = 1;
9376 else {
9377 if (NIL_P(ARGF.argv)) {
9378 ARGF.next_p = -1;
9380 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
9381 ARGF.next_p = 1;
9385 if (ARGF.next_p == 1) {
9386 if (ARGF.init_p == 1) argf_close(argf);
9387 retry:
9388 if (RARRAY_LEN(ARGF.argv) > 0) {
9389 VALUE filename = rb_ary_shift(ARGF.argv);
9390 FilePathValue(filename);
9391 ARGF.filename = filename;
9392 filename = rb_str_encode_ospath(filename);
9393 fn = StringValueCStr(filename);
9394 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
9395 ARGF.current_file = rb_stdin;
9396 if (ARGF.inplace) {
9397 rb_warn("Can't do inplace edit for stdio; skipping");
9398 goto retry;
9401 else {
9402 VALUE write_io = Qnil;
9403 int fr = rb_sysopen(filename, O_RDONLY, 0);
9405 if (ARGF.inplace) {
9406 struct stat st;
9407 #ifndef NO_SAFE_RENAME
9408 struct stat st2;
9409 #endif
9410 VALUE str;
9411 int fw;
9413 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
9414 rb_io_close(r_stdout);
9416 fstat(fr, &st);
9417 str = filename;
9418 if (!NIL_P(ARGF.inplace)) {
9419 VALUE suffix = ARGF.inplace;
9420 str = rb_str_dup(str);
9421 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
9422 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
9423 rb_enc_get(suffix), 0, Qnil))) {
9424 rb_str_append(str, suffix);
9426 #ifdef NO_SAFE_RENAME
9427 (void)close(fr);
9428 (void)unlink(RSTRING_PTR(str));
9429 if (rename(fn, RSTRING_PTR(str)) < 0) {
9430 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
9431 filename, str, strerror(errno));
9432 goto retry;
9434 fr = rb_sysopen(str, O_RDONLY, 0);
9435 #else
9436 if (rename(fn, RSTRING_PTR(str)) < 0) {
9437 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
9438 filename, str, strerror(errno));
9439 close(fr);
9440 goto retry;
9442 #endif
9444 else {
9445 #ifdef NO_SAFE_RENAME
9446 rb_fatal("Can't do inplace edit without backup");
9447 #else
9448 if (unlink(fn) < 0) {
9449 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
9450 filename, strerror(errno));
9451 close(fr);
9452 goto retry;
9454 #endif
9456 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
9457 #ifndef NO_SAFE_RENAME
9458 fstat(fw, &st2);
9459 #ifdef HAVE_FCHMOD
9460 fchmod(fw, st.st_mode);
9461 #else
9462 chmod(fn, st.st_mode);
9463 #endif
9464 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
9465 int err;
9466 #ifdef HAVE_FCHOWN
9467 err = fchown(fw, st.st_uid, st.st_gid);
9468 #else
9469 err = chown(fn, st.st_uid, st.st_gid);
9470 #endif
9471 if (err && getuid() == 0 && st2.st_uid == 0) {
9472 const char *wkfn = RSTRING_PTR(filename);
9473 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
9474 filename, str, strerror(errno));
9475 (void)close(fr);
9476 (void)close(fw);
9477 (void)unlink(wkfn);
9478 goto retry;
9481 #endif
9482 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
9483 rb_ractor_stdout_set(write_io);
9484 if (stdout_binmode) rb_io_binmode(rb_stdout);
9486 fmode = FMODE_READABLE;
9487 if (!ARGF.binmode) {
9488 fmode |= DEFAULT_TEXTMODE;
9490 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
9491 if (!NIL_P(write_io)) {
9492 rb_io_set_write_io(ARGF.current_file, write_io);
9494 RB_GC_GUARD(filename);
9496 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
9497 GetOpenFile(ARGF.current_file, fptr);
9498 if (ARGF.encs.enc) {
9499 fptr->encs = ARGF.encs;
9500 clear_codeconv(fptr);
9502 else {
9503 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
9504 if (!ARGF.binmode) {
9505 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
9506 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9507 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9508 #endif
9511 ARGF.next_p = 0;
9513 else {
9514 ARGF.next_p = 1;
9515 return FALSE;
9518 else if (ARGF.next_p == -1) {
9519 ARGF.current_file = rb_stdin;
9520 ARGF.filename = rb_str_new2("-");
9521 if (ARGF.inplace) {
9522 rb_warn("Can't do inplace edit for stdio");
9523 rb_ractor_stdout_set(orig_stdout);
9526 if (ARGF.init_p == -1) ARGF.init_p = 1;
9527 return TRUE;
9530 static VALUE
9531 argf_getline(int argc, VALUE *argv, VALUE argf)
9533 VALUE line;
9534 long lineno = ARGF.lineno;
9536 retry:
9537 if (!next_argv()) return Qnil;
9538 if (ARGF_GENERIC_INPUT_P()) {
9539 line = forward_current(idGets, argc, argv);
9541 else {
9542 if (argc == 0 && rb_rs == rb_default_rs) {
9543 line = rb_io_gets(ARGF.current_file);
9545 else {
9546 line = rb_io_getline(argc, argv, ARGF.current_file);
9548 if (NIL_P(line) && ARGF.next_p != -1) {
9549 argf_close(argf);
9550 ARGF.next_p = 1;
9551 goto retry;
9554 if (!NIL_P(line)) {
9555 ARGF.lineno = ++lineno;
9556 ARGF.last_lineno = ARGF.lineno;
9558 return line;
9561 static VALUE
9562 argf_lineno_getter(ID id, VALUE *var)
9564 VALUE argf = *var;
9565 return INT2FIX(ARGF.last_lineno);
9568 static void
9569 argf_lineno_setter(VALUE val, ID id, VALUE *var)
9571 VALUE argf = *var;
9572 int n = NUM2INT(val);
9573 ARGF.last_lineno = ARGF.lineno = n;
9576 static VALUE argf_gets(int, VALUE *, VALUE);
9579 * call-seq:
9580 * gets(sep=$/ [, getline_args]) -> string or nil
9581 * gets(limit [, getline_args]) -> string or nil
9582 * gets(sep, limit [, getline_args]) -> string or nil
9584 * Returns (and assigns to <code>$_</code>) the next line from the list
9585 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
9586 * no files are present on the command line. Returns +nil+ at end of
9587 * file. The optional argument specifies the record separator. The
9588 * separator is included with the contents of each record. A separator
9589 * of +nil+ reads the entire contents, and a zero-length separator
9590 * reads the input one paragraph at a time, where paragraphs are
9591 * divided by two consecutive newlines. If the first argument is an
9592 * integer, or optional second argument is given, the returning string
9593 * would not be longer than the given value in bytes. If multiple
9594 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
9595 * the contents one file at a time.
9597 * ARGV << "testfile"
9598 * print while gets
9600 * <em>produces:</em>
9602 * This is line one
9603 * This is line two
9604 * This is line three
9605 * And so on...
9607 * The style of programming using <code>$_</code> as an implicit
9608 * parameter is gradually losing favor in the Ruby community.
9611 static VALUE
9612 rb_f_gets(int argc, VALUE *argv, VALUE recv)
9614 if (recv == argf) {
9615 return argf_gets(argc, argv, argf);
9617 return forward(argf, idGets, argc, argv);
9621 * call-seq:
9622 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
9623 * ARGF.gets(limit [, getline_args]) -> string or nil
9624 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
9626 * Returns the next line from the current file in +ARGF+.
9628 * By default lines are assumed to be separated by <code>$/</code>;
9629 * to use a different character as a separator, supply it as a +String+
9630 * for the _sep_ argument.
9632 * The optional _limit_ argument specifies how many characters of each line
9633 * to return. By default all characters are returned.
9635 * See IO.readlines for details about getline_args.
9638 static VALUE
9639 argf_gets(int argc, VALUE *argv, VALUE argf)
9641 VALUE line;
9643 line = argf_getline(argc, argv, argf);
9644 rb_lastline_set(line);
9646 return line;
9649 VALUE
9650 rb_gets(void)
9652 VALUE line;
9654 if (rb_rs != rb_default_rs) {
9655 return rb_f_gets(0, 0, argf);
9658 retry:
9659 if (!next_argv()) return Qnil;
9660 line = rb_io_gets(ARGF.current_file);
9661 if (NIL_P(line) && ARGF.next_p != -1) {
9662 rb_io_close(ARGF.current_file);
9663 ARGF.next_p = 1;
9664 goto retry;
9666 rb_lastline_set(line);
9667 if (!NIL_P(line)) {
9668 ARGF.lineno++;
9669 ARGF.last_lineno = ARGF.lineno;
9672 return line;
9675 static VALUE argf_readline(int, VALUE *, VALUE);
9678 * call-seq:
9679 * readline(sep=$/) -> string
9680 * readline(limit) -> string
9681 * readline(sep, limit) -> string
9683 * Equivalent to Kernel::gets, except
9684 * +readline+ raises +EOFError+ at end of file.
9687 static VALUE
9688 rb_f_readline(int argc, VALUE *argv, VALUE recv)
9690 if (recv == argf) {
9691 return argf_readline(argc, argv, argf);
9693 return forward(argf, rb_intern("readline"), argc, argv);
9698 * call-seq:
9699 * ARGF.readline(sep=$/) -> string
9700 * ARGF.readline(limit) -> string
9701 * ARGF.readline(sep, limit) -> string
9703 * Returns the next line from the current file in +ARGF+.
9705 * By default lines are assumed to be separated by <code>$/</code>;
9706 * to use a different character as a separator, supply it as a +String+
9707 * for the _sep_ argument.
9709 * The optional _limit_ argument specifies how many characters of each line
9710 * to return. By default all characters are returned.
9712 * An +EOFError+ is raised at the end of the file.
9714 static VALUE
9715 argf_readline(int argc, VALUE *argv, VALUE argf)
9717 VALUE line;
9719 if (!next_argv()) rb_eof_error();
9720 ARGF_FORWARD(argc, argv);
9721 line = argf_gets(argc, argv, argf);
9722 if (NIL_P(line)) {
9723 rb_eof_error();
9726 return line;
9729 static VALUE argf_readlines(int, VALUE *, VALUE);
9732 * call-seq:
9733 * readlines(sep=$/) -> array
9734 * readlines(limit) -> array
9735 * readlines(sep, limit) -> array
9737 * Returns an array containing the lines returned by calling
9738 * <code>Kernel.gets(<i>sep</i>)</code> until the end of file.
9741 static VALUE
9742 rb_f_readlines(int argc, VALUE *argv, VALUE recv)
9744 if (recv == argf) {
9745 return argf_readlines(argc, argv, argf);
9747 return forward(argf, rb_intern("readlines"), argc, argv);
9751 * call-seq:
9752 * ARGF.readlines(sep=$/) -> array
9753 * ARGF.readlines(limit) -> array
9754 * ARGF.readlines(sep, limit) -> array
9756 * ARGF.to_a(sep=$/) -> array
9757 * ARGF.to_a(limit) -> array
9758 * ARGF.to_a(sep, limit) -> array
9760 * Reads +ARGF+'s current file in its entirety, returning an +Array+ of its
9761 * lines, one line per element. Lines are assumed to be separated by _sep_.
9763 * lines = ARGF.readlines
9764 * lines[0] #=> "This is line one\n"
9766 static VALUE
9767 argf_readlines(int argc, VALUE *argv, VALUE argf)
9769 long lineno = ARGF.lineno;
9770 VALUE lines, ary;
9772 ary = rb_ary_new();
9773 while (next_argv()) {
9774 if (ARGF_GENERIC_INPUT_P()) {
9775 lines = forward_current(rb_intern("readlines"), argc, argv);
9777 else {
9778 lines = rb_io_readlines(argc, argv, ARGF.current_file);
9779 argf_close(argf);
9781 ARGF.next_p = 1;
9782 rb_ary_concat(ary, lines);
9783 ARGF.lineno = lineno + RARRAY_LEN(ary);
9784 ARGF.last_lineno = ARGF.lineno;
9786 ARGF.init_p = 0;
9787 return ary;
9791 * call-seq:
9792 * `cmd` -> string
9794 * Returns the standard output of running _cmd_ in a subshell.
9795 * The built-in syntax <code>%x{...}</code> uses
9796 * this method. Sets <code>$?</code> to the process status.
9798 * `date` #=> "Wed Apr 9 08:56:30 CDT 2003\n"
9799 * `ls testdir`.split[1] #=> "main.rb"
9800 * `echo oops && exit 99` #=> "oops\n"
9801 * $?.exitstatus #=> 99
9804 static VALUE
9805 rb_f_backquote(VALUE obj, VALUE str)
9807 VALUE port;
9808 VALUE result;
9809 rb_io_t *fptr;
9811 SafeStringValue(str);
9812 rb_last_status_clear();
9813 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
9814 if (NIL_P(port)) return rb_str_new(0,0);
9816 GetOpenFile(port, fptr);
9817 result = read_all(fptr, remain_size(fptr), Qnil);
9818 rb_io_close(port);
9819 RFILE(port)->fptr = NULL;
9820 rb_io_fptr_finalize(fptr);
9821 RB_GC_GUARD(port);
9823 return result;
9826 #ifdef HAVE_SYS_SELECT_H
9827 #include <sys/select.h>
9828 #endif
9830 static VALUE
9831 select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
9833 VALUE res, list;
9834 rb_fdset_t *rp, *wp, *ep;
9835 rb_io_t *fptr;
9836 long i;
9837 int max = 0, n;
9838 int pending = 0;
9839 struct timeval timerec;
9841 if (!NIL_P(read)) {
9842 Check_Type(read, T_ARRAY);
9843 for (i=0; i<RARRAY_LEN(read); i++) {
9844 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
9845 rb_fd_set(fptr->fd, &fds[0]);
9846 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
9847 pending++;
9848 rb_fd_set(fptr->fd, &fds[3]);
9850 if (max < fptr->fd) max = fptr->fd;
9852 if (pending) { /* no blocking if there's buffered data */
9853 timerec.tv_sec = timerec.tv_usec = 0;
9854 tp = &timerec;
9856 rp = &fds[0];
9858 else
9859 rp = 0;
9861 if (!NIL_P(write)) {
9862 Check_Type(write, T_ARRAY);
9863 for (i=0; i<RARRAY_LEN(write); i++) {
9864 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
9865 GetOpenFile(write_io, fptr);
9866 rb_fd_set(fptr->fd, &fds[1]);
9867 if (max < fptr->fd) max = fptr->fd;
9869 wp = &fds[1];
9871 else
9872 wp = 0;
9874 if (!NIL_P(except)) {
9875 Check_Type(except, T_ARRAY);
9876 for (i=0; i<RARRAY_LEN(except); i++) {
9877 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
9878 VALUE write_io = GetWriteIO(io);
9879 GetOpenFile(io, fptr);
9880 rb_fd_set(fptr->fd, &fds[2]);
9881 if (max < fptr->fd) max = fptr->fd;
9882 if (io != write_io) {
9883 GetOpenFile(write_io, fptr);
9884 rb_fd_set(fptr->fd, &fds[2]);
9885 if (max < fptr->fd) max = fptr->fd;
9888 ep = &fds[2];
9890 else {
9891 ep = 0;
9894 max++;
9896 n = rb_thread_fd_select(max, rp, wp, ep, tp);
9897 if (n < 0) {
9898 rb_sys_fail(0);
9900 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
9902 res = rb_ary_new2(3);
9903 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
9904 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
9905 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
9907 if (rp) {
9908 list = RARRAY_AREF(res, 0);
9909 for (i=0; i< RARRAY_LEN(read); i++) {
9910 VALUE obj = rb_ary_entry(read, i);
9911 VALUE io = rb_io_get_io(obj);
9912 GetOpenFile(io, fptr);
9913 if (rb_fd_isset(fptr->fd, &fds[0]) ||
9914 rb_fd_isset(fptr->fd, &fds[3])) {
9915 rb_ary_push(list, obj);
9920 if (wp) {
9921 list = RARRAY_AREF(res, 1);
9922 for (i=0; i< RARRAY_LEN(write); i++) {
9923 VALUE obj = rb_ary_entry(write, i);
9924 VALUE io = rb_io_get_io(obj);
9925 VALUE write_io = GetWriteIO(io);
9926 GetOpenFile(write_io, fptr);
9927 if (rb_fd_isset(fptr->fd, &fds[1])) {
9928 rb_ary_push(list, obj);
9933 if (ep) {
9934 list = RARRAY_AREF(res, 2);
9935 for (i=0; i< RARRAY_LEN(except); i++) {
9936 VALUE obj = rb_ary_entry(except, i);
9937 VALUE io = rb_io_get_io(obj);
9938 VALUE write_io = GetWriteIO(io);
9939 GetOpenFile(io, fptr);
9940 if (rb_fd_isset(fptr->fd, &fds[2])) {
9941 rb_ary_push(list, obj);
9943 else if (io != write_io) {
9944 GetOpenFile(write_io, fptr);
9945 if (rb_fd_isset(fptr->fd, &fds[2])) {
9946 rb_ary_push(list, obj);
9952 return res; /* returns an empty array on interrupt */
9955 struct select_args {
9956 VALUE read, write, except;
9957 struct timeval *timeout;
9958 rb_fdset_t fdsets[4];
9961 static VALUE
9962 select_call(VALUE arg)
9964 struct select_args *p = (struct select_args *)arg;
9966 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
9969 static VALUE
9970 select_end(VALUE arg)
9972 struct select_args *p = (struct select_args *)arg;
9973 int i;
9975 for (i = 0; i < numberof(p->fdsets); ++i)
9976 rb_fd_term(&p->fdsets[i]);
9977 return Qnil;
9980 static VALUE sym_normal, sym_sequential, sym_random,
9981 sym_willneed, sym_dontneed, sym_noreuse;
9983 #ifdef HAVE_POSIX_FADVISE
9984 struct io_advise_struct {
9985 int fd;
9986 int advice;
9987 off_t offset;
9988 off_t len;
9991 static VALUE
9992 io_advise_internal(void *arg)
9994 struct io_advise_struct *ptr = arg;
9995 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
9998 static VALUE
9999 io_advise_sym_to_const(VALUE sym)
10001 #ifdef POSIX_FADV_NORMAL
10002 if (sym == sym_normal)
10003 return INT2NUM(POSIX_FADV_NORMAL);
10004 #endif
10006 #ifdef POSIX_FADV_RANDOM
10007 if (sym == sym_random)
10008 return INT2NUM(POSIX_FADV_RANDOM);
10009 #endif
10011 #ifdef POSIX_FADV_SEQUENTIAL
10012 if (sym == sym_sequential)
10013 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10014 #endif
10016 #ifdef POSIX_FADV_WILLNEED
10017 if (sym == sym_willneed)
10018 return INT2NUM(POSIX_FADV_WILLNEED);
10019 #endif
10021 #ifdef POSIX_FADV_DONTNEED
10022 if (sym == sym_dontneed)
10023 return INT2NUM(POSIX_FADV_DONTNEED);
10024 #endif
10026 #ifdef POSIX_FADV_NOREUSE
10027 if (sym == sym_noreuse)
10028 return INT2NUM(POSIX_FADV_NOREUSE);
10029 #endif
10031 return Qnil;
10034 static VALUE
10035 do_io_advise(rb_io_t *fptr, VALUE advice, off_t offset, off_t len)
10037 int rv;
10038 struct io_advise_struct ias;
10039 VALUE num_adv;
10041 num_adv = io_advise_sym_to_const(advice);
10044 * The platform doesn't support this hint. We don't raise exception, instead
10045 * silently ignore it. Because IO::advise is only hint.
10047 if (NIL_P(num_adv))
10048 return Qnil;
10050 ias.fd = fptr->fd;
10051 ias.advice = NUM2INT(num_adv);
10052 ias.offset = offset;
10053 ias.len = len;
10055 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
10056 if (rv && rv != ENOSYS) {
10057 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10058 it returns the error code. */
10059 VALUE message = rb_sprintf("%"PRIsVALUE" "
10060 "(%"PRI_OFFT_PREFIX"d, "
10061 "%"PRI_OFFT_PREFIX"d, "
10062 "%"PRIsVALUE")",
10063 fptr->pathv, offset, len, advice);
10064 rb_syserr_fail_str(rv, message);
10067 return Qnil;
10070 #endif /* HAVE_POSIX_FADVISE */
10072 static void
10073 advice_arg_check(VALUE advice)
10075 if (!SYMBOL_P(advice))
10076 rb_raise(rb_eTypeError, "advice must be a Symbol");
10078 if (advice != sym_normal &&
10079 advice != sym_sequential &&
10080 advice != sym_random &&
10081 advice != sym_willneed &&
10082 advice != sym_dontneed &&
10083 advice != sym_noreuse) {
10084 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10089 * call-seq:
10090 * ios.advise(advice, offset=0, len=0) -> nil
10092 * Announce an intention to access data from the current file in a
10093 * specific pattern. On platforms that do not support the
10094 * <em>posix_fadvise(2)</em> system call, this method is a no-op.
10096 * _advice_ is one of the following symbols:
10098 * :normal:: No advice to give; the default assumption for an open file.
10099 * :sequential:: The data will be accessed sequentially
10100 * with lower offsets read before higher ones.
10101 * :random:: The data will be accessed in random order.
10102 * :willneed:: The data will be accessed in the near future.
10103 * :dontneed:: The data will not be accessed in the near future.
10104 * :noreuse:: The data will only be accessed once.
10106 * The semantics of a piece of advice are platform-dependent. See
10107 * <em>man 2 posix_fadvise</em> for details.
10109 * "data" means the region of the current file that begins at
10110 * _offset_ and extends for _len_ bytes. If _len_ is 0, the region
10111 * ends at the last byte of the file. By default, both _offset_ and
10112 * _len_ are 0, meaning that the advice applies to the entire file.
10114 * If an error occurs, one of the following exceptions will be raised:
10116 * IOError:: The IO stream is closed.
10117 * Errno::EBADF::
10118 * The file descriptor of the current file is invalid.
10119 * Errno::EINVAL:: An invalid value for _advice_ was given.
10120 * Errno::ESPIPE::
10121 * The file descriptor of the current file refers to a FIFO or
10122 * pipe. (Linux raises Errno::EINVAL in this case).
10123 * TypeError::
10124 * Either _advice_ was not a Symbol, or one of the
10125 * other arguments was not an Integer.
10126 * RangeError:: One of the arguments given was too big/small.
10128 * This list is not exhaustive; other Errno:: exceptions are also possible.
10130 static VALUE
10131 rb_io_advise(int argc, VALUE *argv, VALUE io)
10133 VALUE advice, offset, len;
10134 off_t off, l;
10135 rb_io_t *fptr;
10137 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10138 advice_arg_check(advice);
10140 io = GetWriteIO(io);
10141 GetOpenFile(io, fptr);
10143 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10144 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10146 #ifdef HAVE_POSIX_FADVISE
10147 return do_io_advise(fptr, advice, off, l);
10148 #else
10149 ((void)off, (void)l); /* Ignore all hint */
10150 return Qnil;
10151 #endif
10155 * call-seq:
10156 * IO.select(read_array [, write_array [, error_array [, timeout]]]) -> array or nil
10158 * Calls select(2) system call.
10159 * It monitors given arrays of IO objects, waits until one or more of
10160 * IO objects are ready for reading, are ready for writing, and have
10161 * pending exceptions respectively, and returns an array that contains
10162 * arrays of those IO objects. It will return +nil+ if optional
10163 * <i>timeout</i> value is given and no IO object is ready in
10164 * <i>timeout</i> seconds.
10166 * IO.select peeks the buffer of IO objects for testing readability.
10167 * If the IO buffer is not empty, IO.select immediately notifies
10168 * readability. This "peek" only happens for IO objects. It does not
10169 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10171 * The best way to use IO.select is invoking it after nonblocking
10172 * methods such as #read_nonblock, #write_nonblock, etc. The methods
10173 * raise an exception which is extended by IO::WaitReadable or
10174 * IO::WaitWritable. The modules notify how the caller should wait
10175 * with IO.select. If IO::WaitReadable is raised, the caller should
10176 * wait for reading. If IO::WaitWritable is raised, the caller should
10177 * wait for writing.
10179 * So, blocking read (#readpartial) can be emulated using
10180 * #read_nonblock and IO.select as follows:
10182 * begin
10183 * result = io_like.read_nonblock(maxlen)
10184 * rescue IO::WaitReadable
10185 * IO.select([io_like])
10186 * retry
10187 * rescue IO::WaitWritable
10188 * IO.select(nil, [io_like])
10189 * retry
10190 * end
10192 * Especially, the combination of nonblocking methods and IO.select is
10193 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
10194 * has #to_io method to return underlying IO object. IO.select calls
10195 * #to_io to obtain the file descriptor to wait.
10197 * This means that readability notified by IO.select doesn't mean
10198 * readability from OpenSSL::SSL::SSLSocket object.
10200 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
10201 * some data. IO.select doesn't see the buffer. So IO.select can
10202 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
10204 * However, several more complicated situations exist.
10206 * SSL is a protocol which is sequence of records.
10207 * The record consists of multiple bytes.
10208 * So, the remote side of SSL sends a partial record, IO.select
10209 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
10210 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
10212 * Also, the remote side can request SSL renegotiation which forces
10213 * the local SSL engine to write some data.
10214 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
10215 * system call and it can block.
10216 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
10217 * IO::WaitWritable instead of blocking.
10218 * So, the caller should wait for ready for writability as above
10219 * example.
10221 * The combination of nonblocking methods and IO.select is also useful
10222 * for streams such as tty, pipe socket socket when multiple processes
10223 * read from a stream.
10225 * Finally, Linux kernel developers don't guarantee that
10226 * readability of select(2) means readability of following read(2) even
10227 * for a single process.
10228 * See select(2) manual on GNU/Linux system.
10230 * Invoking IO.select before IO#readpartial works well as usual.
10231 * However it is not the best way to use IO.select.
10233 * The writability notified by select(2) doesn't show
10234 * how many bytes are writable.
10235 * IO#write method blocks until given whole string is written.
10236 * So, <code>IO#write(two or more bytes)</code> can block after
10237 * writability is notified by IO.select. IO#write_nonblock is required
10238 * to avoid the blocking.
10240 * Blocking write (#write) can be emulated using #write_nonblock and
10241 * IO.select as follows: IO::WaitReadable should also be rescued for
10242 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
10244 * while 0 < string.bytesize
10245 * begin
10246 * written = io_like.write_nonblock(string)
10247 * rescue IO::WaitReadable
10248 * IO.select([io_like])
10249 * retry
10250 * rescue IO::WaitWritable
10251 * IO.select(nil, [io_like])
10252 * retry
10253 * end
10254 * string = string.byteslice(written..-1)
10255 * end
10257 * === Parameters
10258 * read_array:: an array of IO objects that wait until ready for read
10259 * write_array:: an array of IO objects that wait until ready for write
10260 * error_array:: an array of IO objects that wait for exceptions
10261 * timeout:: a numeric value in second
10263 * === Example
10265 * rp, wp = IO.pipe
10266 * mesg = "ping "
10267 * 100.times {
10268 * # IO.select follows IO#read. Not the best way to use IO.select.
10269 * rs, ws, = IO.select([rp], [wp])
10270 * if r = rs[0]
10271 * ret = r.read(5)
10272 * print ret
10273 * case ret
10274 * when /ping/
10275 * mesg = "pong\n"
10276 * when /pong/
10277 * mesg = "ping "
10278 * end
10279 * end
10280 * if w = ws[0]
10281 * w.write(mesg)
10282 * end
10285 * <em>produces:</em>
10287 * ping pong
10288 * ping pong
10289 * ping pong
10290 * (snipped)
10291 * ping
10294 static VALUE
10295 rb_f_select(int argc, VALUE *argv, VALUE obj)
10297 VALUE timeout;
10298 struct select_args args;
10299 struct timeval timerec;
10300 int i;
10302 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
10303 if (NIL_P(timeout)) {
10304 args.timeout = 0;
10306 else {
10307 timerec = rb_time_interval(timeout);
10308 args.timeout = &timerec;
10311 for (i = 0; i < numberof(args.fdsets); ++i)
10312 rb_fd_init(&args.fdsets[i]);
10314 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
10317 #ifdef IOCTL_REQ_TYPE
10318 typedef IOCTL_REQ_TYPE ioctl_req_t;
10319 #else
10320 typedef int ioctl_req_t;
10321 # define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
10322 #endif
10324 #ifdef HAVE_IOCTL
10325 struct ioctl_arg {
10326 int fd;
10327 ioctl_req_t cmd;
10328 long narg;
10331 static VALUE
10332 nogvl_ioctl(void *ptr)
10334 struct ioctl_arg *arg = ptr;
10336 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
10339 static int
10340 do_ioctl(int fd, ioctl_req_t cmd, long narg)
10342 int retval;
10343 struct ioctl_arg arg;
10345 arg.fd = fd;
10346 arg.cmd = cmd;
10347 arg.narg = narg;
10349 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
10351 return retval;
10353 #endif
10355 #define DEFAULT_IOCTL_NARG_LEN (256)
10357 #if defined(__linux__) && defined(_IOC_SIZE)
10358 static long
10359 linux_iocparm_len(ioctl_req_t cmd)
10361 long len;
10363 if ((cmd & 0xFFFF0000) == 0) {
10364 /* legacy and unstructured ioctl number. */
10365 return DEFAULT_IOCTL_NARG_LEN;
10368 len = _IOC_SIZE(cmd);
10370 /* paranoia check for silly drivers which don't keep ioctl convention */
10371 if (len < DEFAULT_IOCTL_NARG_LEN)
10372 len = DEFAULT_IOCTL_NARG_LEN;
10374 return len;
10376 #endif
10378 #ifdef HAVE_IOCTL
10379 static long
10380 ioctl_narg_len(ioctl_req_t cmd)
10382 long len;
10384 #ifdef IOCPARM_MASK
10385 #ifndef IOCPARM_LEN
10386 #define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
10387 #endif
10388 #endif
10389 #ifdef IOCPARM_LEN
10390 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
10391 #elif defined(__linux__) && defined(_IOC_SIZE)
10392 len = linux_iocparm_len(cmd);
10393 #else
10394 /* otherwise guess at what's safe */
10395 len = DEFAULT_IOCTL_NARG_LEN;
10396 #endif
10398 return len;
10400 #endif
10402 #ifdef HAVE_FCNTL
10403 #ifdef __linux__
10404 typedef long fcntl_arg_t;
10405 #else
10406 /* posix */
10407 typedef int fcntl_arg_t;
10408 #endif
10410 static long
10411 fcntl_narg_len(ioctl_req_t cmd)
10413 long len;
10415 switch (cmd) {
10416 #ifdef F_DUPFD
10417 case F_DUPFD:
10418 len = sizeof(fcntl_arg_t);
10419 break;
10420 #endif
10421 #ifdef F_DUP2FD /* bsd specific */
10422 case F_DUP2FD:
10423 len = sizeof(int);
10424 break;
10425 #endif
10426 #ifdef F_DUPFD_CLOEXEC /* linux specific */
10427 case F_DUPFD_CLOEXEC:
10428 len = sizeof(fcntl_arg_t);
10429 break;
10430 #endif
10431 #ifdef F_GETFD
10432 case F_GETFD:
10433 len = 1;
10434 break;
10435 #endif
10436 #ifdef F_SETFD
10437 case F_SETFD:
10438 len = sizeof(fcntl_arg_t);
10439 break;
10440 #endif
10441 #ifdef F_GETFL
10442 case F_GETFL:
10443 len = 1;
10444 break;
10445 #endif
10446 #ifdef F_SETFL
10447 case F_SETFL:
10448 len = sizeof(fcntl_arg_t);
10449 break;
10450 #endif
10451 #ifdef F_GETOWN
10452 case F_GETOWN:
10453 len = 1;
10454 break;
10455 #endif
10456 #ifdef F_SETOWN
10457 case F_SETOWN:
10458 len = sizeof(fcntl_arg_t);
10459 break;
10460 #endif
10461 #ifdef F_GETOWN_EX /* linux specific */
10462 case F_GETOWN_EX:
10463 len = sizeof(struct f_owner_ex);
10464 break;
10465 #endif
10466 #ifdef F_SETOWN_EX /* linux specific */
10467 case F_SETOWN_EX:
10468 len = sizeof(struct f_owner_ex);
10469 break;
10470 #endif
10471 #ifdef F_GETLK
10472 case F_GETLK:
10473 len = sizeof(struct flock);
10474 break;
10475 #endif
10476 #ifdef F_SETLK
10477 case F_SETLK:
10478 len = sizeof(struct flock);
10479 break;
10480 #endif
10481 #ifdef F_SETLKW
10482 case F_SETLKW:
10483 len = sizeof(struct flock);
10484 break;
10485 #endif
10486 #ifdef F_READAHEAD /* bsd specific */
10487 case F_READAHEAD:
10488 len = sizeof(int);
10489 break;
10490 #endif
10491 #ifdef F_RDAHEAD /* Darwin specific */
10492 case F_RDAHEAD:
10493 len = sizeof(int);
10494 break;
10495 #endif
10496 #ifdef F_GETSIG /* linux specific */
10497 case F_GETSIG:
10498 len = 1;
10499 break;
10500 #endif
10501 #ifdef F_SETSIG /* linux specific */
10502 case F_SETSIG:
10503 len = sizeof(fcntl_arg_t);
10504 break;
10505 #endif
10506 #ifdef F_GETLEASE /* linux specific */
10507 case F_GETLEASE:
10508 len = 1;
10509 break;
10510 #endif
10511 #ifdef F_SETLEASE /* linux specific */
10512 case F_SETLEASE:
10513 len = sizeof(fcntl_arg_t);
10514 break;
10515 #endif
10516 #ifdef F_NOTIFY /* linux specific */
10517 case F_NOTIFY:
10518 len = sizeof(fcntl_arg_t);
10519 break;
10520 #endif
10522 default:
10523 len = 256;
10524 break;
10527 return len;
10529 #else /* HAVE_FCNTL */
10530 static long
10531 fcntl_narg_len(ioctl_req_t cmd)
10533 return 0;
10535 #endif /* HAVE_FCNTL */
10537 #define NARG_SENTINEL 17
10539 static long
10540 setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
10542 long narg = 0;
10543 VALUE arg = *argp;
10545 if (!RTEST(arg)) {
10546 narg = 0;
10548 else if (FIXNUM_P(arg)) {
10549 narg = FIX2LONG(arg);
10551 else if (arg == Qtrue) {
10552 narg = 1;
10554 else {
10555 VALUE tmp = rb_check_string_type(arg);
10557 if (NIL_P(tmp)) {
10558 narg = NUM2LONG(arg);
10560 else {
10561 char *ptr;
10562 long len, slen;
10564 *argp = arg = tmp;
10565 len = narg_len(cmd);
10566 rb_str_modify(arg);
10568 slen = RSTRING_LEN(arg);
10569 /* expand for data + sentinel. */
10570 if (slen < len+1) {
10571 rb_str_resize(arg, len+1);
10572 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
10573 slen = len+1;
10575 /* a little sanity check here */
10576 ptr = RSTRING_PTR(arg);
10577 ptr[slen - 1] = NARG_SENTINEL;
10578 narg = (long)(SIGNED_VALUE)ptr;
10582 return narg;
10585 static VALUE
10586 finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
10588 if (retval < 0) rb_sys_fail_path(fptr->pathv);
10589 if (RB_TYPE_P(arg, T_STRING)) {
10590 char *ptr;
10591 long slen;
10592 RSTRING_GETMEM(arg, ptr, slen);
10593 if (ptr[slen-1] != NARG_SENTINEL)
10594 rb_raise(rb_eArgError, "return value overflowed string");
10595 ptr[slen-1] = '\0';
10598 return INT2NUM(retval);
10601 #ifdef HAVE_IOCTL
10602 static VALUE
10603 rb_ioctl(VALUE io, VALUE req, VALUE arg)
10605 ioctl_req_t cmd = NUM2IOCTLREQ(req);
10606 rb_io_t *fptr;
10607 long narg;
10608 int retval;
10610 narg = setup_narg(cmd, &arg, ioctl_narg_len);
10611 GetOpenFile(io, fptr);
10612 retval = do_ioctl(fptr->fd, cmd, narg);
10613 return finish_narg(retval, arg, fptr);
10617 * call-seq:
10618 * ios.ioctl(integer_cmd, arg) -> integer
10620 * Provides a mechanism for issuing low-level commands to control or
10621 * query I/O devices. Arguments and results are platform dependent. If
10622 * <i>arg</i> is a number, its value is passed directly. If it is a
10623 * string, it is interpreted as a binary sequence of bytes. On Unix
10624 * platforms, see <code>ioctl(2)</code> for details. Not implemented on
10625 * all platforms.
10628 static VALUE
10629 rb_io_ioctl(int argc, VALUE *argv, VALUE io)
10631 VALUE req, arg;
10633 rb_scan_args(argc, argv, "11", &req, &arg);
10634 return rb_ioctl(io, req, arg);
10636 #else
10637 #define rb_io_ioctl rb_f_notimplement
10638 #endif
10640 #ifdef HAVE_FCNTL
10641 struct fcntl_arg {
10642 int fd;
10643 int cmd;
10644 long narg;
10647 static VALUE
10648 nogvl_fcntl(void *ptr)
10650 struct fcntl_arg *arg = ptr;
10652 #if defined(F_DUPFD)
10653 if (arg->cmd == F_DUPFD)
10654 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
10655 #endif
10656 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
10659 static int
10660 do_fcntl(int fd, int cmd, long narg)
10662 int retval;
10663 struct fcntl_arg arg;
10665 arg.fd = fd;
10666 arg.cmd = cmd;
10667 arg.narg = narg;
10669 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
10670 if (retval != -1) {
10671 switch (cmd) {
10672 #if defined(F_DUPFD)
10673 case F_DUPFD:
10674 #endif
10675 #if defined(F_DUPFD_CLOEXEC)
10676 case F_DUPFD_CLOEXEC:
10677 #endif
10678 rb_update_max_fd(retval);
10682 return retval;
10685 static VALUE
10686 rb_fcntl(VALUE io, VALUE req, VALUE arg)
10688 int cmd = NUM2INT(req);
10689 rb_io_t *fptr;
10690 long narg;
10691 int retval;
10693 narg = setup_narg(cmd, &arg, fcntl_narg_len);
10694 GetOpenFile(io, fptr);
10695 retval = do_fcntl(fptr->fd, cmd, narg);
10696 return finish_narg(retval, arg, fptr);
10700 * call-seq:
10701 * ios.fcntl(integer_cmd, arg) -> integer
10703 * Provides a mechanism for issuing low-level commands to control or
10704 * query file-oriented I/O streams. Arguments and results are platform
10705 * dependent. If <i>arg</i> is a number, its value is passed
10706 * directly. If it is a string, it is interpreted as a binary sequence
10707 * of bytes (Array#pack might be a useful way to build this string). On
10708 * Unix platforms, see <code>fcntl(2)</code> for details. Not
10709 * implemented on all platforms.
10712 static VALUE
10713 rb_io_fcntl(int argc, VALUE *argv, VALUE io)
10715 VALUE req, arg;
10717 rb_scan_args(argc, argv, "11", &req, &arg);
10718 return rb_fcntl(io, req, arg);
10720 #else
10721 #define rb_io_fcntl rb_f_notimplement
10722 #endif
10724 #if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
10726 * call-seq:
10727 * syscall(num [, args...]) -> integer
10729 * Calls the operating system function identified by _num_ and
10730 * returns the result of the function or raises SystemCallError if
10731 * it failed.
10733 * Arguments for the function can follow _num_. They must be either
10734 * +String+ objects or +Integer+ objects. A +String+ object is passed
10735 * as a pointer to the byte sequence. An +Integer+ object is passed
10736 * as an integer whose bit size is the same as a pointer.
10737 * Up to nine parameters may be passed.
10739 * The function identified by _num_ is system
10740 * dependent. On some Unix systems, the numbers may be obtained from a
10741 * header file called <code>syscall.h</code>.
10743 * syscall 4, 1, "hello\n", 6 # '4' is write(2) on our box
10745 * <em>produces:</em>
10747 * hello
10749 * Calling +syscall+ on a platform which does not have any way to
10750 * an arbitrary system function just fails with NotImplementedError.
10752 * *Note:*
10753 * +syscall+ is essentially unsafe and unportable.
10754 * Feel free to shoot your foot.
10755 * The DL (Fiddle) library is preferred for safer and a bit
10756 * more portable programming.
10759 static VALUE
10760 rb_f_syscall(int argc, VALUE *argv, VALUE _)
10762 VALUE arg[8];
10763 #if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
10764 # define SYSCALL __syscall
10765 # define NUM2SYSCALLID(x) NUM2LONG(x)
10766 # define RETVAL2NUM(x) LONG2NUM(x)
10767 # if SIZEOF_LONG == 8
10768 long num, retval = -1;
10769 # elif SIZEOF_LONG_LONG == 8
10770 long long num, retval = -1;
10771 # else
10772 # error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
10773 # endif
10774 #elif defined(__linux__)
10775 # define SYSCALL syscall
10776 # define NUM2SYSCALLID(x) NUM2LONG(x)
10777 # define RETVAL2NUM(x) LONG2NUM(x)
10779 * Linux man page says, syscall(2) function prototype is below.
10781 * int syscall(int number, ...);
10783 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
10785 long num, retval = -1;
10786 #else
10787 # define SYSCALL syscall
10788 # define NUM2SYSCALLID(x) NUM2INT(x)
10789 # define RETVAL2NUM(x) INT2NUM(x)
10790 int num, retval = -1;
10791 #endif
10792 int i;
10794 if (RTEST(ruby_verbose)) {
10795 rb_category_warning(RB_WARN_CATEGORY_DEPRECATED,
10796 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
10799 if (argc == 0)
10800 rb_raise(rb_eArgError, "too few arguments for syscall");
10801 if (argc > numberof(arg))
10802 rb_raise(rb_eArgError, "too many arguments for syscall");
10803 num = NUM2SYSCALLID(argv[0]); ++argv;
10804 for (i = argc - 1; i--; ) {
10805 VALUE v = rb_check_string_type(argv[i]);
10807 if (!NIL_P(v)) {
10808 SafeStringValue(v);
10809 rb_str_modify(v);
10810 arg[i] = (VALUE)StringValueCStr(v);
10812 else {
10813 arg[i] = (VALUE)NUM2LONG(argv[i]);
10817 switch (argc) {
10818 case 1:
10819 retval = SYSCALL(num);
10820 break;
10821 case 2:
10822 retval = SYSCALL(num, arg[0]);
10823 break;
10824 case 3:
10825 retval = SYSCALL(num, arg[0],arg[1]);
10826 break;
10827 case 4:
10828 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
10829 break;
10830 case 5:
10831 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
10832 break;
10833 case 6:
10834 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
10835 break;
10836 case 7:
10837 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
10838 break;
10839 case 8:
10840 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
10841 break;
10844 if (retval == -1)
10845 rb_sys_fail(0);
10846 return RETVAL2NUM(retval);
10847 #undef SYSCALL
10848 #undef NUM2SYSCALLID
10849 #undef RETVAL2NUM
10851 #else
10852 #define rb_f_syscall rb_f_notimplement
10853 #endif
10855 static VALUE
10856 io_new_instance(VALUE args)
10858 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
10861 static rb_encoding *
10862 find_encoding(VALUE v)
10864 rb_encoding *enc = rb_find_encoding(v);
10865 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
10866 return enc;
10869 static void
10870 io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
10872 rb_encoding *enc, *enc2;
10873 int ecflags = fptr->encs.ecflags;
10874 VALUE ecopts, tmp;
10876 if (!NIL_P(v2)) {
10877 enc2 = find_encoding(v1);
10878 tmp = rb_check_string_type(v2);
10879 if (!NIL_P(tmp)) {
10880 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
10881 /* Special case - "-" => no transcoding */
10882 enc = enc2;
10883 enc2 = NULL;
10885 else
10886 enc = find_encoding(v2);
10887 if (enc == enc2) {
10888 /* Special case - "-" => no transcoding */
10889 enc2 = NULL;
10892 else {
10893 enc = find_encoding(v2);
10894 if (enc == enc2) {
10895 /* Special case - "-" => no transcoding */
10896 enc2 = NULL;
10899 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10900 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
10902 else {
10903 if (NIL_P(v1)) {
10904 /* Set to default encodings */
10905 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
10906 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10907 ecopts = Qnil;
10909 else {
10910 tmp = rb_check_string_type(v1);
10911 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
10912 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
10913 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10914 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
10916 else {
10917 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
10918 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10919 ecopts = Qnil;
10923 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
10924 fptr->encs.enc = enc;
10925 fptr->encs.enc2 = enc2;
10926 fptr->encs.ecflags = ecflags;
10927 fptr->encs.ecopts = ecopts;
10928 clear_codeconv(fptr);
10932 struct io_encoding_set_args {
10933 rb_io_t *fptr;
10934 VALUE v1;
10935 VALUE v2;
10936 VALUE opt;
10939 static VALUE
10940 io_encoding_set_v(VALUE v)
10942 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
10943 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
10944 return Qnil;
10947 static VALUE
10948 pipe_pair_close(VALUE rw)
10950 VALUE *rwp = (VALUE *)rw;
10951 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
10955 * call-seq:
10956 * IO.pipe -> [read_io, write_io]
10957 * IO.pipe(ext_enc) -> [read_io, write_io]
10958 * IO.pipe("ext_enc:int_enc" [, opt]) -> [read_io, write_io]
10959 * IO.pipe(ext_enc, int_enc [, opt]) -> [read_io, write_io]
10961 * IO.pipe(...) {|read_io, write_io| ... }
10963 * Creates a pair of pipe endpoints (connected to each other) and
10964 * returns them as a two-element array of IO objects:
10965 * <code>[</code> <i>read_io</i>, <i>write_io</i> <code>]</code>.
10967 * If a block is given, the block is called and
10968 * returns the value of the block.
10969 * <i>read_io</i> and <i>write_io</i> are sent to the block as arguments.
10970 * If read_io and write_io are not closed when the block exits, they are closed.
10971 * i.e. closing read_io and/or write_io doesn't cause an error.
10973 * Not available on all platforms.
10975 * If an encoding (encoding name or encoding object) is specified as an optional argument,
10976 * read string from pipe is tagged with the encoding specified.
10977 * If the argument is a colon separated two encoding names "A:B",
10978 * the read string is converted from encoding A (external encoding)
10979 * to encoding B (internal encoding), then tagged with B.
10980 * If two optional arguments are specified, those must be
10981 * encoding objects or encoding names,
10982 * and the first one is the external encoding,
10983 * and the second one is the internal encoding.
10984 * If the external encoding and the internal encoding is specified,
10985 * optional hash argument specify the conversion option.
10987 * In the example below, the two processes close the ends of the pipe
10988 * that they are not using. This is not just a cosmetic nicety. The
10989 * read end of a pipe will not generate an end of file condition if
10990 * there are any writers with the pipe still open. In the case of the
10991 * parent process, the <code>rd.read</code> will never return if it
10992 * does not first issue a <code>wr.close</code>.
10994 * rd, wr = IO.pipe
10996 * if fork
10997 * wr.close
10998 * puts "Parent got: <#{rd.read}>"
10999 * rd.close
11000 * Process.wait
11001 * else
11002 * rd.close
11003 * puts "Sending message to parent"
11004 * wr.write "Hi Dad"
11005 * wr.close
11006 * end
11008 * <em>produces:</em>
11010 * Sending message to parent
11011 * Parent got: <Hi Dad>
11014 static VALUE
11015 rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11017 int pipes[2], state;
11018 VALUE r, w, args[3], v1, v2;
11019 VALUE opt;
11020 rb_io_t *fptr, *fptr2;
11021 struct io_encoding_set_args ies_args;
11022 int fmode = 0;
11023 VALUE ret;
11025 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11026 if (rb_pipe(pipes) < 0)
11027 rb_sys_fail(0);
11029 args[0] = klass;
11030 args[1] = INT2NUM(pipes[0]);
11031 args[2] = INT2FIX(O_RDONLY);
11032 r = rb_protect(io_new_instance, (VALUE)args, &state);
11033 if (state) {
11034 close(pipes[0]);
11035 close(pipes[1]);
11036 rb_jump_tag(state);
11038 GetOpenFile(r, fptr);
11040 ies_args.fptr = fptr;
11041 ies_args.v1 = v1;
11042 ies_args.v2 = v2;
11043 ies_args.opt = opt;
11044 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11045 if (state) {
11046 close(pipes[1]);
11047 io_close(r);
11048 rb_jump_tag(state);
11051 args[1] = INT2NUM(pipes[1]);
11052 args[2] = INT2FIX(O_WRONLY);
11053 w = rb_protect(io_new_instance, (VALUE)args, &state);
11054 if (state) {
11055 close(pipes[1]);
11056 if (!NIL_P(r)) rb_io_close(r);
11057 rb_jump_tag(state);
11059 GetOpenFile(w, fptr2);
11060 rb_io_synchronized(fptr2);
11062 extract_binmode(opt, &fmode);
11064 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11065 rb_io_ascii8bit_binmode(r);
11066 rb_io_ascii8bit_binmode(w);
11069 #if DEFAULT_TEXTMODE
11070 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11071 fptr->mode &= ~FMODE_TEXTMODE;
11072 setmode(fptr->fd, O_BINARY);
11074 #if RUBY_CRLF_ENVIRONMENT
11075 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
11076 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
11078 #endif
11079 #endif
11080 fptr->mode |= fmode;
11081 #if DEFAULT_TEXTMODE
11082 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11083 fptr2->mode &= ~FMODE_TEXTMODE;
11084 setmode(fptr2->fd, O_BINARY);
11086 #endif
11087 fptr2->mode |= fmode;
11089 ret = rb_assoc_new(r, w);
11090 if (rb_block_given_p()) {
11091 VALUE rw[2];
11092 rw[0] = r;
11093 rw[1] = w;
11094 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11096 return ret;
11099 struct foreach_arg {
11100 int argc;
11101 VALUE *argv;
11102 VALUE io;
11105 static void
11106 open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11108 VALUE path, v;
11109 VALUE vmode = Qnil, vperm = Qnil;
11111 path = *argv++;
11112 argc--;
11113 FilePathValue(path);
11114 arg->io = 0;
11115 arg->argc = argc;
11116 arg->argv = argv;
11117 if (NIL_P(opt)) {
11118 vmode = INT2NUM(O_RDONLY);
11119 vperm = INT2FIX(0666);
11121 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11122 int n;
11124 v = rb_to_array_type(v);
11125 n = RARRAY_LENINT(v);
11126 rb_check_arity(n, 0, 3); /* rb_io_open */
11127 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11129 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11132 static VALUE
11133 io_s_foreach(VALUE v)
11135 struct getline_arg *arg = (void *)v;
11136 VALUE str;
11138 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11139 rb_lastline_set(str);
11140 rb_yield(str);
11142 rb_lastline_set(Qnil);
11143 return Qnil;
11147 * call-seq:
11148 * IO.foreach(name, sep=$/ [, getline_args, open_args]) {|line| block } -> nil
11149 * IO.foreach(name, limit [, getline_args, open_args]) {|line| block } -> nil
11150 * IO.foreach(name, sep, limit [, getline_args, open_args]) {|line| block } -> nil
11151 * IO.foreach(...) -> an_enumerator
11152 * File.foreach(name, sep=$/ [, getline_args, open_args]) {|line| block } -> nil
11153 * File.foreach(name, limit [, getline_args, open_args]) {|line| block } -> nil
11154 * File.foreach(name, sep, limit [, getline_args, open_args]) {|line| block } -> nil
11155 * File.foreach(...) -> an_enumerator
11157 * Executes the block for every line in the named I/O port, where lines
11158 * are separated by <em>sep</em>.
11160 * If no block is given, an enumerator is returned instead.
11162 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11163 * is the IO class, a subprocess is created in the same way as Kernel#open,
11164 * and each line in its output is yielded.
11165 * Consider to use File.foreach to disable the behavior of subprocess invocation.
11167 * File.foreach("testfile") {|x| print "GOT ", x }
11168 * IO.foreach("| cat testfile") {|x| print "GOT ", x }
11170 * <em>produces:</em>
11172 * GOT This is line one
11173 * GOT This is line two
11174 * GOT This is line three
11175 * GOT And so on...
11177 * If the last argument is a hash, it's the keyword argument to open.
11178 * See IO.readlines for details about getline_args.
11179 * And see also IO.read for details about open_args.
11183 static VALUE
11184 rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
11186 VALUE opt;
11187 int orig_argc = argc;
11188 struct foreach_arg arg;
11189 struct getline_arg garg;
11191 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
11192 RETURN_ENUMERATOR(self, orig_argc, argv);
11193 extract_getline_args(argc-1, argv+1, &garg);
11194 open_key_args(self, argc, argv, opt, &arg);
11195 if (NIL_P(arg.io)) return Qnil;
11196 extract_getline_opts(opt, &garg);
11197 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
11198 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
11201 static VALUE
11202 io_s_readlines(VALUE v)
11204 struct getline_arg *arg = (void *)v;
11205 return io_readlines(arg, arg->io);
11209 * call-seq:
11210 * IO.readlines(name, sep=$/ [, getline_args, open_args]) -> array
11211 * IO.readlines(name, limit [, getline_args, open_args]) -> array
11212 * IO.readlines(name, sep, limit [, getline_args, open_args]) -> array
11213 * File.readlines(name, sep=$/ [, getline_args, open_args]) -> array
11214 * File.readlines(name, limit [, getline_args, open_args]) -> array
11215 * File.readlines(name, sep, limit [, getline_args, open_args]) -> array
11217 * Reads the entire file specified by <i>name</i> as individual
11218 * lines, and returns those lines in an array. Lines are separated by
11219 * <i>sep</i>.
11221 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11222 * is the IO class, a subprocess is created in the same way as Kernel#open,
11223 * and each line in its output is yielded.
11224 * Consider to use File.readlines to disable the behavior of subprocess invocation.
11226 * a = File.readlines("testfile")
11227 * a[0] #=> "This is line one\n"
11229 * b = File.readlines("testfile", chomp: true)
11230 * b[0] #=> "This is line one"
11232 * IO.readlines("|ls -a") #=> [".\n", "..\n", ...]
11234 * If the last argument is a hash, it's the keyword argument to open.
11236 * === Options for getline
11238 * The options hash accepts the following keys:
11240 * :chomp::
11241 * When the optional +chomp+ keyword argument has a true value,
11242 * <code>\n</code>, <code>\r</code>, and <code>\r\n</code>
11243 * will be removed from the end of each line.
11245 * See also IO.read for details about +name+ and open_args.
11248 static VALUE
11249 rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
11251 VALUE opt;
11252 struct foreach_arg arg;
11253 struct getline_arg garg;
11255 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
11256 extract_getline_args(argc-1, argv+1, &garg);
11257 open_key_args(io, argc, argv, opt, &arg);
11258 if (NIL_P(arg.io)) return Qnil;
11259 extract_getline_opts(opt, &garg);
11260 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
11261 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
11264 static VALUE
11265 io_s_read(VALUE v)
11267 struct foreach_arg *arg = (void *)v;
11268 return io_read(arg->argc, arg->argv, arg->io);
11271 struct seek_arg {
11272 VALUE io;
11273 VALUE offset;
11274 int mode;
11277 static VALUE
11278 seek_before_access(VALUE argp)
11280 struct seek_arg *arg = (struct seek_arg *)argp;
11281 rb_io_binmode(arg->io);
11282 return rb_io_seek(arg->io, arg->offset, arg->mode);
11286 * call-seq:
11287 * IO.read(name, [length [, offset]] [, opt]) -> string
11288 * File.read(name, [length [, offset]] [, opt]) -> string
11290 * Opens the file, optionally seeks to the given +offset+, then returns
11291 * +length+ bytes (defaulting to the rest of the file). #read ensures
11292 * the file is closed before returning.
11294 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11295 * is the IO class, a subprocess is created in the same way as Kernel#open,
11296 * and its output is returned.
11297 * Consider to use File.read to disable the behavior of subprocess invocation.
11299 * === Options
11301 * The options hash accepts the following keys:
11303 * :encoding::
11304 * string or encoding
11306 * Specifies the encoding of the read string. +:encoding+ will be ignored
11307 * if +length+ is specified. See Encoding.aliases for possible encodings.
11309 * :mode::
11310 * string or integer
11312 * Specifies the <i>mode</i> argument for open(). It must start
11313 * with an "r", otherwise it will cause an error.
11314 * See IO.new for the list of possible modes.
11316 * :open_args::
11317 * array
11319 * Specifies arguments for open() as an array. This key can not be used
11320 * in combination with either +:encoding+ or +:mode+.
11322 * Examples:
11324 * File.read("testfile") #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
11325 * File.read("testfile", 20) #=> "This is line one\nThi"
11326 * File.read("testfile", 20, 10) #=> "ne one\nThis is line "
11327 * File.read("binfile", mode: "rb") #=> "\xF7\x00\x00\x0E\x12"
11328 * IO.read("|ls -a") #=> ".\n..\n"...
11331 static VALUE
11332 rb_io_s_read(int argc, VALUE *argv, VALUE io)
11334 VALUE opt, offset;
11335 struct foreach_arg arg;
11337 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
11338 open_key_args(io, argc, argv, opt, &arg);
11339 if (NIL_P(arg.io)) return Qnil;
11340 if (!NIL_P(offset)) {
11341 struct seek_arg sarg;
11342 int state = 0;
11343 sarg.io = arg.io;
11344 sarg.offset = offset;
11345 sarg.mode = SEEK_SET;
11346 rb_protect(seek_before_access, (VALUE)&sarg, &state);
11347 if (state) {
11348 rb_io_close(arg.io);
11349 rb_jump_tag(state);
11351 if (arg.argc == 2) arg.argc = 1;
11353 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
11357 * call-seq:
11358 * IO.binread(name, [length [, offset]]) -> string
11359 * File.binread(name, [length [, offset]]) -> string
11361 * Opens the file, optionally seeks to the given <i>offset</i>, then
11362 * returns <i>length</i> bytes (defaulting to the rest of the file).
11363 * #binread ensures the file is closed before returning. The open mode
11364 * would be <code>"rb:ASCII-8BIT"</code>.
11366 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11367 * is the IO class, a subprocess is created in the same way as Kernel#open,
11368 * and its output is returned.
11369 * Consider to use File.binread to disable the behavior of subprocess invocation.
11371 * File.binread("testfile") #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
11372 * File.binread("testfile", 20) #=> "This is line one\nThi"
11373 * File.binread("testfile", 20, 10) #=> "ne one\nThis is line "
11374 * IO.binread("| cat testfile") #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
11376 * See also IO.read for details about +name+ and open_args.
11379 static VALUE
11380 rb_io_s_binread(int argc, VALUE *argv, VALUE io)
11382 VALUE offset;
11383 struct foreach_arg arg;
11384 enum {
11385 fmode = FMODE_READABLE|FMODE_BINMODE,
11386 oflags = O_RDONLY
11387 #ifdef O_BINARY
11388 |O_BINARY
11389 #endif
11391 convconfig_t convconfig = {NULL, NULL, 0, Qnil};
11393 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
11394 FilePathValue(argv[0]);
11395 convconfig.enc = rb_ascii8bit_encoding();
11396 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
11397 if (NIL_P(arg.io)) return Qnil;
11398 arg.argv = argv+1;
11399 arg.argc = (argc > 1) ? 1 : 0;
11400 if (!NIL_P(offset)) {
11401 struct seek_arg sarg;
11402 int state = 0;
11403 sarg.io = arg.io;
11404 sarg.offset = offset;
11405 sarg.mode = SEEK_SET;
11406 rb_protect(seek_before_access, (VALUE)&sarg, &state);
11407 if (state) {
11408 rb_io_close(arg.io);
11409 rb_jump_tag(state);
11412 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
11415 static VALUE
11416 io_s_write0(VALUE v)
11418 struct write_arg *arg = (void *)v;
11419 return io_write(arg->io,arg->str,arg->nosync);
11422 static VALUE
11423 io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
11425 VALUE string, offset, opt;
11426 struct foreach_arg arg;
11427 struct write_arg warg;
11429 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
11431 if (NIL_P(opt)) opt = rb_hash_new();
11432 else opt = rb_hash_dup(opt);
11435 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
11436 int mode = O_WRONLY|O_CREAT;
11437 #ifdef O_BINARY
11438 if (binary) mode |= O_BINARY;
11439 #endif
11440 if (NIL_P(offset)) mode |= O_TRUNC;
11441 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
11443 open_key_args(klass, argc, argv, opt, &arg);
11445 #ifndef O_BINARY
11446 if (binary) rb_io_binmode_m(arg.io);
11447 #endif
11449 if (NIL_P(arg.io)) return Qnil;
11450 if (!NIL_P(offset)) {
11451 struct seek_arg sarg;
11452 int state = 0;
11453 sarg.io = arg.io;
11454 sarg.offset = offset;
11455 sarg.mode = SEEK_SET;
11456 rb_protect(seek_before_access, (VALUE)&sarg, &state);
11457 if (state) {
11458 rb_io_close(arg.io);
11459 rb_jump_tag(state);
11463 warg.io = arg.io;
11464 warg.str = string;
11465 warg.nosync = 0;
11467 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
11471 * call-seq:
11472 * IO.write(name, string [, offset]) -> integer
11473 * IO.write(name, string [, offset] [, opt]) -> integer
11474 * File.write(name, string [, offset]) -> integer
11475 * File.write(name, string [, offset] [, opt]) -> integer
11477 * Opens the file, optionally seeks to the given <i>offset</i>, writes
11478 * <i>string</i>, then returns the length written. #write ensures the
11479 * file is closed before returning. If <i>offset</i> is not given in
11480 * write mode, the file is truncated. Otherwise, it is not truncated.
11482 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11483 * is the IO class, a subprocess is created in the same way as Kernel#open,
11484 * and its output is printed to the standard output.
11485 * Consider to use File.write to disable the behavior of subprocess invocation.
11487 * File.write("testfile", "0123456789", 20) #=> 10
11488 * # File could contain: "This is line one\nThi0123456789two\nThis is line three\nAnd so on...\n"
11489 * File.write("testfile", "0123456789") #=> 10
11490 * # File would now read: "0123456789"
11491 * IO.write("|tr a-z A-Z", "abc") #=> 3
11492 * # Prints "ABC" to the standard output
11494 * If the last argument is a hash, it specifies options for the internal
11495 * open(). It accepts the following keys:
11497 * :encoding::
11498 * string or encoding
11500 * Specifies the encoding of the read string.
11501 * See Encoding.aliases for possible encodings.
11503 * :mode::
11504 * string or integer
11506 * Specifies the <i>mode</i> argument for open(). It must start
11507 * with "w", "a", or "r+", otherwise it will cause an error.
11508 * See IO.new for the list of possible modes.
11510 * :perm::
11511 * integer
11513 * Specifies the <i>perm</i> argument for open().
11515 * :open_args::
11516 * array
11518 * Specifies arguments for open() as an array.
11519 * This key can not be used in combination with other keys.
11521 * See also IO.read for details about +name+ and open_args.
11524 static VALUE
11525 rb_io_s_write(int argc, VALUE *argv, VALUE io)
11527 return io_s_write(argc, argv, io, 0);
11531 * call-seq:
11532 * IO.binwrite(name, string, [offset]) -> integer
11533 * IO.binwrite(name, string, [offset], open_args) -> integer
11534 * File.binwrite(name, string, [offset]) -> integer
11535 * File.binwrite(name, string, [offset], open_args) -> integer
11537 * Same as IO.write except opening the file in binary mode and
11538 * ASCII-8BIT encoding (<code>"wb:ASCII-8BIT"</code>).
11540 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11541 * is the IO class, a subprocess is created in the same way as Kernel#open,
11542 * and its output is printed to the standard output.
11543 * Consider to use File.binwrite to disable the behavior of subprocess invocation.
11545 * See also IO.read for details about +name+ and open_args.
11548 static VALUE
11549 rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
11551 return io_s_write(argc, argv, io, 1);
11554 struct copy_stream_struct {
11555 VALUE src;
11556 VALUE dst;
11557 off_t copy_length; /* (off_t)-1 if not specified */
11558 off_t src_offset; /* (off_t)-1 if not specified */
11560 rb_io_t *src_fptr;
11561 rb_io_t *dst_fptr;
11562 unsigned close_src : 1;
11563 unsigned close_dst : 1;
11564 int error_no;
11565 off_t total;
11566 const char *syserr;
11567 const char *notimp;
11568 VALUE th;
11569 struct stat src_stat;
11570 struct stat dst_stat;
11571 #ifdef HAVE_FCOPYFILE
11572 copyfile_state_t copyfile_state;
11573 #endif
11576 static void *
11577 exec_interrupts(void *arg)
11579 VALUE th = (VALUE)arg;
11580 rb_thread_execute_interrupts(th);
11581 return NULL;
11585 * returns TRUE if the preceding system call was interrupted
11586 * so we can continue. If the thread was interrupted, we
11587 * reacquire the GVL to execute interrupts before continuing.
11589 static int
11590 maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
11592 switch (errno) {
11593 case EINTR:
11594 #if defined(ERESTART)
11595 case ERESTART:
11596 #endif
11597 if (rb_thread_interrupted(stp->th)) {
11598 if (has_gvl)
11599 rb_thread_execute_interrupts(stp->th);
11600 else
11601 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
11603 return TRUE;
11605 return FALSE;
11608 struct wait_for_single_fd {
11609 VALUE scheduler;
11611 rb_io_t *fptr;
11612 short events;
11614 VALUE result;
11617 static void *
11618 rb_thread_fiber_scheduler_wait_for(void * _args)
11620 struct wait_for_single_fd *args = (struct wait_for_single_fd *)_args;
11622 args->result = rb_fiber_scheduler_io_wait(args->scheduler, args->fptr->self, INT2NUM(args->events), Qnil);
11624 return NULL;
11627 #if USE_POLL
11628 # define IOWAIT_SYSCALL "poll"
11629 STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
11630 STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
11631 static int
11632 nogvl_wait_for(VALUE th, rb_io_t *fptr, short events)
11634 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
11635 if (scheduler != Qnil) {
11636 struct wait_for_single_fd args = {.scheduler = scheduler, .fptr = fptr, .events = events};
11637 rb_thread_call_with_gvl(rb_thread_fiber_scheduler_wait_for, &args);
11638 return RTEST(args.result);
11641 int fd = fptr->fd;
11642 if (fd == -1) return 0;
11644 struct pollfd fds;
11646 fds.fd = fd;
11647 fds.events = events;
11649 return poll(&fds, 1, -1);
11651 #else /* !USE_POLL */
11652 # define IOWAIT_SYSCALL "select"
11653 static int
11654 nogvl_wait_for(VALUE th, rb_io_t *fptr, short events)
11656 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
11657 if (scheduler != Qnil) {
11658 struct wait_for_single_fd args = {.scheduler = scheduler, .fptr = fptr, .events = events};
11659 rb_thread_call_with_gvl(rb_thread_fiber_scheduler_wait_for, &args);
11660 return RTEST(args.result);
11663 int fd = fptr->fd;
11664 if (fd == -1) return 0;
11666 rb_fdset_t fds;
11667 int ret;
11669 rb_fd_init(&fds);
11670 rb_fd_set(fd, &fds);
11672 switch (events) {
11673 case RB_WAITFD_IN:
11674 ret = rb_fd_select(fd + 1, &fds, 0, 0, 0);
11675 break;
11676 case RB_WAITFD_OUT:
11677 ret = rb_fd_select(fd + 1, 0, &fds, 0, 0);
11678 break;
11679 default:
11680 VM_UNREACHABLE(nogvl_wait_for);
11683 rb_fd_term(&fds);
11684 return ret;
11686 #endif /* !USE_POLL */
11688 static int
11689 maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
11691 int ret;
11693 do {
11694 if (has_gvl) {
11695 ret = RB_NUM2INT(rb_io_wait(stp->src, RB_INT2NUM(RUBY_IO_READABLE), Qnil));
11697 else {
11698 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN);
11700 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
11702 if (ret < 0) {
11703 stp->syserr = IOWAIT_SYSCALL;
11704 stp->error_no = errno;
11705 return ret;
11707 return 0;
11710 static int
11711 nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
11713 int ret;
11715 do {
11716 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT);
11717 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
11719 if (ret < 0) {
11720 stp->syserr = IOWAIT_SYSCALL;
11721 stp->error_no = errno;
11722 return ret;
11724 return 0;
11727 #ifdef USE_COPY_FILE_RANGE
11729 static ssize_t
11730 simple_copy_file_range(int in_fd, off_t *in_offset, int out_fd, off_t *out_offset, size_t count, unsigned int flags)
11732 #ifdef HAVE_COPY_FILE_RANGE
11733 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
11734 #else
11735 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
11736 #endif
11739 static int
11740 nogvl_copy_file_range(struct copy_stream_struct *stp)
11742 ssize_t ss;
11743 off_t src_size;
11744 off_t copy_length, src_offset, *src_offset_ptr;
11746 if (!S_ISREG(stp->src_stat.st_mode))
11747 return 0;
11749 src_size = stp->src_stat.st_size;
11750 src_offset = stp->src_offset;
11751 if (src_offset >= (off_t)0) {
11752 src_offset_ptr = &src_offset;
11754 else {
11755 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
11758 copy_length = stp->copy_length;
11759 if (copy_length < (off_t)0) {
11760 if (src_offset < (off_t)0) {
11761 off_t current_offset;
11762 errno = 0;
11763 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
11764 if (current_offset < (off_t)0 && errno) {
11765 stp->syserr = "lseek";
11766 stp->error_no = errno;
11767 return (int)current_offset;
11769 copy_length = src_size - current_offset;
11771 else {
11772 copy_length = src_size - src_offset;
11776 retry_copy_file_range:
11777 # if SIZEOF_OFF_T > SIZEOF_SIZE_T
11778 /* we are limited by the 32-bit ssize_t return value on 32-bit */
11779 ss = (copy_length > (off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
11780 # else
11781 ss = (ssize_t)copy_length;
11782 # endif
11783 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
11784 if (0 < ss) {
11785 stp->total += ss;
11786 copy_length -= ss;
11787 if (0 < copy_length) {
11788 goto retry_copy_file_range;
11791 if (ss < 0) {
11792 if (maygvl_copy_stream_continue_p(0, stp)) {
11793 goto retry_copy_file_range;
11795 switch (errno) {
11796 case EINVAL:
11797 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
11798 docker container) */
11799 #ifdef ENOSYS
11800 case ENOSYS:
11801 #endif
11802 #ifdef EXDEV
11803 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
11804 #endif
11805 return 0;
11806 case EAGAIN:
11807 #if EWOULDBLOCK != EAGAIN
11808 case EWOULDBLOCK:
11809 #endif
11811 int ret = nogvl_copy_stream_wait_write(stp);
11812 if (ret < 0) return ret;
11814 goto retry_copy_file_range;
11815 case EBADF:
11817 int e = errno;
11818 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
11820 if (flags != -1 && flags & O_APPEND) {
11821 return 0;
11823 errno = e;
11826 stp->syserr = "copy_file_range";
11827 stp->error_no = errno;
11828 return (int)ss;
11830 return 1;
11832 #endif
11834 #ifdef HAVE_FCOPYFILE
11835 static int
11836 nogvl_fcopyfile(struct copy_stream_struct *stp)
11838 off_t cur, ss = 0;
11839 const off_t src_offset = stp->src_offset;
11840 int ret;
11842 if (stp->copy_length >= (off_t)0) {
11843 /* copy_length can't be specified in fcopyfile(3) */
11844 return 0;
11847 if (!S_ISREG(stp->src_stat.st_mode))
11848 return 0;
11850 if (!S_ISREG(stp->dst_stat.st_mode))
11851 return 0;
11852 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (off_t)0) /* if dst IO was already written */
11853 return 0;
11854 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
11855 /* fcopyfile(3) appends src IO to dst IO and then truncates
11856 * dst IO to src IO's original size. */
11857 off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
11858 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
11859 if (end > (off_t)0) return 0;
11862 if (src_offset > (off_t)0) {
11863 off_t r;
11865 /* get current offset */
11866 errno = 0;
11867 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
11868 if (cur < (off_t)0 && errno) {
11869 stp->error_no = errno;
11870 return 1;
11873 errno = 0;
11874 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
11875 if (r < (off_t)0 && errno) {
11876 stp->error_no = errno;
11877 return 1;
11881 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
11882 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
11883 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
11885 if (ret == 0) { /* success */
11886 stp->total = ss;
11887 if (src_offset > (off_t)0) {
11888 off_t r;
11889 errno = 0;
11890 /* reset offset */
11891 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
11892 if (r < (off_t)0 && errno) {
11893 stp->error_no = errno;
11894 return 1;
11898 else {
11899 switch (errno) {
11900 case ENOTSUP:
11901 case EPERM:
11902 case EINVAL:
11903 return 0;
11905 stp->syserr = "fcopyfile";
11906 stp->error_no = errno;
11907 return (int)ret;
11909 return 1;
11911 #endif
11913 #ifdef HAVE_SENDFILE
11915 # ifdef __linux__
11916 # define USE_SENDFILE
11918 # ifdef HAVE_SYS_SENDFILE_H
11919 # include <sys/sendfile.h>
11920 # endif
11922 static ssize_t
11923 simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count)
11925 return sendfile(out_fd, in_fd, offset, (size_t)count);
11928 # elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
11929 /* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
11930 * without cpuset -l 0.
11932 # define USE_SENDFILE
11934 static ssize_t
11935 simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count)
11937 int r;
11938 off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
11939 off_t sbytes;
11940 # ifdef __APPLE__
11941 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
11942 sbytes = count;
11943 # else
11944 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
11945 # endif
11946 if (r != 0 && sbytes == 0) return r;
11947 if (offset) {
11948 *offset += sbytes;
11950 else {
11951 lseek(in_fd, sbytes, SEEK_CUR);
11953 return (ssize_t)sbytes;
11956 # endif
11958 #endif
11960 #ifdef USE_SENDFILE
11961 static int
11962 nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
11964 ssize_t ss;
11965 off_t src_size;
11966 off_t copy_length;
11967 off_t src_offset;
11968 int use_pread;
11970 if (!S_ISREG(stp->src_stat.st_mode))
11971 return 0;
11973 src_size = stp->src_stat.st_size;
11974 #ifndef __linux__
11975 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
11976 return 0;
11977 #endif
11979 src_offset = stp->src_offset;
11980 use_pread = src_offset >= (off_t)0;
11982 copy_length = stp->copy_length;
11983 if (copy_length < (off_t)0) {
11984 if (use_pread)
11985 copy_length = src_size - src_offset;
11986 else {
11987 off_t cur;
11988 errno = 0;
11989 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
11990 if (cur < (off_t)0 && errno) {
11991 stp->syserr = "lseek";
11992 stp->error_no = errno;
11993 return (int)cur;
11995 copy_length = src_size - cur;
11999 retry_sendfile:
12000 # if SIZEOF_OFF_T > SIZEOF_SIZE_T
12001 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12002 ss = (copy_length > (off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12003 # else
12004 ss = (ssize_t)copy_length;
12005 # endif
12006 if (use_pread) {
12007 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12009 else {
12010 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12012 if (0 < ss) {
12013 stp->total += ss;
12014 copy_length -= ss;
12015 if (0 < copy_length) {
12016 goto retry_sendfile;
12019 if (ss < 0) {
12020 if (maygvl_copy_stream_continue_p(0, stp))
12021 goto retry_sendfile;
12022 switch (errno) {
12023 case EINVAL:
12024 #ifdef ENOSYS
12025 case ENOSYS:
12026 #endif
12027 #ifdef EOPNOTSUP
12028 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12029 see also: [Feature #16965] */
12030 case EOPNOTSUP:
12031 #endif
12032 return 0;
12033 case EAGAIN:
12034 #if EWOULDBLOCK != EAGAIN
12035 case EWOULDBLOCK:
12036 #endif
12038 int ret;
12039 #ifndef __linux__
12041 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12042 * select() reports regular files to always be "ready", so
12043 * there is no need to select() on it.
12044 * Other OSes may have the same limitation for sendfile() which
12045 * allow us to bypass maygvl_copy_stream_wait_read()...
12047 ret = maygvl_copy_stream_wait_read(0, stp);
12048 if (ret < 0) return ret;
12049 #endif
12050 ret = nogvl_copy_stream_wait_write(stp);
12051 if (ret < 0) return ret;
12053 goto retry_sendfile;
12055 stp->syserr = "sendfile";
12056 stp->error_no = errno;
12057 return (int)ss;
12059 return 1;
12061 #endif
12063 static ssize_t
12064 maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12066 if (has_gvl)
12067 return rb_read_internal(fptr, buf, count);
12068 else
12069 return read(fptr->fd, buf, count);
12072 static ssize_t
12073 maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, off_t offset)
12075 ssize_t ss;
12076 retry_read:
12077 if (offset < (off_t)0) {
12078 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12080 else {
12081 #ifdef HAVE_PREAD
12082 ss = pread(stp->src_fptr->fd, buf, len, offset);
12083 #else
12084 stp->notimp = "pread";
12085 return -1;
12086 #endif
12088 if (ss == 0) {
12089 return 0;
12091 if (ss < 0) {
12092 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12093 goto retry_read;
12094 switch (errno) {
12095 case EAGAIN:
12096 #if EWOULDBLOCK != EAGAIN
12097 case EWOULDBLOCK:
12098 #endif
12100 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12101 if (ret < 0) return ret;
12103 goto retry_read;
12104 #ifdef ENOSYS
12105 case ENOSYS:
12106 stp->notimp = "pread";
12107 return ss;
12108 #endif
12110 stp->syserr = offset < (off_t)0 ? "read" : "pread";
12111 stp->error_no = errno;
12113 return ss;
12116 static int
12117 nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
12119 ssize_t ss;
12120 int off = 0;
12121 while (len) {
12122 ss = write(stp->dst_fptr->fd, buf+off, len);
12123 if (ss < 0) {
12124 if (maygvl_copy_stream_continue_p(0, stp))
12125 continue;
12126 if (io_again_p(errno)) {
12127 int ret = nogvl_copy_stream_wait_write(stp);
12128 if (ret < 0) return ret;
12129 continue;
12131 stp->syserr = "write";
12132 stp->error_no = errno;
12133 return (int)ss;
12135 off += (int)ss;
12136 len -= (int)ss;
12137 stp->total += ss;
12139 return 0;
12142 static void
12143 nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
12145 char buf[1024*16];
12146 size_t len;
12147 ssize_t ss;
12148 int ret;
12149 off_t copy_length;
12150 int use_eof;
12151 off_t src_offset;
12152 int use_pread;
12154 copy_length = stp->copy_length;
12155 use_eof = copy_length < (off_t)0;
12156 src_offset = stp->src_offset;
12157 use_pread = src_offset >= (off_t)0;
12159 if (use_pread && stp->close_src) {
12160 off_t r;
12161 errno = 0;
12162 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12163 if (r < (off_t)0 && errno) {
12164 stp->syserr = "lseek";
12165 stp->error_no = errno;
12166 return;
12168 src_offset = (off_t)-1;
12169 use_pread = 0;
12172 while (use_eof || 0 < copy_length) {
12173 if (!use_eof && copy_length < (off_t)sizeof(buf)) {
12174 len = (size_t)copy_length;
12176 else {
12177 len = sizeof(buf);
12179 if (use_pread) {
12180 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
12181 if (0 < ss)
12182 src_offset += ss;
12184 else {
12185 ss = maygvl_copy_stream_read(0, stp, buf, len, (off_t)-1);
12187 if (ss <= 0) /* EOF or error */
12188 return;
12190 ret = nogvl_copy_stream_write(stp, buf, ss);
12191 if (ret < 0)
12192 return;
12194 if (!use_eof)
12195 copy_length -= ss;
12199 static void *
12200 nogvl_copy_stream_func(void *arg)
12202 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
12203 #if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
12204 int ret;
12205 #endif
12207 #ifdef USE_COPY_FILE_RANGE
12208 ret = nogvl_copy_file_range(stp);
12209 if (ret != 0)
12210 goto finish; /* error or success */
12211 #endif
12213 #ifdef HAVE_FCOPYFILE
12214 ret = nogvl_fcopyfile(stp);
12215 if (ret != 0)
12216 goto finish; /* error or success */
12217 #endif
12219 #ifdef USE_SENDFILE
12220 ret = nogvl_copy_stream_sendfile(stp);
12221 if (ret != 0)
12222 goto finish; /* error or success */
12223 #endif
12225 nogvl_copy_stream_read_write(stp);
12227 #if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
12228 finish:
12229 #endif
12230 return 0;
12233 static VALUE
12234 copy_stream_fallback_body(VALUE arg)
12236 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
12237 const int buflen = 16*1024;
12238 VALUE n;
12239 VALUE buf = rb_str_buf_new(buflen);
12240 off_t rest = stp->copy_length;
12241 off_t off = stp->src_offset;
12242 ID read_method = id_readpartial;
12244 if (!stp->src_fptr) {
12245 if (!rb_respond_to(stp->src, read_method)) {
12246 read_method = id_read;
12250 while (1) {
12251 long numwrote;
12252 long l;
12253 if (stp->copy_length < (off_t)0) {
12254 l = buflen;
12256 else {
12257 if (rest == 0) {
12258 rb_str_resize(buf, 0);
12259 break;
12261 l = buflen < rest ? buflen : (long)rest;
12263 if (!stp->src_fptr) {
12264 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
12266 if (read_method == id_read && NIL_P(rc))
12267 break;
12269 else {
12270 ssize_t ss;
12271 rb_str_resize(buf, buflen);
12272 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
12273 rb_str_resize(buf, ss > 0 ? ss : 0);
12274 if (ss < 0)
12275 return Qnil;
12276 if (ss == 0)
12277 rb_eof_error();
12278 if (off >= (off_t)0)
12279 off += ss;
12281 n = rb_io_write(stp->dst, buf);
12282 numwrote = NUM2LONG(n);
12283 stp->total += numwrote;
12284 rest -= numwrote;
12285 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
12286 break;
12290 return Qnil;
12293 static VALUE
12294 copy_stream_fallback(struct copy_stream_struct *stp)
12296 if (!stp->src_fptr && stp->src_offset >= (off_t)0) {
12297 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
12299 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
12300 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
12301 rb_eEOFError, (VALUE)0);
12302 return Qnil;
12305 static VALUE
12306 copy_stream_body(VALUE arg)
12308 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
12309 VALUE src_io = stp->src, dst_io = stp->dst;
12310 const int common_oflags = 0
12311 #ifdef O_NOCTTY
12312 | O_NOCTTY
12313 #endif
12316 stp->th = rb_thread_current();
12318 stp->total = 0;
12320 if (src_io == argf ||
12321 !(RB_TYPE_P(src_io, T_FILE) ||
12322 RB_TYPE_P(src_io, T_STRING) ||
12323 rb_respond_to(src_io, rb_intern("to_path")))) {
12324 stp->src_fptr = NULL;
12326 else {
12327 int stat_ret;
12328 VALUE tmp_io = rb_io_check_io(src_io);
12329 if (!NIL_P(tmp_io)) {
12330 src_io = tmp_io;
12332 else if (!RB_TYPE_P(src_io, T_FILE)) {
12333 VALUE args[2];
12334 FilePathValue(src_io);
12335 args[0] = src_io;
12336 args[1] = INT2NUM(O_RDONLY|common_oflags);
12337 src_io = rb_class_new_instance(2, args, rb_cFile);
12338 stp->src = src_io;
12339 stp->close_src = 1;
12341 RB_IO_POINTER(src_io, stp->src_fptr);
12342 rb_io_check_byte_readable(stp->src_fptr);
12344 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
12345 if (stat_ret < 0) {
12346 stp->syserr = "fstat";
12347 stp->error_no = errno;
12348 return Qnil;
12352 if (dst_io == argf ||
12353 !(RB_TYPE_P(dst_io, T_FILE) ||
12354 RB_TYPE_P(dst_io, T_STRING) ||
12355 rb_respond_to(dst_io, rb_intern("to_path")))) {
12356 stp->dst_fptr = NULL;
12358 else {
12359 int stat_ret;
12360 VALUE tmp_io = rb_io_check_io(dst_io);
12361 if (!NIL_P(tmp_io)) {
12362 dst_io = GetWriteIO(tmp_io);
12364 else if (!RB_TYPE_P(dst_io, T_FILE)) {
12365 VALUE args[3];
12366 FilePathValue(dst_io);
12367 args[0] = dst_io;
12368 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
12369 args[2] = INT2FIX(0666);
12370 dst_io = rb_class_new_instance(3, args, rb_cFile);
12371 stp->dst = dst_io;
12372 stp->close_dst = 1;
12374 else {
12375 dst_io = GetWriteIO(dst_io);
12376 stp->dst = dst_io;
12378 RB_IO_POINTER(dst_io, stp->dst_fptr);
12379 rb_io_check_writable(stp->dst_fptr);
12381 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
12382 if (stat_ret < 0) {
12383 stp->syserr = "fstat";
12384 stp->error_no = errno;
12385 return Qnil;
12389 #ifdef O_BINARY
12390 if (stp->src_fptr)
12391 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
12392 #endif
12393 if (stp->dst_fptr)
12394 io_ascii8bit_binmode(stp->dst_fptr);
12396 if (stp->src_offset < (off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
12397 size_t len = stp->src_fptr->rbuf.len;
12398 VALUE str;
12399 if (stp->copy_length >= (off_t)0 && stp->copy_length < (off_t)len) {
12400 len = (size_t)stp->copy_length;
12402 str = rb_str_buf_new(len);
12403 rb_str_resize(str,len);
12404 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
12405 if (stp->dst_fptr) { /* IO or filename */
12406 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
12407 rb_sys_fail_on_write(stp->dst_fptr);
12409 else /* others such as StringIO */
12410 rb_io_write(dst_io, str);
12411 rb_str_resize(str, 0);
12412 stp->total += len;
12413 if (stp->copy_length >= (off_t)0)
12414 stp->copy_length -= len;
12417 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
12418 rb_raise(rb_eIOError, "flush failed");
12421 if (stp->copy_length == 0)
12422 return Qnil;
12424 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
12425 return copy_stream_fallback(stp);
12428 rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
12429 return Qnil;
12432 static VALUE
12433 copy_stream_finalize(VALUE arg)
12435 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
12437 #ifdef HAVE_FCOPYFILE
12438 if (stp->copyfile_state) {
12439 copyfile_state_free(stp->copyfile_state);
12441 #endif
12443 if (stp->close_src) {
12444 rb_io_close_m(stp->src);
12446 if (stp->close_dst) {
12447 rb_io_close_m(stp->dst);
12449 if (stp->syserr) {
12450 rb_syserr_fail(stp->error_no, stp->syserr);
12452 if (stp->notimp) {
12453 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
12455 return Qnil;
12459 * call-seq:
12460 * IO.copy_stream(src, dst)
12461 * IO.copy_stream(src, dst, copy_length)
12462 * IO.copy_stream(src, dst, copy_length, src_offset)
12464 * IO.copy_stream copies <i>src</i> to <i>dst</i>.
12465 * <i>src</i> and <i>dst</i> is either a filename or an IO-like object.
12466 * IO-like object for <i>src</i> should have #readpartial or #read
12467 * method. IO-like object for <i>dst</i> should have #write method.
12468 * (Specialized mechanisms, such as sendfile system call, may be used
12469 * on appropriate situation.)
12471 * This method returns the number of bytes copied.
12473 * If optional arguments are not given,
12474 * the start position of the copy is
12475 * the beginning of the filename or
12476 * the current file offset of the IO.
12477 * The end position of the copy is the end of file.
12479 * If <i>copy_length</i> is given,
12480 * No more than <i>copy_length</i> bytes are copied.
12482 * If <i>src_offset</i> is given,
12483 * it specifies the start position of the copy.
12485 * When <i>src_offset</i> is specified and
12486 * <i>src</i> is an IO,
12487 * IO.copy_stream doesn't move the current file offset.
12490 static VALUE
12491 rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
12493 VALUE src, dst, length, src_offset;
12494 struct copy_stream_struct st;
12496 MEMZERO(&st, struct copy_stream_struct, 1);
12498 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
12500 st.src = src;
12501 st.dst = dst;
12503 st.src_fptr = NULL;
12504 st.dst_fptr = NULL;
12506 if (NIL_P(length))
12507 st.copy_length = (off_t)-1;
12508 else
12509 st.copy_length = NUM2OFFT(length);
12511 if (NIL_P(src_offset))
12512 st.src_offset = (off_t)-1;
12513 else
12514 st.src_offset = NUM2OFFT(src_offset);
12516 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
12518 return OFFT2NUM(st.total);
12522 * call-seq:
12523 * io.external_encoding -> encoding
12525 * Returns the Encoding object that represents the encoding of the file.
12526 * If _io_ is in write mode and no encoding is specified, returns +nil+.
12529 static VALUE
12530 rb_io_external_encoding(VALUE io)
12532 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
12534 if (fptr->encs.enc2) {
12535 return rb_enc_from_encoding(fptr->encs.enc2);
12537 if (fptr->mode & FMODE_WRITABLE) {
12538 if (fptr->encs.enc)
12539 return rb_enc_from_encoding(fptr->encs.enc);
12540 return Qnil;
12542 return rb_enc_from_encoding(io_read_encoding(fptr));
12546 * call-seq:
12547 * io.internal_encoding -> encoding
12549 * Returns the Encoding of the internal string if conversion is
12550 * specified. Otherwise returns +nil+.
12553 static VALUE
12554 rb_io_internal_encoding(VALUE io)
12556 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
12558 if (!fptr->encs.enc2) return Qnil;
12559 return rb_enc_from_encoding(io_read_encoding(fptr));
12563 * call-seq:
12564 * io.set_encoding(ext_enc) -> io
12565 * io.set_encoding("ext_enc:int_enc") -> io
12566 * io.set_encoding(ext_enc, int_enc) -> io
12567 * io.set_encoding("ext_enc:int_enc", opt) -> io
12568 * io.set_encoding(ext_enc, int_enc, opt) -> io
12570 * If single argument is specified, read string from io is tagged
12571 * with the encoding specified. If encoding is a colon separated two
12572 * encoding names "A:B", the read string is converted from encoding A
12573 * (external encoding) to encoding B (internal encoding), then tagged
12574 * with B. If two arguments are specified, those must be encoding
12575 * objects or encoding names, and the first one is the external encoding, and the
12576 * second one is the internal encoding.
12577 * If the external encoding and the internal encoding is specified,
12578 * optional hash argument specify the conversion option.
12581 static VALUE
12582 rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
12584 rb_io_t *fptr;
12585 VALUE v1, v2, opt;
12587 if (!RB_TYPE_P(io, T_FILE)) {
12588 return forward(io, id_set_encoding, argc, argv);
12591 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
12592 GetOpenFile(io, fptr);
12593 io_encoding_set(fptr, v1, v2, opt);
12594 return io;
12597 void
12598 rb_stdio_set_default_encoding(void)
12600 VALUE val = Qnil;
12602 #ifdef _WIN32
12603 if (isatty(fileno(stdin))) {
12604 rb_encoding *external = rb_locale_encoding();
12605 rb_encoding *internal = rb_default_internal_encoding();
12606 if (!internal) internal = rb_default_external_encoding();
12607 io_encoding_set(RFILE(rb_stdin)->fptr,
12608 rb_enc_from_encoding(external),
12609 rb_enc_from_encoding(internal),
12610 Qnil);
12612 else
12613 #endif
12614 rb_io_set_encoding(1, &val, rb_stdin);
12615 rb_io_set_encoding(1, &val, rb_stdout);
12616 rb_io_set_encoding(1, &val, rb_stderr);
12619 static inline int
12620 global_argf_p(VALUE arg)
12622 return arg == argf;
12626 * call-seq:
12627 * ARGF.external_encoding -> encoding
12629 * Returns the external encoding for files read from +ARGF+ as an +Encoding+
12630 * object. The external encoding is the encoding of the text as stored in a
12631 * file. Contrast with +ARGF.internal_encoding+, which is the encoding used
12632 * to represent this text within Ruby.
12634 * To set the external encoding use +ARGF.set_encoding+.
12636 * For example:
12638 * ARGF.external_encoding #=> #<Encoding:UTF-8>
12641 static VALUE
12642 argf_external_encoding(VALUE argf)
12644 if (!RTEST(ARGF.current_file)) {
12645 return rb_enc_from_encoding(rb_default_external_encoding());
12647 return rb_io_external_encoding(rb_io_check_io(ARGF.current_file));
12651 * call-seq:
12652 * ARGF.internal_encoding -> encoding
12654 * Returns the internal encoding for strings read from +ARGF+ as an
12655 * +Encoding+ object.
12657 * If +ARGF.set_encoding+ has been called with two encoding names, the second
12658 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
12659 * value is returned. Failing that, if a default external encoding was
12660 * specified on the command-line, that value is used. If the encoding is
12661 * unknown, +nil+ is returned.
12663 static VALUE
12664 argf_internal_encoding(VALUE argf)
12666 if (!RTEST(ARGF.current_file)) {
12667 return rb_enc_from_encoding(rb_default_external_encoding());
12669 return rb_io_internal_encoding(rb_io_check_io(ARGF.current_file));
12673 * call-seq:
12674 * ARGF.set_encoding(ext_enc) -> ARGF
12675 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
12676 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
12677 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
12678 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
12680 * If single argument is specified, strings read from ARGF are tagged with
12681 * the encoding specified.
12683 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
12684 * the read string is converted from the first encoding (external encoding)
12685 * to the second encoding (internal encoding), then tagged with the second
12686 * encoding.
12688 * If two arguments are specified, they must be encoding objects or encoding
12689 * names. Again, the first specifies the external encoding; the second
12690 * specifies the internal encoding.
12692 * If the external encoding and the internal encoding are specified, the
12693 * optional +Hash+ argument can be used to adjust the conversion process. The
12694 * structure of this hash is explained in the String#encode documentation.
12696 * For example:
12698 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
12699 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
12700 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
12701 * # to UTF-8.
12703 static VALUE
12704 argf_set_encoding(int argc, VALUE *argv, VALUE argf)
12706 rb_io_t *fptr;
12708 if (!next_argv()) {
12709 rb_raise(rb_eArgError, "no stream to set encoding");
12711 rb_io_set_encoding(argc, argv, ARGF.current_file);
12712 GetOpenFile(ARGF.current_file, fptr);
12713 ARGF.encs = fptr->encs;
12714 return argf;
12718 * call-seq:
12719 * ARGF.tell -> Integer
12720 * ARGF.pos -> Integer
12722 * Returns the current offset (in bytes) of the current file in +ARGF+.
12724 * ARGF.pos #=> 0
12725 * ARGF.gets #=> "This is line one\n"
12726 * ARGF.pos #=> 17
12729 static VALUE
12730 argf_tell(VALUE argf)
12732 if (!next_argv()) {
12733 rb_raise(rb_eArgError, "no stream to tell");
12735 ARGF_FORWARD(0, 0);
12736 return rb_io_tell(ARGF.current_file);
12740 * call-seq:
12741 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
12743 * Seeks to offset _amount_ (an +Integer+) in the +ARGF+ stream according to
12744 * the value of _whence_. See IO#seek for further details.
12746 static VALUE
12747 argf_seek_m(int argc, VALUE *argv, VALUE argf)
12749 if (!next_argv()) {
12750 rb_raise(rb_eArgError, "no stream to seek");
12752 ARGF_FORWARD(argc, argv);
12753 return rb_io_seek_m(argc, argv, ARGF.current_file);
12757 * call-seq:
12758 * ARGF.pos = position -> Integer
12760 * Seeks to the position given by _position_ (in bytes) in +ARGF+.
12762 * For example:
12764 * ARGF.pos = 17
12765 * ARGF.gets #=> "This is line two\n"
12767 static VALUE
12768 argf_set_pos(VALUE argf, VALUE offset)
12770 if (!next_argv()) {
12771 rb_raise(rb_eArgError, "no stream to set position");
12773 ARGF_FORWARD(1, &offset);
12774 return rb_io_set_pos(ARGF.current_file, offset);
12778 * call-seq:
12779 * ARGF.rewind -> 0
12781 * Positions the current file to the beginning of input, resetting
12782 * +ARGF.lineno+ to zero.
12784 * ARGF.readline #=> "This is line one\n"
12785 * ARGF.rewind #=> 0
12786 * ARGF.lineno #=> 0
12787 * ARGF.readline #=> "This is line one\n"
12789 static VALUE
12790 argf_rewind(VALUE argf)
12792 VALUE ret;
12793 int old_lineno;
12795 if (!next_argv()) {
12796 rb_raise(rb_eArgError, "no stream to rewind");
12798 ARGF_FORWARD(0, 0);
12799 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
12800 ret = rb_io_rewind(ARGF.current_file);
12801 if (!global_argf_p(argf)) {
12802 ARGF.last_lineno = ARGF.lineno -= old_lineno;
12804 return ret;
12808 * call-seq:
12809 * ARGF.fileno -> integer
12810 * ARGF.to_i -> integer
12812 * Returns an integer representing the numeric file descriptor for
12813 * the current file. Raises an +ArgumentError+ if there isn't a current file.
12815 * ARGF.fileno #=> 3
12817 static VALUE
12818 argf_fileno(VALUE argf)
12820 if (!next_argv()) {
12821 rb_raise(rb_eArgError, "no stream");
12823 ARGF_FORWARD(0, 0);
12824 return rb_io_fileno(ARGF.current_file);
12828 * call-seq:
12829 * ARGF.to_io -> IO
12831 * Returns an +IO+ object representing the current file. This will be a
12832 * +File+ object unless the current file is a stream such as STDIN.
12834 * For example:
12836 * ARGF.to_io #=> #<File:glark.txt>
12837 * ARGF.to_io #=> #<IO:<STDIN>>
12839 static VALUE
12840 argf_to_io(VALUE argf)
12842 next_argv();
12843 ARGF_FORWARD(0, 0);
12844 return ARGF.current_file;
12848 * call-seq:
12849 * ARGF.eof? -> true or false
12850 * ARGF.eof -> true or false
12852 * Returns true if the current file in +ARGF+ is at end of file, i.e. it has
12853 * no data to read. The stream must be opened for reading or an +IOError+
12854 * will be raised.
12856 * $ echo "eof" | ruby argf.rb
12858 * ARGF.eof? #=> false
12859 * 3.times { ARGF.readchar }
12860 * ARGF.eof? #=> false
12861 * ARGF.readchar #=> "\n"
12862 * ARGF.eof? #=> true
12865 static VALUE
12866 argf_eof(VALUE argf)
12868 next_argv();
12869 if (RTEST(ARGF.current_file)) {
12870 if (ARGF.init_p == 0) return Qtrue;
12871 next_argv();
12872 ARGF_FORWARD(0, 0);
12873 if (rb_io_eof(ARGF.current_file)) {
12874 return Qtrue;
12877 return Qfalse;
12881 * call-seq:
12882 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
12884 * Reads _length_ bytes from ARGF. The files named on the command line
12885 * are concatenated and treated as a single file by this method, so when
12886 * called without arguments the contents of this pseudo file are returned in
12887 * their entirety.
12889 * _length_ must be a non-negative integer or +nil+.
12891 * If _length_ is a positive integer, +read+ tries to read
12892 * _length_ bytes without any conversion (binary mode).
12893 * It returns +nil+ if an EOF is encountered before anything can be read.
12894 * Fewer than _length_ bytes are returned if an EOF is encountered during
12895 * the read.
12896 * In the case of an integer _length_, the resulting string is always
12897 * in ASCII-8BIT encoding.
12899 * If _length_ is omitted or is +nil+, it reads until EOF
12900 * and the encoding conversion is applied, if applicable.
12901 * A string is returned even if EOF is encountered before any data is read.
12903 * If _length_ is zero, it returns an empty string (<code>""</code>).
12905 * If the optional _outbuf_ argument is present,
12906 * it must reference a String, which will receive the data.
12907 * The _outbuf_ will contain only the received data after the method call
12908 * even if it is not empty at the beginning.
12910 * For example:
12912 * $ echo "small" > small.txt
12913 * $ echo "large" > large.txt
12914 * $ ./glark.rb small.txt large.txt
12916 * ARGF.read #=> "small\nlarge"
12917 * ARGF.read(200) #=> "small\nlarge"
12918 * ARGF.read(2) #=> "sm"
12919 * ARGF.read(0) #=> ""
12921 * Note that this method behaves like the fread() function in C.
12922 * This means it retries to invoke read(2) system calls to read data
12923 * with the specified length.
12924 * If you need the behavior like a single read(2) system call,
12925 * consider ARGF#readpartial or ARGF#read_nonblock.
12928 static VALUE
12929 argf_read(int argc, VALUE *argv, VALUE argf)
12931 VALUE tmp, str, length;
12932 long len = 0;
12934 rb_scan_args(argc, argv, "02", &length, &str);
12935 if (!NIL_P(length)) {
12936 len = NUM2LONG(argv[0]);
12938 if (!NIL_P(str)) {
12939 StringValue(str);
12940 rb_str_resize(str,0);
12941 argv[1] = Qnil;
12944 retry:
12945 if (!next_argv()) {
12946 return str;
12948 if (ARGF_GENERIC_INPUT_P()) {
12949 tmp = argf_forward(argc, argv, argf);
12951 else {
12952 tmp = io_read(argc, argv, ARGF.current_file);
12954 if (NIL_P(str)) str = tmp;
12955 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
12956 if (NIL_P(tmp) || NIL_P(length)) {
12957 if (ARGF.next_p != -1) {
12958 argf_close(argf);
12959 ARGF.next_p = 1;
12960 goto retry;
12963 else if (argc >= 1) {
12964 long slen = RSTRING_LEN(str);
12965 if (slen < len) {
12966 argv[0] = LONG2NUM(len - slen);
12967 goto retry;
12970 return str;
12973 struct argf_call_arg {
12974 int argc;
12975 VALUE *argv;
12976 VALUE argf;
12979 static VALUE
12980 argf_forward_call(VALUE arg)
12982 struct argf_call_arg *p = (struct argf_call_arg *)arg;
12983 argf_forward(p->argc, p->argv, p->argf);
12984 return Qnil;
12987 static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
12988 int nonblock);
12991 * call-seq:
12992 * ARGF.readpartial(maxlen) -> string
12993 * ARGF.readpartial(maxlen, outbuf) -> outbuf
12995 * Reads at most _maxlen_ bytes from the ARGF stream.
12997 * If the optional _outbuf_ argument is present,
12998 * it must reference a String, which will receive the data.
12999 * The _outbuf_ will contain only the received data after the method call
13000 * even if it is not empty at the beginning.
13002 * It raises EOFError on end of ARGF stream.
13003 * Since ARGF stream is a concatenation of multiple files,
13004 * internally EOF is occur for each file.
13005 * ARGF.readpartial returns empty strings for EOFs except the last one and
13006 * raises EOFError for the last one.
13010 static VALUE
13011 argf_readpartial(int argc, VALUE *argv, VALUE argf)
13013 return argf_getpartial(argc, argv, argf, Qnil, 0);
13017 * call-seq:
13018 * ARGF.read_nonblock(maxlen[, options]) -> string
13019 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13021 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13024 static VALUE
13025 argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13027 VALUE opts;
13029 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13031 if (!NIL_P(opts))
13032 argc--;
13034 return argf_getpartial(argc, argv, argf, opts, 1);
13037 static VALUE
13038 argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13040 VALUE tmp, str, length;
13041 int no_exception;
13043 rb_scan_args(argc, argv, "11", &length, &str);
13044 if (!NIL_P(str)) {
13045 StringValue(str);
13046 argv[1] = str;
13048 no_exception = no_exception_p(opts);
13050 if (!next_argv()) {
13051 if (!NIL_P(str)) {
13052 rb_str_resize(str, 0);
13054 rb_eof_error();
13056 if (ARGF_GENERIC_INPUT_P()) {
13057 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13058 struct argf_call_arg arg;
13059 arg.argc = argc;
13060 arg.argv = argv;
13061 arg.argf = argf;
13062 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
13063 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
13065 else {
13066 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13068 if (NIL_P(tmp)) {
13069 if (ARGF.next_p == -1) {
13070 return io_nonblock_eof(no_exception);
13072 argf_close(argf);
13073 ARGF.next_p = 1;
13074 if (RARRAY_LEN(ARGF.argv) == 0) {
13075 return io_nonblock_eof(no_exception);
13077 if (NIL_P(str))
13078 str = rb_str_new(NULL, 0);
13079 return str;
13081 return tmp;
13085 * call-seq:
13086 * ARGF.getc -> String or nil
13088 * Reads the next character from +ARGF+ and returns it as a +String+. Returns
13089 * +nil+ at the end of the stream.
13091 * +ARGF+ treats the files named on the command line as a single file created
13092 * by concatenating their contents. After returning the last character of the
13093 * first file, it returns the first character of the second file, and so on.
13095 * For example:
13097 * $ echo "foo" > file
13098 * $ ruby argf.rb file
13100 * ARGF.getc #=> "f"
13101 * ARGF.getc #=> "o"
13102 * ARGF.getc #=> "o"
13103 * ARGF.getc #=> "\n"
13104 * ARGF.getc #=> nil
13105 * ARGF.getc #=> nil
13107 static VALUE
13108 argf_getc(VALUE argf)
13110 VALUE ch;
13112 retry:
13113 if (!next_argv()) return Qnil;
13114 if (ARGF_GENERIC_INPUT_P()) {
13115 ch = forward_current(rb_intern("getc"), 0, 0);
13117 else {
13118 ch = rb_io_getc(ARGF.current_file);
13120 if (NIL_P(ch) && ARGF.next_p != -1) {
13121 argf_close(argf);
13122 ARGF.next_p = 1;
13123 goto retry;
13126 return ch;
13130 * call-seq:
13131 * ARGF.getbyte -> Integer or nil
13133 * Gets the next 8-bit byte (0..255) from +ARGF+. Returns +nil+ if called at
13134 * the end of the stream.
13136 * For example:
13138 * $ echo "foo" > file
13139 * $ ruby argf.rb file
13141 * ARGF.getbyte #=> 102
13142 * ARGF.getbyte #=> 111
13143 * ARGF.getbyte #=> 111
13144 * ARGF.getbyte #=> 10
13145 * ARGF.getbyte #=> nil
13147 static VALUE
13148 argf_getbyte(VALUE argf)
13150 VALUE ch;
13152 retry:
13153 if (!next_argv()) return Qnil;
13154 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
13155 ch = forward_current(rb_intern("getbyte"), 0, 0);
13157 else {
13158 ch = rb_io_getbyte(ARGF.current_file);
13160 if (NIL_P(ch) && ARGF.next_p != -1) {
13161 argf_close(argf);
13162 ARGF.next_p = 1;
13163 goto retry;
13166 return ch;
13170 * call-seq:
13171 * ARGF.readchar -> String or nil
13173 * Reads the next character from +ARGF+ and returns it as a +String+. Raises
13174 * an +EOFError+ after the last character of the last file has been read.
13176 * For example:
13178 * $ echo "foo" > file
13179 * $ ruby argf.rb file
13181 * ARGF.readchar #=> "f"
13182 * ARGF.readchar #=> "o"
13183 * ARGF.readchar #=> "o"
13184 * ARGF.readchar #=> "\n"
13185 * ARGF.readchar #=> end of file reached (EOFError)
13187 static VALUE
13188 argf_readchar(VALUE argf)
13190 VALUE ch;
13192 retry:
13193 if (!next_argv()) rb_eof_error();
13194 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
13195 ch = forward_current(rb_intern("getc"), 0, 0);
13197 else {
13198 ch = rb_io_getc(ARGF.current_file);
13200 if (NIL_P(ch) && ARGF.next_p != -1) {
13201 argf_close(argf);
13202 ARGF.next_p = 1;
13203 goto retry;
13206 return ch;
13210 * call-seq:
13211 * ARGF.readbyte -> Integer
13213 * Reads the next 8-bit byte from ARGF and returns it as an +Integer+. Raises
13214 * an +EOFError+ after the last byte of the last file has been read.
13216 * For example:
13218 * $ echo "foo" > file
13219 * $ ruby argf.rb file
13221 * ARGF.readbyte #=> 102
13222 * ARGF.readbyte #=> 111
13223 * ARGF.readbyte #=> 111
13224 * ARGF.readbyte #=> 10
13225 * ARGF.readbyte #=> end of file reached (EOFError)
13227 static VALUE
13228 argf_readbyte(VALUE argf)
13230 VALUE c;
13232 NEXT_ARGF_FORWARD(0, 0);
13233 c = argf_getbyte(argf);
13234 if (NIL_P(c)) {
13235 rb_eof_error();
13237 return c;
13240 #define FOREACH_ARGF() while (next_argv())
13242 static VALUE
13243 argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
13245 const VALUE current = ARGF.current_file;
13246 rb_yield_values2(argc, argv);
13247 if (ARGF.init_p == -1 || current != ARGF.current_file) {
13248 rb_iter_break_value(Qundef);
13250 return Qnil;
13253 #define ARGF_block_call(mid, argc, argv, func, argf) \
13254 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
13255 func, argf, rb_keyword_given_p())
13257 static void
13258 argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
13260 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
13261 if (ret != Qundef) ARGF.next_p = 1;
13264 static VALUE
13265 argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
13267 if (!global_argf_p(argf)) {
13268 ARGF.last_lineno = ++ARGF.lineno;
13270 return argf_block_call_i(i, argf, argc, argv, blockarg);
13273 static void
13274 argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
13276 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
13277 if (ret != Qundef) ARGF.next_p = 1;
13281 * call-seq:
13282 * ARGF.each(sep=$/) {|line| block } -> ARGF
13283 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
13284 * ARGF.each(...) -> an_enumerator
13286 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
13287 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
13288 * ARGF.each_line(...) -> an_enumerator
13290 * Returns an enumerator which iterates over each line (separated by _sep_,
13291 * which defaults to your platform's newline character) of each file in
13292 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
13293 * block, otherwise an enumerator is returned.
13294 * The optional _limit_ argument is an +Integer+ specifying the maximum
13295 * length of each line; longer lines will be split according to this limit.
13297 * This method allows you to treat the files supplied on the command line as
13298 * a single file consisting of the concatenation of each named file. After
13299 * the last line of the first file has been returned, the first line of the
13300 * second file is returned. The +ARGF.filename+ and +ARGF.lineno+ methods can
13301 * be used to determine the filename of the current line and line number of
13302 * the whole input, respectively.
13304 * For example, the following code prints out each line of each named file
13305 * prefixed with its line number, displaying the filename once per file:
13307 * ARGF.each_line do |line|
13308 * puts ARGF.filename if ARGF.file.lineno == 1
13309 * puts "#{ARGF.file.lineno}: #{line}"
13310 * end
13312 * While the following code prints only the first file's name at first, and
13313 * the contents with line number counted through all named files.
13315 * ARGF.each_line do |line|
13316 * puts ARGF.filename if ARGF.lineno == 1
13317 * puts "#{ARGF.lineno}: #{line}"
13318 * end
13320 static VALUE
13321 argf_each_line(int argc, VALUE *argv, VALUE argf)
13323 RETURN_ENUMERATOR(argf, argc, argv);
13324 FOREACH_ARGF() {
13325 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
13327 return argf;
13331 * call-seq:
13332 * ARGF.each_byte {|byte| block } -> ARGF
13333 * ARGF.each_byte -> an_enumerator
13335 * Iterates over each byte of each file in +ARGV+.
13336 * A byte is returned as an +Integer+ in the range 0..255.
13338 * This method allows you to treat the files supplied on the command line as
13339 * a single file consisting of the concatenation of each named file. After
13340 * the last byte of the first file has been returned, the first byte of the
13341 * second file is returned. The +ARGF.filename+ method can be used to
13342 * determine the filename of the current byte.
13344 * If no block is given, an enumerator is returned instead.
13346 * For example:
13348 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
13351 static VALUE
13352 argf_each_byte(VALUE argf)
13354 RETURN_ENUMERATOR(argf, 0, 0);
13355 FOREACH_ARGF() {
13356 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
13358 return argf;
13362 * call-seq:
13363 * ARGF.each_char {|char| block } -> ARGF
13364 * ARGF.each_char -> an_enumerator
13366 * Iterates over each character of each file in +ARGF+.
13368 * This method allows you to treat the files supplied on the command line as
13369 * a single file consisting of the concatenation of each named file. After
13370 * the last character of the first file has been returned, the first
13371 * character of the second file is returned. The +ARGF.filename+ method can
13372 * be used to determine the name of the file in which the current character
13373 * appears.
13375 * If no block is given, an enumerator is returned instead.
13377 static VALUE
13378 argf_each_char(VALUE argf)
13380 RETURN_ENUMERATOR(argf, 0, 0);
13381 FOREACH_ARGF() {
13382 argf_block_call(rb_intern("each_char"), 0, 0, argf);
13384 return argf;
13388 * call-seq:
13389 * ARGF.each_codepoint {|codepoint| block } -> ARGF
13390 * ARGF.each_codepoint -> an_enumerator
13392 * Iterates over each codepoint of each file in +ARGF+.
13394 * This method allows you to treat the files supplied on the command line as
13395 * a single file consisting of the concatenation of each named file. After
13396 * the last codepoint of the first file has been returned, the first
13397 * codepoint of the second file is returned. The +ARGF.filename+ method can
13398 * be used to determine the name of the file in which the current codepoint
13399 * appears.
13401 * If no block is given, an enumerator is returned instead.
13403 static VALUE
13404 argf_each_codepoint(VALUE argf)
13406 RETURN_ENUMERATOR(argf, 0, 0);
13407 FOREACH_ARGF() {
13408 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
13410 return argf;
13414 * call-seq:
13415 * ARGF.filename -> String
13416 * ARGF.path -> String
13418 * Returns the current filename. "-" is returned when the current file is
13419 * STDIN.
13421 * For example:
13423 * $ echo "foo" > foo
13424 * $ echo "bar" > bar
13425 * $ echo "glark" > glark
13427 * $ ruby argf.rb foo bar glark
13429 * ARGF.filename #=> "foo"
13430 * ARGF.read(5) #=> "foo\nb"
13431 * ARGF.filename #=> "bar"
13432 * ARGF.skip
13433 * ARGF.filename #=> "glark"
13435 static VALUE
13436 argf_filename(VALUE argf)
13438 next_argv();
13439 return ARGF.filename;
13442 static VALUE
13443 argf_filename_getter(ID id, VALUE *var)
13445 return argf_filename(*var);
13449 * call-seq:
13450 * ARGF.file -> IO or File object
13452 * Returns the current file as an +IO+ or +File+ object.
13453 * <code>$stdin</code> is returned when the current file is STDIN.
13455 * For example:
13457 * $ echo "foo" > foo
13458 * $ echo "bar" > bar
13460 * $ ruby argf.rb foo bar
13462 * ARGF.file #=> #<File:foo>
13463 * ARGF.read(5) #=> "foo\nb"
13464 * ARGF.file #=> #<File:bar>
13466 static VALUE
13467 argf_file(VALUE argf)
13469 next_argv();
13470 return ARGF.current_file;
13474 * call-seq:
13475 * ARGF.binmode -> ARGF
13477 * Puts +ARGF+ into binary mode. Once a stream is in binary mode, it cannot
13478 * be reset to non-binary mode. This option has the following effects:
13480 * * Newline conversion is disabled.
13481 * * Encoding conversion is disabled.
13482 * * Content is treated as ASCII-8BIT.
13484 static VALUE
13485 argf_binmode_m(VALUE argf)
13487 ARGF.binmode = 1;
13488 next_argv();
13489 ARGF_FORWARD(0, 0);
13490 rb_io_ascii8bit_binmode(ARGF.current_file);
13491 return argf;
13495 * call-seq:
13496 * ARGF.binmode? -> true or false
13498 * Returns true if +ARGF+ is being read in binary mode; false otherwise.
13499 * To enable binary mode use +ARGF.binmode+.
13501 * For example:
13503 * ARGF.binmode? #=> false
13504 * ARGF.binmode
13505 * ARGF.binmode? #=> true
13507 static VALUE
13508 argf_binmode_p(VALUE argf)
13510 return RBOOL(ARGF.binmode);
13514 * call-seq:
13515 * ARGF.skip -> ARGF
13517 * Sets the current file to the next file in ARGV. If there aren't any more
13518 * files it has no effect.
13520 * For example:
13522 * $ ruby argf.rb foo bar
13523 * ARGF.filename #=> "foo"
13524 * ARGF.skip
13525 * ARGF.filename #=> "bar"
13527 static VALUE
13528 argf_skip(VALUE argf)
13530 if (ARGF.init_p && ARGF.next_p == 0) {
13531 argf_close(argf);
13532 ARGF.next_p = 1;
13534 return argf;
13538 * call-seq:
13539 * ARGF.close -> ARGF
13541 * Closes the current file and skips to the next file in ARGV. If there are
13542 * no more files to open, just closes the current file. +STDIN+ will not be
13543 * closed.
13545 * For example:
13547 * $ ruby argf.rb foo bar
13549 * ARGF.filename #=> "foo"
13550 * ARGF.close
13551 * ARGF.filename #=> "bar"
13552 * ARGF.close
13554 static VALUE
13555 argf_close_m(VALUE argf)
13557 next_argv();
13558 argf_close(argf);
13559 if (ARGF.next_p != -1) {
13560 ARGF.next_p = 1;
13562 ARGF.lineno = 0;
13563 return argf;
13567 * call-seq:
13568 * ARGF.closed? -> true or false
13570 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
13571 * +ARGF.close+ to actually close the current file.
13573 static VALUE
13574 argf_closed(VALUE argf)
13576 next_argv();
13577 ARGF_FORWARD(0, 0);
13578 return rb_io_closed(ARGF.current_file);
13582 * call-seq:
13583 * ARGF.to_s -> String
13585 * Returns "ARGF".
13587 static VALUE
13588 argf_to_s(VALUE argf)
13590 return rb_str_new2("ARGF");
13594 * call-seq:
13595 * ARGF.inplace_mode -> String
13597 * Returns the file extension appended to the names of modified files under
13598 * in-place edit mode. This value can be set using +ARGF.inplace_mode=+ or
13599 * passing the +-i+ switch to the Ruby binary.
13601 static VALUE
13602 argf_inplace_mode_get(VALUE argf)
13604 if (!ARGF.inplace) return Qnil;
13605 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
13606 return rb_str_dup(ARGF.inplace);
13609 static VALUE
13610 opt_i_get(ID id, VALUE *var)
13612 return argf_inplace_mode_get(*var);
13616 * call-seq:
13617 * ARGF.inplace_mode = ext -> ARGF
13619 * Sets the filename extension for in-place editing mode to the given String.
13620 * Each file being edited has this value appended to its filename. The
13621 * modified file is saved under this new name.
13623 * For example:
13625 * $ ruby argf.rb file.txt
13627 * ARGF.inplace_mode = '.bak'
13628 * ARGF.each_line do |line|
13629 * print line.sub("foo","bar")
13630 * end
13632 * Each line of _file.txt_ has the first occurrence of "foo" replaced with
13633 * "bar", then the new line is written out to _file.txt.bak_.
13635 static VALUE
13636 argf_inplace_mode_set(VALUE argf, VALUE val)
13638 if (!RTEST(val)) {
13639 ARGF.inplace = Qfalse;
13641 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
13642 ARGF.inplace = Qnil;
13644 else {
13645 ARGF.inplace = rb_str_new_frozen(val);
13647 return argf;
13650 static void
13651 opt_i_set(VALUE val, ID id, VALUE *var)
13653 argf_inplace_mode_set(*var, val);
13656 void
13657 ruby_set_inplace_mode(const char *suffix)
13659 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
13663 * call-seq:
13664 * ARGF.argv -> ARGV
13666 * Returns the +ARGV+ array, which contains the arguments passed to your
13667 * script, one per element.
13669 * For example:
13671 * $ ruby argf.rb -v glark.txt
13673 * ARGF.argv #=> ["-v", "glark.txt"]
13676 static VALUE
13677 argf_argv(VALUE argf)
13679 return ARGF.argv;
13682 static VALUE
13683 argf_argv_getter(ID id, VALUE *var)
13685 return argf_argv(*var);
13688 VALUE
13689 rb_get_argv(void)
13691 return ARGF.argv;
13695 * call-seq:
13696 * ARGF.to_write_io -> io
13698 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
13699 * enabled.
13701 static VALUE
13702 argf_write_io(VALUE argf)
13704 if (!RTEST(ARGF.current_file)) {
13705 rb_raise(rb_eIOError, "not opened for writing");
13707 return GetWriteIO(ARGF.current_file);
13711 * call-seq:
13712 * ARGF.write(string) -> integer
13714 * Writes _string_ if inplace mode.
13716 static VALUE
13717 argf_write(VALUE argf, VALUE str)
13719 return rb_io_write(argf_write_io(argf), str);
13722 void
13723 rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
13725 rb_readwrite_syserr_fail(waiting, errno, mesg);
13728 void
13729 rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
13731 VALUE arg, c = Qnil;
13732 arg = mesg ? rb_str_new2(mesg) : Qnil;
13733 switch (waiting) {
13734 case RB_IO_WAIT_WRITABLE:
13735 switch (n) {
13736 case EAGAIN:
13737 c = rb_eEAGAINWaitWritable;
13738 break;
13739 #if EAGAIN != EWOULDBLOCK
13740 case EWOULDBLOCK:
13741 c = rb_eEWOULDBLOCKWaitWritable;
13742 break;
13743 #endif
13744 case EINPROGRESS:
13745 c = rb_eEINPROGRESSWaitWritable;
13746 break;
13747 default:
13748 rb_mod_syserr_fail_str(rb_mWaitWritable, n, arg);
13750 break;
13751 case RB_IO_WAIT_READABLE:
13752 switch (n) {
13753 case EAGAIN:
13754 c = rb_eEAGAINWaitReadable;
13755 break;
13756 #if EAGAIN != EWOULDBLOCK
13757 case EWOULDBLOCK:
13758 c = rb_eEWOULDBLOCKWaitReadable;
13759 break;
13760 #endif
13761 case EINPROGRESS:
13762 c = rb_eEINPROGRESSWaitReadable;
13763 break;
13764 default:
13765 rb_mod_syserr_fail_str(rb_mWaitReadable, n, arg);
13767 break;
13768 default:
13769 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
13771 rb_exc_raise(rb_class_new_instance(1, &arg, c));
13774 static VALUE
13775 get_LAST_READ_LINE(ID _x, VALUE *_y)
13777 return rb_lastline_get();
13780 static void
13781 set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
13783 rb_lastline_set(val);
13787 * Document-class: IOError
13789 * Raised when an IO operation fails.
13791 * File.open("/etc/hosts") {|f| f << "example"}
13792 * #=> IOError: not opened for writing
13794 * File.open("/etc/hosts") {|f| f.close; f.read }
13795 * #=> IOError: closed stream
13797 * Note that some IO failures raise <code>SystemCallError</code>s
13798 * and these are not subclasses of IOError:
13800 * File.open("does/not/exist")
13801 * #=> Errno::ENOENT: No such file or directory - does/not/exist
13805 * Document-class: EOFError
13807 * Raised by some IO operations when reaching the end of file. Many IO
13808 * methods exist in two forms,
13810 * one that returns +nil+ when the end of file is reached, the other
13811 * raises +EOFError+.
13813 * +EOFError+ is a subclass of +IOError+.
13815 * file = File.open("/etc/hosts")
13816 * file.read
13817 * file.gets #=> nil
13818 * file.readline #=> EOFError: end of file reached
13822 * Document-class: ARGF
13824 * +ARGF+ is a stream designed for use in scripts that process files given as
13825 * command-line arguments or passed in via STDIN.
13827 * The arguments passed to your script are stored in the +ARGV+ Array, one
13828 * argument per element. +ARGF+ assumes that any arguments that aren't
13829 * filenames have been removed from +ARGV+. For example:
13831 * $ ruby argf.rb --verbose file1 file2
13833 * ARGV #=> ["--verbose", "file1", "file2"]
13834 * option = ARGV.shift #=> "--verbose"
13835 * ARGV #=> ["file1", "file2"]
13837 * You can now use +ARGF+ to work with a concatenation of each of these named
13838 * files. For instance, +ARGF.read+ will return the contents of _file1_
13839 * followed by the contents of _file2_.
13841 * After a file in +ARGV+ has been read +ARGF+ removes it from the Array.
13842 * Thus, after all files have been read +ARGV+ will be empty.
13844 * You can manipulate +ARGV+ yourself to control what +ARGF+ operates on. If
13845 * you remove a file from +ARGV+, it is ignored by +ARGF+; if you add files to
13846 * +ARGV+, they are treated as if they were named on the command line. For
13847 * example:
13849 * ARGV.replace ["file1"]
13850 * ARGF.readlines # Returns the contents of file1 as an Array
13851 * ARGV #=> []
13852 * ARGV.replace ["file2", "file3"]
13853 * ARGF.read # Returns the contents of file2 and file3
13855 * If +ARGV+ is empty, +ARGF+ acts as if it contained STDIN, i.e. the data
13856 * piped to your script. For example:
13858 * $ echo "glark" | ruby -e 'p ARGF.read'
13859 * "glark\n"
13863 * An instance of class \IO (commonly called a _stream_)
13864 * represents an input/output stream in the underlying operating system.
13865 * \Class \IO is the basis for input and output in Ruby.
13867 * \Class File is the only class in the Ruby core that is a subclass of \IO.
13868 * Some classes in the Ruby standard library are also subclasses of \IO;
13869 * these include TCPSocket and UDPSocket.
13871 * The global constant ARGF (also accessible as <tt>$<</tt>)
13872 * provides an IO-like stream that allows access to all file paths
13873 * found in ARGV (or found in STDIN if ARGV is empty).
13874 * Note that ARGF is not itself a subclass of \IO.
13876 * Important objects based on \IO include:
13878 * - $stdin.
13879 * - $stdout.
13880 * - $stderr.
13881 * - Instances of class File.
13883 * An instance of \IO may be created using:
13885 * - IO.new: returns a new \IO object for the given integer file descriptor.
13886 * - IO.open: passes a new \IO object to the given block.
13887 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
13888 * of a newly-launched subprocess.
13889 * - Kernel#open: Returns a new \IO object connected to a given source:
13890 * stream, file, or subprocess.
13892 * A \IO stream has:
13894 * - A read/write mode, which may be read-only, write-only, or read/write;
13895 * see {Read/Write Mode}[#class-IO-label-Read-2FWrite+Mode].
13896 * - A data mode, which may be text-only or binary;
13897 * see {Data Mode}[#class-IO-label-Data+Mode].
13898 * - A position, which determines where in the stream the next
13899 * read or write is to occur;
13900 * see {Position}[#class-IO-label-Position].
13901 * - A line number, which is a special, line-oriented, "position"
13902 * (different from the position mentioned above);
13903 * see {Line Number}[#class-IO-label-Line+Number].
13904 * - Internal and external encodings;
13905 * see {Encodings}[#class-IO-label-Encodings].
13907 * == Extension <tt>io/console</tt>
13909 * Extension <tt>io/console</tt> provides numerous methods
13910 * for interacting with the console;
13911 * requiring it adds numerous methods to class \IO.
13913 * == Example Files
13915 * Many examples here use these filenames and their corresponding files:
13917 * - <tt>t.txt</tt>: A text-only file that is assumed to exist via:
13919 * text = <<~EOT
13920 * First line
13921 * Second line
13923 * Fourth line
13924 * Fifth line
13925 * EOT
13926 * File.write('t.txt', text)
13928 * - <tt>t.dat</tt>: A data file that is assumed to exist via:
13930 * data = "\u9990\u9991\u9992\u9993\u9994"
13931 * f = File.open('t.dat', 'wb:UTF-16')
13932 * f.write(data)
13933 * f.close
13935 * - <tt>t.rus</tt>: A Russian-language text file that is assumed to exist via:
13937 * File.write('t.rus', "\u{442 435 441 442}")
13939 * - <tt>t.tmp</tt>: A file that is assumed _not_ to exist.
13941 * == Modes
13943 * A number of \IO method calls must or may specify a _mode_ for the stream;
13944 * the mode determines how stream is to be accessible, including:
13946 * - Whether the stream is to be read-only, write-only, or read-write.
13947 * - Whether the stream is positioned at its beginning or its end.
13948 * - Whether the stream treats data as text-only or binary.
13949 * - The external and internal encodings.
13951 * === Read/Write Mode
13953 * ==== Read/Write Mode Specified as an \Integer
13955 * When +mode+ is an integer it must be one or more (combined by bitwise OR (<tt>|</tt>)
13956 * of the modes defined in File::Constants:
13958 * - +File::RDONLY+: Open for reading only.
13959 * - +File::WRONLY+: Open for writing only.
13960 * - +File::RDWR+: Open for reading and writing.
13961 * - +File::APPEND+: Open for appending only.
13962 * - +File::CREAT+: Create file if it does not exist.
13963 * - +File::EXCL+: Raise an exception if +File::CREAT+ is given and the file exists.
13965 * Examples:
13967 * File.new('t.txt', File::RDONLY)
13968 * File.new('t.tmp', File::RDWR | File::CREAT | File::EXCL)
13970 * Note: Method IO#set_encoding does not allow the mode to be specified as an integer.
13972 * ==== Read/Write Mode Specified As a \String
13974 * When +mode+ is a string it must begin with one of the following:
13976 * - <tt>'r'</tt>: Read-only stream, positioned at the beginning;
13977 * the stream cannot be changed to writable.
13978 * - <tt>'w'</tt>: Write-only stream, positioned at the beginning;
13979 * the stream cannot be changed to readable.
13980 * - <tt>'a'</tt>: Write-only stream, positioned at the end;
13981 * every write appends to the end;
13982 * the stream cannot be changed to readable.
13983 * - <tt>'r+'</tt>: Read-write stream, positioned at the beginning.
13984 * - <tt>'w+'</tt>: Read-write stream, positioned at the end.
13985 * - <tt>'a+'</tt>: Read-write stream, positioned at the end.
13987 * For a writable file stream (that is, any except read-only),
13988 * the file is truncated to zero if it exists,
13989 * and is created if it does not exist.
13991 * Examples:
13993 * File.open('t.txt', 'r')
13994 * File.open('t.tmp', 'w')
13996 * === Data Mode
13998 * Either of the following may be suffixed to any of the string read/write modes above:
14000 * - <tt>'t'</tt>: Text data; sets the default external encoding to +Encoding::UTF_8+;
14001 * on Windows, enables conversion between EOL and CRLF.
14002 * - <tt>'b'</tt>: Binary data; sets the default external encoding to +Encoding::ASCII_8BIT+;
14003 * on Windows, suppresses conversion between EOL and CRLF.
14005 * If neither is given, the stream defaults to text data.
14007 * Examples:
14009 * File.open('t.txt', 'rt')
14010 * File.open('t.dat', 'rb')
14012 * The following may be suffixed to any writable string mode above:
14014 * - <tt>'x'</tt>: Creates the file if it does not exist;
14015 * raises an exception if the file exists.
14017 * Example:
14019 * File.open('t.tmp', 'wx')
14021 * == Encodings
14023 * Any of the string modes above may specify encodings --
14024 * either external encoding only or both external and internal encodings --
14025 * by appending one or both encoding names, separated by colons:
14027 * f = File.new('t.dat', 'rb')
14028 * f.external_encoding # => #<Encoding:ASCII-8BIT>
14029 * f.internal_encoding # => nil
14030 * f = File.new('t.dat', 'rb:UTF-16')
14031 * f.external_encoding # => #<Encoding:UTF-16 (dummy)>
14032 * f.internal_encoding # => nil
14033 * f = File.new('t.dat', 'rb:UTF-16:UTF-16')
14034 * f.external_encoding # => #<Encoding:UTF-16 (dummy)>
14035 * f.internal_encoding # => #<Encoding:UTF-16>
14037 * The numerous encoding names are available in array Encoding.name_list:
14039 * Encoding.name_list.size # => 175
14040 * Encoding.name_list.take(3) # => ["ASCII-8BIT", "UTF-8", "US-ASCII"]
14042 * When the external encoding is set,
14043 * strings read are tagged by that encoding
14044 * when reading, and strings written are converted to that
14045 * encoding when writing.
14047 * When both external and internal encodings are set,
14048 * strings read are converted from external to internal encoding,
14049 * and strings written are converted from internal to external encoding.
14050 * For further details about transcoding input and output, see Encoding.
14052 * If the external encoding is <tt>'BOM|UTF-8'</tt>, <tt>'BOM|UTF-16LE'</tt>
14053 * or <tt>'BOM|UTF16-BE'</tt>, Ruby checks for
14054 * a Unicode BOM in the input document to help determine the encoding. For
14055 * UTF-16 encodings the file open mode must be binary.
14056 * If the BOM is found, it is stripped and the external encoding from the BOM is used.
14058 * Note that the BOM-style encoding option is case insensitive,
14059 * so 'bom|utf-8' is also valid.)
14061 * == Open Options
14063 * A number of \IO methods accept optional keyword arguments
14064 * that determine how a new stream is to be opened:
14066 * - +:mode+: Stream mode.
14067 * - +:flags+: \Integer file open flags;
14068 * If +mode+ is also given, the two are bitwise-ORed.
14069 * - +:external_encoding+: External encoding for the stream.
14070 * - +:internal_encoding+: Internal encoding for the stream.
14071 * <tt>'-'</tt> is a synonym for the default internal encoding.
14072 * If the value is +nil+ no conversion occurs.
14073 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
14074 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
14075 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
14076 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
14077 * when the stream closes; otherwise it remains open.
14079 * Also available are the options offered in String#encode,
14080 * which may control conversion between external internal encoding.
14082 * == Line Options
14084 * A number of \IO methods accept optional keyword arguments
14085 * that determine how lines in a stream are to be treated:
14087 * - +:chomp+: If +true+, line separators are omitted; default is +false+.
14089 * == Position
14091 * An \IO stream has a _position_, which is the non-negative integer offset
14092 * (in bytes) in the stream where the next read or write will occur.
14094 * Note that a text stream may have multi-byte characters,
14095 * so a text stream whose position is +n+ (_bytes_) may not have +n+ _characters_
14096 * preceding the current position -- there may be fewer.
14098 * A new stream is initially positioned:
14100 * - At the beginning (position +0+)
14101 * if its mode is <tt>'r'</tt>, <tt>'w'</tt>, or <tt>'r+'</tt>.
14102 * - At the end (position <tt>self.size</tt>)
14103 * if its mode is <tt>'a'</tt>, <tt>'w+'</tt>, or <tt>'a+'</tt>.
14105 * Methods to query the position:
14107 * - IO#tell and its alias IO#pos return the position for an open stream.
14108 * - IO#eof? and its alias IO#eof return whether the position is at the end
14109 * of a readable stream.
14111 * Reading from a stream usually changes its position:
14113 * f = File.open('t.txt')
14114 * f.tell # => 0
14115 * f.readline # => "This is line one.\n"
14116 * f.tell # => 19
14117 * f.readline # => "This is the second line.\n"
14118 * f.tell # => 45
14119 * f.eof? # => false
14120 * f.readline # => "Here's the third line.\n"
14121 * f.eof? # => true
14124 * Writing to a stream usually changes its position:
14126 * f = File.open('t.tmp', 'w')
14127 * f.tell # => 0
14128 * f.write('foo') # => 3
14129 * f.tell # => 3
14130 * f.write('bar') # => 3
14131 * f.tell # => 6
14134 * Iterating over a stream usually changes its position:
14136 * f = File.open('t.txt')
14137 * f.each do |line|
14138 * p "position=#{f.pos} eof?=#{f.eof?} line=#{line}"
14139 * end
14141 * Output:
14143 * "position=19 eof?=false line=This is line one.\n"
14144 * "position=45 eof?=false line=This is the second line.\n"
14145 * "position=70 eof?=true line=This is the third line.\n"
14147 * The position may also be changed by certain other methods:
14149 * - IO#pos= and IO#seek change the position to a specified offset.
14150 * - IO#rewind changes the position to the beginning.
14152 * == Lines
14154 * Some reader methods in \IO are line-oriented;
14155 * such a method reads one or more lines,
14156 * which are separated by an implicit or explicit line separator.
14158 * These methods include:
14160 * - IO::foreach.
14161 * - IO::readlines.
14162 * - IO#each.
14163 * - IO#gets.
14164 * - IO#readline.
14165 * - IO#readlines.
14167 * Each of these methods may be called with:
14169 * - An optional line separator, +sep+.
14170 * - An optional line-size limit, +limit+.
14171 * - Both +sep+ and +limit+.
14173 * === Line Separator
14175 * The default line separator is the given by the global variable <tt>$/</tt>,
14176 * whose value is often <tt>"\n"</tt>.
14177 * The line to be read next is all data from the current position
14178 * to the next line separator:
14180 * f = File.open('t.txt')
14181 * f.gets # => "First line\n"
14182 * f.gets # => "Second line\n"
14183 * f.gets # => "\n"
14184 * f.gets # => "Fourth line\n"
14185 * f.gets # => "Fifth line\n"
14187 * You can specify a different line separator:
14189 * f = File.new('t.txt')
14190 * f.gets('l') # => "First l"
14191 * f.gets('li') # => "ine\nSecond li"
14192 * f.gets('lin') # => "ne\n\nFourth lin"
14193 * f.gets # => "e\n"
14195 * There are two special line separators:
14197 * - +nil+: The entire stream is read into a single string:
14199 * f = File.new('t.txt')
14200 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14202 * - <tt>''</tt> (the empty string): The next "paragraph" is read
14203 * (paragraphs being separated by two consecutive line separators):
14205 * f = File.new('t.txt')
14206 * f.gets('') # => "First line\nSecond line\n\n"
14207 * f.gets('') # => "Fourth line\nFifth line\n"
14209 * === Line Limit
14211 * The line to be read may be further defined by an optional argument +limit+,
14212 * which specifies that the line may not be (much) longer than the given limit;
14213 * a multi-byte character will not be split, and so a line may be slightly longer
14214 * than the given limit.
14216 * If +limit+ is not given, the line is determined only by +sep+.
14218 * # Text with 1-byte characters.
14219 * File.open('t.txt') {|f| f.gets(1) } # => "F"
14220 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
14221 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
14222 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
14223 * # No more than one line.
14224 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
14225 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
14226 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
14228 * # Text with 2-byte characters, which will not be split.
14229 * File.open('t.rus') {|f| f.gets(1).size } # => 1
14230 * File.open('t.rus') {|f| f.gets(2).size } # => 1
14231 * File.open('t.rus') {|f| f.gets(3).size } # => 2
14232 * File.open('t.rus') {|f| f.gets(4).size } # => 2
14234 * With arguments +sep+ and +limit+ given,
14235 * combines the two behaviors:
14237 * - Returns the next line as determined by line separator +sep+,
14238 * or +nil+ if none.
14239 * - But returns no more bytes than are allowed by the limit.
14241 * === Line Number
14243 * A readable \IO stream has a _line_ _number_,
14244 * which is the non-negative integer line number
14245 * in the stream where the next read will occur.
14247 * A new stream is initially has line number +0+.
14249 * \Method IO#lineno returns the line number.
14251 * Reading lines from a stream usually changes its line number:
14253 * f = File.open('t.txt', 'r')
14254 * f.lineno # => 0
14255 * f.readline # => "This is line one.\n"
14256 * f.lineno # => 1
14257 * f.readline # => "This is the second line.\n"
14258 * f.lineno # => 2
14259 * f.readline # => "Here's the third line.\n"
14260 * f.lineno # => 3
14261 * f.eof? # => true
14263 * Iterating over lines in a stream usually changes its line number:
14265 * f = File.open('t.txt')
14266 * f.each_line do |line|
14267 * p "position=#{f.pos} eof?=#{f.eof?} line=#{line}"
14268 * end
14270 * Output:
14272 * "position=19 eof?=false line=This is line one.\n"
14273 * "position=45 eof?=false line=This is the second line.\n"
14274 * "position=70 eof?=true line=This is the third line.\n"
14276 * == What's Here
14278 * First, what's elsewhere. \Class \IO:
14280 * - Inherits from {class Object}[Object.html#class-Object-label-What-27s+Here].
14281 * - Includes {module Enumerable}[Enumerable.html#module-Enumerable-label-What-27s+Here],
14282 * which provides dozens of additional methods.
14284 * Here, class \IO provides methods that are useful for:
14286 * - {Creating}[#class-IO-label-Creating]
14287 * - {Reading}[#class-IO-label-Reading]
14288 * - {Writing}[#class-IO-label-Writing]
14289 * - {Positioning}[#class-IO-label-Positioning]
14290 * - {Iterating}[#class-IO-label-Iterating]
14291 * - {Settings}[#class-IO-label-Settings]
14292 * - {Querying}[#class-IO-label-Querying]
14293 * - {Buffering}[#class-IO-label-Buffering]
14294 * - {Low-Level Access}[#class-IO-label-Low-Level+Access]
14295 * - {Other}[#class-IO-label-Other]
14297 * === Creating
14299 * - ::new (aliased as ::for_fd):: Creates and returns a new \IO object for the given
14300 * integer file descriptor.
14301 * - ::open:: Creates a new \IO object.
14302 * - ::pipe:: Creates a connected pair of reader and writer \IO objects.
14303 * - ::popen:: Creates an \IO object to interact with a subprocess.
14304 * - ::select:: Selects which given \IO instances are ready for reading,
14305 * writing, or have pending exceptions.
14307 * === Reading
14309 * - ::binread:: Returns a binary string with all or a subset of bytes
14310 * from the given file.
14311 * - ::read:: Returns a string with all or a subset of bytes from the given file.
14312 * - ::readlines:: Returns an array of strings, which are the lines from the given file.
14313 * - #getbyte:: Returns the next 8-bit byte read from +self+ as an integer.
14314 * - #getc:: Returns the next character read from +self+ as a string.
14315 * - #gets:: Returns the line read from +self+.
14316 * - #pread:: Returns all or the next _n_ bytes read from +self+,
14317 * not updating the receiver's offset.
14318 * - #read:: Returns all remaining or the next _n_ bytes read from +self+
14319 * for a given _n_.
14320 * - #read_nonblock:: the next _n_ bytes read from +self+ for a given _n_,
14321 * in non-block mode.
14322 * - #readbyte:: Returns the next byte read from +self+;
14323 * same as #getbyte, but raises an exception on end-of-file.
14324 * - #readchar:: Returns the next character read from +self+;
14325 * same as #getc, but raises an exception on end-of-file.
14326 * - #readline:: Returns the next line read from +self+;
14327 * same as #getline, but raises an exception of end-of-file.
14328 * - #readlines:: Returns an array of all lines read read from +self+.
14329 * - #readpartial:: Returns up to the given number of bytes from +self+.
14331 * === Writing
14333 * - ::binwrite:: Writes the given string to the file at the given filepath,
14334 in binary mode.
14335 * - ::write:: Writes the given string to +self+.
14336 * - {::<<}[#method-i-3C-3C]:: Appends the given string to +self+.
14337 * - #print:: Prints last read line or given objects to +self+.
14338 * - #printf:: Writes to +self+ based on the given format string and objects.
14339 * - #putc:: Writes a character to +self+.
14340 * - #puts:: Writes lines to +self+, making sure line ends with a newline.
14341 * - #pwrite:: Writes the given string at the given offset,
14342 * not updating the receiver's offset.
14343 * - #write:: Writes one or more given strings to +self+.
14344 * - #write_nonblock:: Writes one or more given strings to +self+ in non-blocking mode.
14346 * === Positioning
14348 * - #lineno:: Returns the current line number in +self+.
14349 * - #lineno=:: Sets the line number is +self+.
14350 * - #pos (aliased as #tell):: Returns the current byte offset in +self+.
14351 * - #pos=:: Sets the byte offset in +self+.
14352 * - #reopen:: Reassociates +self+ with a new or existing \IO stream.
14353 * - #rewind:: Positions +self+ to the beginning of input.
14354 * - #seek:: Sets the offset for +self+ relative to given position.
14356 * === Iterating
14358 * - ::foreach:: Yields each line of given file to the block.
14359 * - #each (aliased as #each_line):: Calls the given block
14360 * with each successive line in +self+.
14361 * - #each_byte:: Calls the given block with each successive byte in +self+
14362 * as an integer.
14363 * - #each_char:: Calls the given block with each successive character in +self+
14364 * as a string.
14365 * - #each_codepoint:: Calls the given block with each successive codepoint in +self+
14366 * as an integer.
14368 * === Settings
14370 * - #autoclose=:: Sets whether +self+ auto-closes.
14371 * - #binmode:: Sets +self+ to binary mode.
14372 * - #close:: Closes +self+.
14373 * - #close_on_exec=:: Sets the close-on-exec flag.
14374 * - #close_read:: Closes +self+ for reading.
14375 * - #close_write:: Closes +self+ for writing.
14376 * - #set_encoding:: Sets the encoding for +self+.
14377 * - #set_encoding_by_bom:: Sets the encoding for +self+, based on its
14378 * Unicode byte-order-mark.
14379 * - #sync=:: Sets the sync-mode to the given value.
14381 * === Querying
14383 * - #autoclose?:: Returns whether +self+ auto-closes.
14384 * - #binmode?:: Returns whether +self+ is in binary mode.
14385 * - #close_on_exec?:: Returns the close-on-exec flag for +self+.
14386 * - #closed?:: Returns whether +self+ is closed.
14387 * - #eof? (aliased as #eof):: Returns whether +self+ is at end-of-file.
14388 * - #external_encoding:: Returns the external encoding object for +self+.
14389 * - #fileno (aliased as #to_i):: Returns the integer file descriptor for +self+
14390 * - #internal_encoding:: Returns the internal encoding object for +self+.
14391 * - #pid:: Returns the process ID of a child process associated with +self+,
14392 * if +self+ was created by ::popen.
14393 * - #stat:: Returns the File::Stat object containing status information for +self+.
14394 * - #sync:: Returns whether +self+ is in sync-mode.
14395 * - #tty (aliased as #isatty):: Returns whether +self+ is a terminal.
14397 * === Buffering
14399 * - #fdatasync:: Immediately writes all buffered data in +self+ to disk.
14400 * - #flush:: Flushes any buffered data within +self+ to the underlying
14401 * operating system.
14402 * - #fsync:: Immediately writes all buffered data and attributes in +self+ to disk.
14403 * - #ungetbyte:: Prepends buffer for +self+ with given integer byte or string.
14404 * - #ungetc:: Prepends buffer for +self+ with given string.
14406 * === Low-Level Access
14408 * - ::sysopen:: Opens the file given by its path,
14409 * returning the integer file descriptor.
14410 * - #advise:: Announces the intention to access data from +self+ in a specific way.
14411 * - #fcntl:: Passes a low-level command to the file specified
14412 * by the given file descriptor.
14413 * - #ioctl:: Passes a low-level command to the device specified
14414 * by the given file descriptor.
14415 * - #sysread:: Returns up to the next _n_ bytes read from self using a low-level read.
14416 * - #sysseek:: Sets the offset for +self+.
14417 * - #syswrite:: Writes the given string to +self+ using a low-level write.
14419 * === Other
14421 * - ::copy_stream:: Copies data from a source to a destination,
14422 * each of which is a filepath or an \IO-like object.
14423 * - ::try_convert:: Returns a new \IO object resulting from converting
14424 * the given object.
14425 * - #inspect:: Returns the string representation of +self+.
14429 void
14430 Init_IO(void)
14432 VALUE rb_cARGF;
14433 #ifdef __CYGWIN__
14434 #include <sys/cygwin.h>
14435 static struct __cygwin_perfile pf[] =
14437 {"", O_RDONLY | O_BINARY},
14438 {"", O_WRONLY | O_BINARY},
14439 {"", O_RDWR | O_BINARY},
14440 {"", O_APPEND | O_BINARY},
14441 {NULL, 0}
14443 cygwin_internal(CW_PERFILE, pf);
14444 #endif
14446 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
14447 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
14449 id_write = rb_intern_const("write");
14450 id_read = rb_intern_const("read");
14451 id_getc = rb_intern_const("getc");
14452 id_flush = rb_intern_const("flush");
14453 id_readpartial = rb_intern_const("readpartial");
14454 id_set_encoding = rb_intern_const("set_encoding");
14455 id_fileno = rb_intern_const("fileno");
14457 rb_define_global_function("syscall", rb_f_syscall, -1);
14459 rb_define_global_function("open", rb_f_open, -1);
14460 rb_define_global_function("printf", rb_f_printf, -1);
14461 rb_define_global_function("print", rb_f_print, -1);
14462 rb_define_global_function("putc", rb_f_putc, 1);
14463 rb_define_global_function("puts", rb_f_puts, -1);
14464 rb_define_global_function("gets", rb_f_gets, -1);
14465 rb_define_global_function("readline", rb_f_readline, -1);
14466 rb_define_global_function("select", rb_f_select, -1);
14468 rb_define_global_function("readlines", rb_f_readlines, -1);
14470 rb_define_global_function("`", rb_f_backquote, 1);
14472 rb_define_global_function("p", rb_f_p, -1);
14473 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
14475 rb_cIO = rb_define_class("IO", rb_cObject);
14476 rb_include_module(rb_cIO, rb_mEnumerable);
14478 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
14479 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
14480 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
14482 /* exception to wait for reading. see IO.select. */
14483 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
14484 /* exception to wait for writing. see IO.select. */
14485 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
14486 /* exception to wait for reading by EAGAIN. see IO.select. */
14487 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
14488 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
14489 /* exception to wait for writing by EAGAIN. see IO.select. */
14490 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
14491 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
14492 #if EAGAIN == EWOULDBLOCK
14493 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
14494 /* same as IO::EAGAINWaitReadable */
14495 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
14496 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
14497 /* same as IO::EAGAINWaitWritable */
14498 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
14499 #else
14500 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
14501 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
14502 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
14503 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
14504 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
14505 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
14506 #endif
14507 /* exception to wait for reading by EINPROGRESS. see IO.select. */
14508 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
14509 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
14510 /* exception to wait for writing by EINPROGRESS. see IO.select. */
14511 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
14512 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
14514 #if 0
14515 /* This is necessary only for forcing rdoc handle File::open */
14516 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
14517 #endif
14519 rb_define_alloc_func(rb_cIO, io_alloc);
14520 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
14521 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
14522 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
14523 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
14524 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
14525 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
14526 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
14527 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
14528 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
14529 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
14530 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
14531 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
14532 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
14533 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
14534 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
14536 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
14538 rb_output_fs = Qnil;
14539 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
14541 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
14542 rb_gc_register_mark_object(rb_default_rs);
14543 rb_rs = rb_default_rs;
14544 rb_output_rs = Qnil;
14545 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
14546 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
14547 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
14549 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
14550 rb_gvar_ractor_local("$_");
14552 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
14553 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
14555 rb_define_method(rb_cIO, "print", rb_io_print, -1);
14556 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
14557 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
14558 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
14560 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
14561 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
14562 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
14563 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
14564 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
14566 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
14567 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
14569 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
14570 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
14572 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
14573 rb_define_alias(rb_cIO, "to_i", "fileno");
14574 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
14576 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
14577 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
14578 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
14579 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
14581 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
14582 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
14584 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
14586 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
14587 rb_define_method(rb_cIO, "read", io_read, -1);
14588 rb_define_method(rb_cIO, "write", io_write_m, -1);
14589 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
14590 rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
14591 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
14592 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
14593 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
14594 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
14595 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
14596 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
14597 rb_define_method(rb_cIO, "<<", rb_io_addstr, 1);
14598 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
14599 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
14600 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
14601 /* Set I/O position from the beginning */
14602 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
14603 /* Set I/O position from the current position */
14604 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
14605 /* Set I/O position from the end */
14606 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
14607 #ifdef SEEK_DATA
14608 /* Set I/O position to the next location containing data */
14609 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
14610 #endif
14611 #ifdef SEEK_HOLE
14612 /* Set I/O position to the next hole */
14613 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
14614 #endif
14615 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
14616 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
14617 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
14618 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
14619 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
14621 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
14622 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
14624 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
14625 rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
14626 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
14627 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
14629 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
14630 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
14631 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
14632 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
14633 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
14634 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
14636 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
14637 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
14638 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
14639 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
14641 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
14642 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
14643 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
14644 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
14646 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
14647 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
14649 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
14650 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
14651 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
14652 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
14654 rb_gvar_ractor_local("$stdin");
14655 rb_gvar_ractor_local("$stdout");
14656 rb_gvar_ractor_local("$>");
14657 rb_gvar_ractor_local("$stderr");
14659 rb_stdin = rb_io_prep_stdin();
14660 rb_stdout = rb_io_prep_stdout();
14661 rb_stderr = rb_io_prep_stderr();
14663 rb_global_variable(&rb_stdin);
14664 rb_global_variable(&rb_stdout);
14665 rb_global_variable(&rb_stderr);
14667 orig_stdout = rb_stdout;
14668 orig_stderr = rb_stderr;
14670 /* Holds the original stdin */
14671 rb_define_global_const("STDIN", rb_stdin);
14672 /* Holds the original stdout */
14673 rb_define_global_const("STDOUT", rb_stdout);
14674 /* Holds the original stderr */
14675 rb_define_global_const("STDERR", rb_stderr);
14677 #if 0
14678 /* Hack to get rdoc to regard ARGF as a class: */
14679 rb_cARGF = rb_define_class("ARGF", rb_cObject);
14680 #endif
14682 rb_cARGF = rb_class_new(rb_cObject);
14683 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
14684 rb_define_alloc_func(rb_cARGF, argf_alloc);
14686 rb_include_module(rb_cARGF, rb_mEnumerable);
14688 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
14689 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
14690 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
14691 rb_define_alias(rb_cARGF, "inspect", "to_s");
14692 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
14694 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
14695 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
14696 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
14697 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
14698 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
14699 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
14700 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
14701 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
14702 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
14704 rb_define_method(rb_cARGF, "read", argf_read, -1);
14705 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
14706 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
14707 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
14708 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
14709 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
14710 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
14711 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
14712 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
14713 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
14714 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
14715 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
14716 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
14717 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
14718 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
14719 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
14720 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
14721 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
14722 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
14723 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
14725 rb_define_method(rb_cARGF, "write", argf_write, 1);
14726 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
14727 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
14728 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
14729 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
14731 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
14732 rb_define_method(rb_cARGF, "path", argf_filename, 0);
14733 rb_define_method(rb_cARGF, "file", argf_file, 0);
14734 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
14735 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
14736 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
14738 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
14739 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
14741 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
14742 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
14744 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
14745 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
14746 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
14748 argf = rb_class_new_instance(0, 0, rb_cARGF);
14750 rb_define_readonly_variable("$<", &argf);
14752 * ARGF is a stream designed for use in scripts that process files given
14753 * as command-line arguments or passed in via STDIN.
14755 * See ARGF (the class) for more details.
14757 rb_define_global_const("ARGF", argf);
14759 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
14760 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
14761 ARGF.filename = rb_str_new2("-");
14763 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
14764 rb_gvar_ractor_local("$-i");
14766 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
14768 #if defined (_WIN32) || defined(__CYGWIN__)
14769 atexit(pipe_atexit);
14770 #endif
14772 Init_File();
14774 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
14776 sym_mode = ID2SYM(rb_intern_const("mode"));
14777 sym_perm = ID2SYM(rb_intern_const("perm"));
14778 sym_flags = ID2SYM(rb_intern_const("flags"));
14779 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
14780 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
14781 sym_encoding = ID2SYM(rb_id_encoding());
14782 sym_open_args = ID2SYM(rb_intern_const("open_args"));
14783 sym_textmode = ID2SYM(rb_intern_const("textmode"));
14784 sym_binmode = ID2SYM(rb_intern_const("binmode"));
14785 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
14786 sym_normal = ID2SYM(rb_intern_const("normal"));
14787 sym_sequential = ID2SYM(rb_intern_const("sequential"));
14788 sym_random = ID2SYM(rb_intern_const("random"));
14789 sym_willneed = ID2SYM(rb_intern_const("willneed"));
14790 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
14791 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
14792 sym_SET = ID2SYM(rb_intern_const("SET"));
14793 sym_CUR = ID2SYM(rb_intern_const("CUR"));
14794 sym_END = ID2SYM(rb_intern_const("END"));
14795 #ifdef SEEK_DATA
14796 sym_DATA = ID2SYM(rb_intern_const("DATA"));
14797 #endif
14798 #ifdef SEEK_HOLE
14799 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
14800 #endif
14801 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
14802 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
14805 #include "io.rbinc"