[ruby/win32ole] Undefine allocator of WIN32OLE_VARIABLE to get rid of warning
[ruby-80x24.org.git] / io.c
blob7ff7e5a33c69328530e53f2523d0b06c77256674
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, count);
1138 if (result != Qundef) {
1139 ssize_t length = rb_fiber_scheduler_io_result_apply(result);
1141 if (length < 0) rb_sys_fail_path(fptr->pathv);
1143 return length;
1147 struct io_internal_read_struct iis = {
1148 .th = rb_thread_current(),
1149 .fptr = fptr,
1150 .nonblock = 0,
1151 .buf = buf,
1152 .capa = count
1155 return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fptr->fd);
1158 static ssize_t
1159 rb_write_internal(rb_io_t *fptr, const void *buf, size_t count)
1161 VALUE scheduler = rb_fiber_scheduler_current();
1162 if (scheduler != Qnil) {
1163 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1165 if (result != Qundef) {
1166 return rb_fiber_scheduler_io_result_apply(result);
1170 struct io_internal_write_struct iis = {
1171 .fd = fptr->fd,
1172 .buf = buf,
1173 .capa = count
1176 if (fptr->write_lock && rb_mutex_owned_p(fptr->write_lock))
1177 return (ssize_t)rb_thread_call_without_gvl2(internal_write_func2, &iis, RUBY_UBF_IO, NULL);
1178 else
1179 return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fptr->fd);
1182 #ifdef HAVE_WRITEV
1183 static ssize_t
1184 rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1186 VALUE scheduler = rb_fiber_scheduler_current();
1187 if (scheduler != Qnil) {
1188 for (int i = 0; i < iovcnt; i += 1) {
1189 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[i].iov_base, iov[i].iov_len, 0);
1191 if (result != Qundef) {
1192 return rb_fiber_scheduler_io_result_apply(result);
1197 struct io_internal_writev_struct iis = {
1198 .fd = fptr->fd,
1199 .iov = iov,
1200 .iovcnt = iovcnt,
1203 return (ssize_t)rb_thread_io_blocking_region(internal_writev_func, &iis, fptr->fd);
1205 #endif
1207 static VALUE
1208 io_flush_buffer_sync(void *arg)
1210 rb_io_t *fptr = arg;
1211 long l = fptr->wbuf.len;
1212 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1214 if (fptr->wbuf.len <= r) {
1215 fptr->wbuf.off = 0;
1216 fptr->wbuf.len = 0;
1217 return 0;
1219 if (0 <= r) {
1220 fptr->wbuf.off += (int)r;
1221 fptr->wbuf.len -= (int)r;
1222 errno = EAGAIN;
1224 return (VALUE)-1;
1227 static void*
1228 io_flush_buffer_sync2(void *arg)
1230 VALUE result = io_flush_buffer_sync(arg);
1233 * rb_thread_call_without_gvl2 uses 0 as interrupted.
1234 * So, we need to avoid to use 0.
1236 return !result ? (void*)1 : (void*)result;
1239 static VALUE
1240 io_flush_buffer_async(VALUE arg)
1242 rb_io_t *fptr = (rb_io_t *)arg;
1243 return rb_thread_io_blocking_region(io_flush_buffer_sync, fptr, fptr->fd);
1246 static VALUE
1247 io_flush_buffer_async2(VALUE arg)
1249 rb_io_t *fptr = (rb_io_t *)arg;
1250 VALUE ret;
1252 ret = (VALUE)rb_thread_call_without_gvl2(io_flush_buffer_sync2, fptr, RUBY_UBF_IO, NULL);
1254 if (!ret) {
1255 /* pending async interrupt is there. */
1256 errno = EAGAIN;
1257 return -1;
1259 else if (ret == 1) {
1260 return 0;
1262 return ret;
1265 static inline int
1266 io_flush_buffer(rb_io_t *fptr)
1268 if (fptr->write_lock) {
1269 if (rb_mutex_owned_p(fptr->write_lock))
1270 return (int)io_flush_buffer_async2((VALUE)fptr);
1271 else
1272 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async2, (VALUE)fptr);
1274 else {
1275 return (int)io_flush_buffer_async((VALUE)fptr);
1279 static int
1280 io_fflush(rb_io_t *fptr)
1282 rb_io_check_closed(fptr);
1284 if (fptr->wbuf.len == 0)
1285 return 0;
1287 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1288 if (!rb_io_maybe_wait_writable(errno, fptr->self, Qnil))
1289 return -1;
1291 rb_io_check_closed(fptr);
1294 return 0;
1297 VALUE
1298 rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1300 VALUE scheduler = rb_fiber_scheduler_current();
1302 if (scheduler != Qnil) {
1303 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1306 rb_io_t * fptr = NULL;
1307 RB_IO_POINTER(io, fptr);
1309 struct timeval tv_storage;
1310 struct timeval *tv = NULL;
1312 if (timeout != Qnil) {
1313 tv_storage = rb_time_interval(timeout);
1314 tv = &tv_storage;
1317 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1319 if (ready < 0) {
1320 rb_sys_fail(0);
1323 // Not sure if this is necessary:
1324 rb_io_check_closed(fptr);
1326 if (ready) {
1327 return RB_INT2NUM(ready);
1329 else {
1330 return Qfalse;
1334 static VALUE
1335 io_from_fd(int fd)
1337 return prep_io(fd, FMODE_PREP, rb_cIO, NULL);
1340 static int
1341 io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1343 VALUE scheduler = rb_fiber_scheduler_current();
1345 if (scheduler != Qnil) {
1346 return RTEST(
1347 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1351 return rb_thread_wait_for_single_fd(fd, events, timeout);
1355 rb_io_wait_readable(int f)
1357 io_fd_check_closed(f);
1359 VALUE scheduler = rb_fiber_scheduler_current();
1361 switch (errno) {
1362 case EINTR:
1363 #if defined(ERESTART)
1364 case ERESTART:
1365 #endif
1366 rb_thread_check_ints();
1367 return TRUE;
1369 case EAGAIN:
1370 #if EWOULDBLOCK != EAGAIN
1371 case EWOULDBLOCK:
1372 #endif
1373 if (scheduler != Qnil) {
1374 return RTEST(
1375 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1378 else {
1379 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1381 return TRUE;
1383 default:
1384 return FALSE;
1389 rb_io_wait_writable(int f)
1391 io_fd_check_closed(f);
1393 VALUE scheduler = rb_fiber_scheduler_current();
1395 switch (errno) {
1396 case EINTR:
1397 #if defined(ERESTART)
1398 case ERESTART:
1399 #endif
1401 * In old Linux, several special files under /proc and /sys don't handle
1402 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1403 * Otherwise, we face nasty hang up. Sigh.
1404 * e.g. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
1405 * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
1406 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1407 * Then rb_thread_check_ints() is enough.
1409 rb_thread_check_ints();
1410 return TRUE;
1412 case EAGAIN:
1413 #if EWOULDBLOCK != EAGAIN
1414 case EWOULDBLOCK:
1415 #endif
1416 if (scheduler != Qnil) {
1417 return RTEST(
1418 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1421 else {
1422 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1424 return TRUE;
1426 default:
1427 return FALSE;
1432 rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1434 return io_wait_for_single_fd(fd, events, timeout);
1438 rb_thread_wait_fd(int fd)
1440 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1444 rb_thread_fd_writable(int fd)
1446 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1449 VALUE
1450 rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1452 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1453 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1454 // instead relies on `read(-1) -> -1` which causes this code path. We then
1455 // check here whether the IO was in fact closed. Probably it's better to
1456 // check that `fptr->fd != -1` before using it in syscall.
1457 rb_io_check_closed(RFILE(io)->fptr);
1459 switch (error) {
1460 // In old Linux, several special files under /proc and /sys don't handle
1461 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1462 // Otherwise, we face nasty hang up. Sigh.
1463 // e.g. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
1464 // http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
1465 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1466 // Then rb_thread_check_ints() is enough.
1467 case EINTR:
1468 #if defined(ERESTART)
1469 case ERESTART:
1470 #endif
1471 // We might have pending interrupts since the previous syscall was interrupted:
1472 rb_thread_check_ints();
1474 // The operation was interrupted, so retry it immediately:
1475 return events;
1477 case EAGAIN:
1478 #if EWOULDBLOCK != EAGAIN
1479 case EWOULDBLOCK:
1480 #endif
1481 // The operation would block, so wait for the specified events:
1482 return rb_io_wait(io, events, timeout);
1484 default:
1485 // Non-specific error, no event is ready:
1486 return Qfalse;
1491 rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
1493 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1495 if (RTEST(result)) {
1496 return RB_NUM2INT(result);
1498 else {
1499 return 0;
1504 rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
1506 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1508 if (RTEST(result)) {
1509 return RB_NUM2INT(result);
1511 else {
1512 return 0;
1516 static void
1517 make_writeconv(rb_io_t *fptr)
1519 if (!fptr->writeconv_initialized) {
1520 const char *senc, *denc;
1521 rb_encoding *enc;
1522 int ecflags;
1523 VALUE ecopts;
1525 fptr->writeconv_initialized = 1;
1527 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1528 ecopts = fptr->encs.ecopts;
1530 if (!fptr->encs.enc || (fptr->encs.enc == rb_ascii8bit_encoding() && !fptr->encs.enc2)) {
1531 /* no encoding conversion */
1532 fptr->writeconv_pre_ecflags = 0;
1533 fptr->writeconv_pre_ecopts = Qnil;
1534 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1535 if (!fptr->writeconv)
1536 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1537 fptr->writeconv_asciicompat = Qnil;
1539 else {
1540 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1541 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1542 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1543 /* single conversion */
1544 fptr->writeconv_pre_ecflags = ecflags;
1545 fptr->writeconv_pre_ecopts = ecopts;
1546 fptr->writeconv = NULL;
1547 fptr->writeconv_asciicompat = Qnil;
1549 else {
1550 /* double conversion */
1551 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1552 fptr->writeconv_pre_ecopts = ecopts;
1553 if (senc) {
1554 denc = rb_enc_name(enc);
1555 fptr->writeconv_asciicompat = rb_str_new2(senc);
1557 else {
1558 senc = denc = "";
1559 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1561 ecflags = fptr->encs.ecflags & (ECONV_ERROR_HANDLER_MASK|ECONV_STATEFUL_DECORATOR_MASK);
1562 ecopts = fptr->encs.ecopts;
1563 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1564 if (!fptr->writeconv)
1565 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1571 /* writing functions */
1572 struct binwrite_arg {
1573 rb_io_t *fptr;
1574 VALUE str;
1575 const char *ptr;
1576 long length;
1579 struct write_arg {
1580 VALUE io;
1581 VALUE str;
1582 int nosync;
1585 #ifdef HAVE_WRITEV
1586 static VALUE
1587 io_binwrite_string(VALUE arg)
1589 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1590 rb_io_t *fptr = p->fptr;
1591 long r;
1593 if (fptr->wbuf.len) {
1594 struct iovec iov[2];
1596 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1597 iov[0].iov_len = fptr->wbuf.len;
1598 iov[1].iov_base = (char *)p->ptr;
1599 iov[1].iov_len = p->length;
1601 r = rb_writev_internal(fptr, iov, 2);
1603 if (r < 0)
1604 return r;
1606 if (fptr->wbuf.len <= r) {
1607 r -= fptr->wbuf.len;
1608 fptr->wbuf.off = 0;
1609 fptr->wbuf.len = 0;
1611 else {
1612 fptr->wbuf.off += (int)r;
1613 fptr->wbuf.len -= (int)r;
1614 r = 0L;
1617 else {
1618 r = rb_write_internal(fptr, p->ptr, p->length);
1621 return r;
1623 #else
1624 static VALUE
1625 io_binwrite_string(VALUE arg)
1627 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1628 rb_io_t *fptr = p->fptr;
1629 long l, len;
1631 l = len = p->length;
1633 if (fptr->wbuf.len) {
1634 if (fptr->wbuf.len+len <= fptr->wbuf.capa) {
1635 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+len) {
1636 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1637 fptr->wbuf.off = 0;
1639 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, p->ptr, char, len);
1640 fptr->wbuf.len += (int)len;
1641 l = 0;
1643 if (io_fflush(fptr) < 0)
1644 return -2L; /* fail in fflush */
1645 if (l == 0)
1646 return len;
1649 return rb_write_internal(p->fptr, p->ptr, p->length);
1651 #endif
1653 static long
1654 io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
1656 long n, r, offset = 0;
1658 /* don't write anything if current thread has a pending interrupt. */
1659 rb_thread_check_ints();
1661 if ((n = len) <= 0) return n;
1663 if (fptr->wbuf.ptr == NULL && !(!nosync && (fptr->mode & FMODE_SYNC))) {
1664 fptr->wbuf.off = 0;
1665 fptr->wbuf.len = 0;
1666 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1667 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1668 fptr->write_lock = rb_mutex_new();
1669 rb_mutex_allow_trap(fptr->write_lock, 1);
1672 if ((!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY))) ||
1673 (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)) {
1674 struct binwrite_arg arg;
1676 arg.fptr = fptr;
1677 arg.str = str;
1678 retry:
1679 arg.ptr = ptr + offset;
1680 arg.length = n;
1682 if (fptr->write_lock) {
1683 r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1685 else {
1686 r = io_binwrite_string((VALUE)&arg);
1689 /* xxx: other threads may modify given string. */
1690 if (r == n) return len;
1691 if (0 <= r) {
1692 offset += r;
1693 n -= r;
1694 errno = EAGAIN;
1697 if (r == -2L)
1698 return -1L;
1699 if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) {
1700 rb_io_check_closed(fptr);
1702 if (offset < len)
1703 goto retry;
1706 return -1L;
1709 if (fptr->wbuf.off) {
1710 if (fptr->wbuf.len)
1711 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1712 fptr->wbuf.off = 0;
1715 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr+offset, char, len);
1716 fptr->wbuf.len += (int)len;
1718 return len;
1721 # define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1722 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1724 #define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1725 MODE_BTMODE(d, e, f) : \
1726 MODE_BTMODE(a, b, c))
1728 static VALUE
1729 do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1731 if (NEED_WRITECONV(fptr)) {
1732 VALUE common_encoding = Qnil;
1733 SET_BINARY_MODE(fptr);
1735 make_writeconv(fptr);
1737 if (fptr->writeconv) {
1738 #define fmode (fptr->mode)
1739 if (!NIL_P(fptr->writeconv_asciicompat))
1740 common_encoding = fptr->writeconv_asciicompat;
1741 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1742 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1743 rb_enc_name(rb_enc_get(str)));
1745 #undef fmode
1747 else {
1748 if (fptr->encs.enc2)
1749 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1750 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1751 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1754 if (!NIL_P(common_encoding)) {
1755 str = rb_str_encode(str, common_encoding,
1756 fptr->writeconv_pre_ecflags, fptr->writeconv_pre_ecopts);
1757 *converted = 1;
1760 if (fptr->writeconv) {
1761 str = rb_econv_str_convert(fptr->writeconv, str, ECONV_PARTIAL_INPUT);
1762 *converted = 1;
1765 #if RUBY_CRLF_ENVIRONMENT
1766 #define fmode (fptr->mode)
1767 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1768 if ((fptr->mode & FMODE_READABLE) &&
1769 !(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
1770 setmode(fptr->fd, O_BINARY);
1772 else {
1773 setmode(fptr->fd, O_TEXT);
1775 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1776 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1777 rb_enc_name(rb_enc_get(str)));
1780 #undef fmode
1781 #endif
1782 return str;
1785 static long
1786 io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1788 int converted = 0;
1789 VALUE tmp;
1790 long n, len;
1791 const char *ptr;
1792 #ifdef _WIN32
1793 if (fptr->mode & FMODE_TTY) {
1794 long len = rb_w32_write_console(str, fptr->fd);
1795 if (len > 0) return len;
1797 #endif
1798 str = do_writeconv(str, fptr, &converted);
1799 if (converted)
1800 OBJ_FREEZE(str);
1802 tmp = rb_str_tmp_frozen_acquire(str);
1803 RSTRING_GETMEM(tmp, ptr, len);
1804 n = io_binwrite(tmp, ptr, len, fptr, nosync);
1805 rb_str_tmp_frozen_release(str, tmp);
1807 return n;
1810 ssize_t
1811 rb_io_bufwrite(VALUE io, const void *buf, size_t size)
1813 rb_io_t *fptr;
1815 GetOpenFile(io, fptr);
1816 rb_io_check_writable(fptr);
1817 return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
1820 static VALUE
1821 io_write(VALUE io, VALUE str, int nosync)
1823 rb_io_t *fptr;
1824 long n;
1825 VALUE tmp;
1827 io = GetWriteIO(io);
1828 str = rb_obj_as_string(str);
1829 tmp = rb_io_check_io(io);
1830 if (NIL_P(tmp)) {
1831 /* port is not IO, call write method for it. */
1832 return rb_funcall(io, id_write, 1, str);
1834 io = tmp;
1835 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
1837 GetOpenFile(io, fptr);
1838 rb_io_check_writable(fptr);
1840 n = io_fwrite(str, fptr, nosync);
1841 if (n < 0L) rb_sys_fail_on_write(fptr);
1843 return LONG2FIX(n);
1846 #ifdef HAVE_WRITEV
1847 struct binwritev_arg {
1848 rb_io_t *fptr;
1849 const struct iovec *iov;
1850 int iovcnt;
1853 static VALUE
1854 call_writev_internal(VALUE arg)
1856 struct binwritev_arg *p = (struct binwritev_arg *)arg;
1857 return rb_writev_internal(p->fptr, p->iov, p->iovcnt);
1860 static long
1861 io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
1863 int i;
1864 long r, total = 0, written_len = 0;
1866 /* don't write anything if current thread has a pending interrupt. */
1867 rb_thread_check_ints();
1869 if (iovcnt == 0) return 0;
1870 for (i = 1; i < iovcnt; i++) total += iov[i].iov_len;
1872 if (fptr->wbuf.ptr == NULL && !(fptr->mode & FMODE_SYNC)) {
1873 fptr->wbuf.off = 0;
1874 fptr->wbuf.len = 0;
1875 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1876 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1877 fptr->write_lock = rb_mutex_new();
1878 rb_mutex_allow_trap(fptr->write_lock, 1);
1881 if (fptr->wbuf.ptr && fptr->wbuf.len) {
1882 long offset = fptr->wbuf.off + fptr->wbuf.len;
1883 if (offset + total <= fptr->wbuf.capa) {
1884 for (i = 1; i < iovcnt; i++) {
1885 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
1886 offset += iov[i].iov_len;
1888 fptr->wbuf.len += total;
1889 return total;
1891 else {
1892 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
1893 iov[0].iov_len = fptr->wbuf.len;
1896 else {
1897 iov++;
1898 if (!--iovcnt) return 0;
1901 retry:
1902 if (fptr->write_lock) {
1903 struct binwritev_arg arg;
1904 arg.fptr = fptr;
1905 arg.iov = iov;
1906 arg.iovcnt = iovcnt;
1907 r = rb_mutex_synchronize(fptr->write_lock, call_writev_internal, (VALUE)&arg);
1909 else {
1910 r = rb_writev_internal(fptr, iov, iovcnt);
1913 if (r >= 0) {
1914 written_len += r;
1915 if (fptr->wbuf.ptr && fptr->wbuf.len) {
1916 if (written_len < fptr->wbuf.len) {
1917 fptr->wbuf.off += r;
1918 fptr->wbuf.len -= r;
1920 else {
1921 written_len -= fptr->wbuf.len;
1922 fptr->wbuf.off = 0;
1923 fptr->wbuf.len = 0;
1926 if (written_len == total) return total;
1928 while (r >= (ssize_t)iov->iov_len) {
1929 /* iovcnt > 0 */
1930 r -= iov->iov_len;
1931 iov->iov_len = 0;
1932 iov++;
1933 if (!--iovcnt) return total;
1934 /* defensive check: written_len should == total */
1936 iov->iov_base = (char *)iov->iov_base + r;
1937 iov->iov_len -= r;
1939 errno = EAGAIN;
1941 if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) {
1942 rb_io_check_closed(fptr);
1943 goto retry;
1946 return -1L;
1949 static long
1950 io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
1952 int i, converted, iovcnt = argc + 1;
1953 long n;
1954 VALUE v1, v2, str, tmp, *tmp_array;
1955 struct iovec *iov;
1957 iov = ALLOCV_N(struct iovec, v1, iovcnt);
1958 tmp_array = ALLOCV_N(VALUE, v2, argc);
1960 for (i = 0; i < argc; i++) {
1961 str = rb_obj_as_string(argv[i]);
1962 converted = 0;
1963 str = do_writeconv(str, fptr, &converted);
1964 if (converted)
1965 OBJ_FREEZE(str);
1967 tmp = rb_str_tmp_frozen_acquire(str);
1968 tmp_array[i] = tmp;
1969 /* iov[0] is reserved for buffer of fptr */
1970 iov[i+1].iov_base = RSTRING_PTR(tmp);
1971 iov[i+1].iov_len = RSTRING_LEN(tmp);
1974 n = io_binwritev(iov, iovcnt, fptr);
1975 if (v1) ALLOCV_END(v1);
1977 for (i = 0; i < argc; i++) {
1978 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
1981 if (v2) ALLOCV_END(v2);
1983 return n;
1986 static int
1987 iovcnt_ok(int iovcnt)
1989 #ifdef IOV_MAX
1990 return iovcnt < IOV_MAX;
1991 #else /* GNU/Hurd has writev, but no IOV_MAX */
1992 return 1;
1993 #endif
1995 #endif /* HAVE_WRITEV */
1997 static VALUE
1998 io_writev(int argc, const VALUE *argv, VALUE io)
2000 rb_io_t *fptr;
2001 long n;
2002 VALUE tmp, total = INT2FIX(0);
2003 int i, cnt = 1;
2005 io = GetWriteIO(io);
2006 tmp = rb_io_check_io(io);
2007 if (NIL_P(tmp)) {
2008 /* port is not IO, call write method for it. */
2009 return rb_funcallv(io, id_write, argc, argv);
2011 io = tmp;
2013 GetOpenFile(io, fptr);
2014 rb_io_check_writable(fptr);
2016 for (i = 0; i < argc; i += cnt) {
2017 #ifdef HAVE_WRITEV
2018 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2019 n = io_fwritev(cnt, &argv[i], fptr);
2021 else
2022 #endif
2024 cnt = 1;
2025 /* sync at last item */
2026 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2028 if (n < 0L) rb_sys_fail_on_write(fptr);
2029 total = rb_fix_plus(LONG2FIX(n), total);
2032 return total;
2036 * call-seq:
2037 * write(*objects) -> integer
2039 * Writes each of the given +objects+ to +self+,
2040 * which must be opened for writing (see {Modes}[#class-IO-label-Modes]);
2041 * returns the total number bytes written;
2042 * each of +objects+ that is not a string is converted via method +to_s+:
2044 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2045 * $stdout.write('foo', :bar, 2, "\n") # => 8
2047 * Output:
2049 * Hello, World!
2050 * foobar2
2054 static VALUE
2055 io_write_m(int argc, VALUE *argv, VALUE io)
2057 if (argc != 1) {
2058 return io_writev(argc, argv, io);
2060 else {
2061 VALUE str = argv[0];
2062 return io_write(io, str, 0);
2066 VALUE
2067 rb_io_write(VALUE io, VALUE str)
2069 return rb_funcallv(io, id_write, 1, &str);
2072 static VALUE
2073 rb_io_writev(VALUE io, int argc, const VALUE *argv)
2075 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2076 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2077 VALUE klass = CLASS_OF(io);
2078 char sep = FL_TEST(klass, FL_SINGLETON) ? (klass = io, '.') : '#';
2079 rb_category_warning(RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2080 " which accepts just one argument",
2081 klass, sep);
2083 do rb_io_write(io, *argv++); while (--argc);
2084 return argv[0]; /* unused right now */
2086 return rb_funcallv(io, id_write, argc, argv);
2090 * call-seq:
2091 * self << object -> self
2093 * Writes the given +object+ to +self+,
2094 * which must be opened for writing (see {Modes}[#class-IO-label-Modes]);
2095 * returns +self+;
2096 * if +object+ is not a string, it is converted via method +to_s+:
2098 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2099 * $stdout << 'foo' << :bar << 2 << "\n"
2101 * Output:
2103 * Hello, World!
2104 * foobar2
2109 VALUE
2110 rb_io_addstr(VALUE io, VALUE str)
2112 rb_io_write(io, str);
2113 return io;
2116 #ifdef HAVE_FSYNC
2117 static VALUE
2118 nogvl_fsync(void *ptr)
2120 rb_io_t *fptr = ptr;
2122 #ifdef _WIN32
2123 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2124 return 0;
2125 #endif
2126 return (VALUE)fsync(fptr->fd);
2128 #endif
2130 VALUE
2131 rb_io_flush_raw(VALUE io, int sync)
2133 rb_io_t *fptr;
2135 if (!RB_TYPE_P(io, T_FILE)) {
2136 return rb_funcall(io, id_flush, 0);
2139 io = GetWriteIO(io);
2140 GetOpenFile(io, fptr);
2142 if (fptr->mode & FMODE_WRITABLE) {
2143 if (io_fflush(fptr) < 0)
2144 rb_sys_fail_on_write(fptr);
2146 if (fptr->mode & FMODE_READABLE) {
2147 io_unread(fptr);
2150 return io;
2154 * call-seq:
2155 * flush -> self
2157 * Flushes data buffered in +self+ to the operating system
2158 * (but does not necessarily flush data buffered in the operating system):
2160 * $stdout.print 'no newline' # Not necessarily flushed.
2161 * $stdout.flush # Flushed.
2165 VALUE
2166 rb_io_flush(VALUE io)
2168 return rb_io_flush_raw(io, 1);
2172 * call-seq:
2173 * tell -> integer
2175 * Returns the current position (in bytes) in +self+
2176 * (see {Position}[#class-IO-label-Position]):
2178 * f = File.new('t.txt')
2179 * f.tell # => 0
2180 * f.readline # => "This is line one.\n"
2181 * f.tell # => 19
2183 * Related: IO#pos=, IO#seek.
2185 * IO#pos is an alias for IO#tell.
2189 static VALUE
2190 rb_io_tell(VALUE io)
2192 rb_io_t *fptr;
2193 off_t pos;
2195 GetOpenFile(io, fptr);
2196 pos = io_tell(fptr);
2197 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2198 pos -= fptr->rbuf.len;
2199 return OFFT2NUM(pos);
2202 static VALUE
2203 rb_io_seek(VALUE io, VALUE offset, int whence)
2205 rb_io_t *fptr;
2206 off_t pos;
2208 pos = NUM2OFFT(offset);
2209 GetOpenFile(io, fptr);
2210 pos = io_seek(fptr, pos, whence);
2211 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2213 return INT2FIX(0);
2216 static int
2217 interpret_seek_whence(VALUE vwhence)
2219 if (vwhence == sym_SET)
2220 return SEEK_SET;
2221 if (vwhence == sym_CUR)
2222 return SEEK_CUR;
2223 if (vwhence == sym_END)
2224 return SEEK_END;
2225 #ifdef SEEK_DATA
2226 if (vwhence == sym_DATA)
2227 return SEEK_DATA;
2228 #endif
2229 #ifdef SEEK_HOLE
2230 if (vwhence == sym_HOLE)
2231 return SEEK_HOLE;
2232 #endif
2233 return NUM2INT(vwhence);
2237 * call-seq:
2238 * seek(offset, whence = IO::SEEK_SET) -> 0
2240 * Seeks to the position given by integer +offset+
2241 * (see {Position}[#class-IO-label-Position])
2242 * and constant +whence+, which is one of:
2244 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2245 * Repositions the stream to its current position plus the given +offset+:
2247 * f = File.open('t.txt')
2248 * f.tell # => 0
2249 * f.seek(20, :CUR) # => 0
2250 * f.tell # => 20
2251 * f.seek(-10, :CUR) # => 0
2252 * f.tell # => 10
2254 * - +:END+ or <tt>IO::SEEK_END</tt>:
2255 * Repositions the stream to its end plus the given +offset+:
2257 * f = File.open('t.txt')
2258 * f.tell # => 0
2259 * f.seek(0, :END) # => 0 # Repositions to stream end.
2260 * f.tell # => 70
2261 * f.seek(-20, :END) # => 0
2262 * f.tell # => 50
2263 * f.seek(-40, :END) # => 0
2264 * f.tell # => 30
2266 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2267 * Repositions the stream to the given +offset+:
2269 * f = File.open('t.txt')
2270 * f.tell # => 0
2271 * f.seek(20, :SET) # => 0
2272 * f.tell # => 20
2273 * f.seek(40, :SET) # => 0
2274 * f.tell # => 40
2276 * Related: IO#pos=, IO#tell.
2280 static VALUE
2281 rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2283 VALUE offset, ptrname;
2284 int whence = SEEK_SET;
2286 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2287 whence = interpret_seek_whence(ptrname);
2290 return rb_io_seek(io, offset, whence);
2294 * call-seq:
2295 * pos = new_position -> new_position
2297 * Seeks to the given +new_position+ (in bytes);
2298 * see {Position}[#class-IO-label-Position]:
2300 * f = File.open('t.txt')
2301 * f.tell # => 0
2302 * f.pos = 20 # => 20
2303 * f.tell # => 20
2305 * Related: IO#seek, IO#tell.
2309 static VALUE
2310 rb_io_set_pos(VALUE io, VALUE offset)
2312 rb_io_t *fptr;
2313 off_t pos;
2315 pos = NUM2OFFT(offset);
2316 GetOpenFile(io, fptr);
2317 pos = io_seek(fptr, pos, SEEK_SET);
2318 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2320 return OFFT2NUM(pos);
2323 static void clear_readconv(rb_io_t *fptr);
2326 * call-seq:
2327 * rewind -> 0
2329 * Repositions the stream to its beginning,
2330 * setting both the position and the line number to zero;
2331 * see {Position}[#class-IO-label-Position]
2332 * and {Line Number}[#class-IO-label-Line+Number]:
2334 * f = File.open('t.txt')
2335 * f.tell # => 0
2336 * f.lineno # => 0
2337 * f.readline # => "This is line one.\n"
2338 * f.tell # => 19
2339 * f.lineno # => 1
2340 * f.rewind # => 0
2341 * f.tell # => 0
2342 * f.lineno # => 0
2344 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2348 static VALUE
2349 rb_io_rewind(VALUE io)
2351 rb_io_t *fptr;
2353 GetOpenFile(io, fptr);
2354 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2355 if (io == ARGF.current_file) {
2356 ARGF.lineno -= fptr->lineno;
2358 fptr->lineno = 0;
2359 if (fptr->readconv) {
2360 clear_readconv(fptr);
2363 return INT2FIX(0);
2366 static int
2367 fptr_wait_readable(rb_io_t *fptr)
2369 int ret = rb_io_maybe_wait_readable(errno, fptr->self, Qnil);
2371 if (ret)
2372 rb_io_check_closed(fptr);
2374 return ret;
2377 static int
2378 io_fillbuf(rb_io_t *fptr)
2380 ssize_t r;
2382 if (fptr->rbuf.ptr == NULL) {
2383 fptr->rbuf.off = 0;
2384 fptr->rbuf.len = 0;
2385 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2386 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2387 #ifdef _WIN32
2388 fptr->rbuf.capa--;
2389 #endif
2391 if (fptr->rbuf.len == 0) {
2392 retry:
2393 r = rb_read_internal(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2395 if (r < 0) {
2396 if (fptr_wait_readable(fptr))
2397 goto retry;
2399 int e = errno;
2400 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2401 if (!NIL_P(fptr->pathv)) {
2402 rb_str_append(path, fptr->pathv);
2405 rb_syserr_fail_path(e, path);
2407 if (r > 0) rb_io_check_closed(fptr);
2408 fptr->rbuf.off = 0;
2409 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2410 if (r == 0)
2411 return -1; /* EOF */
2413 return 0;
2417 * call-seq:
2418 * eof -> true or false
2420 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2421 * see {Position}[#class-IO-label-Position]:
2423 * f = File.open('t.txt')
2424 * f.eof # => false
2425 * f.seek(0, :END) # => 0
2426 * f.eof # => true
2428 * Raises an exception unless the stream is opened for reading;
2429 * see {Mode}[#class-IO-label-Mode].
2431 * If +self+ is a stream such as pipe or socket, this method
2432 * blocks until the other end sends some data or closes it:
2434 * r, w = IO.pipe
2435 * Thread.new { sleep 1; w.close }
2436 * r.eof? # => true # After 1-second wait.
2438 * r, w = IO.pipe
2439 * Thread.new { sleep 1; w.puts "a" }
2440 * r.eof? # => false # After 1-second wait.
2442 * r, w = IO.pipe
2443 * r.eof? # blocks forever
2445 * Note that this method reads data to the input byte buffer. So
2446 * IO#sysread may not behave as you intend with IO#eof?, unless you
2447 * call IO#rewind first (which is not available for some streams).
2449 * I#eof? is an alias for IO#eof.
2453 VALUE
2454 rb_io_eof(VALUE io)
2456 rb_io_t *fptr;
2458 GetOpenFile(io, fptr);
2459 rb_io_check_char_readable(fptr);
2461 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2462 if (READ_DATA_PENDING(fptr)) return Qfalse;
2463 READ_CHECK(fptr);
2464 #if RUBY_CRLF_ENVIRONMENT
2465 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2466 return RBOOL(eof(fptr->fd));;
2468 #endif
2469 return RBOOL(io_fillbuf(fptr) < 0);
2473 * call-seq:
2474 * sync -> true or false
2476 * Returns the current sync mode of the stream.
2477 * When sync mode is true, all output is immediately flushed to the underlying
2478 * operating system and is not buffered by Ruby internally. See also #fsync.
2480 * f = File.open('t.tmp', 'w')
2481 * f.sync # => false
2482 * f.sync = true
2483 * f.sync # => true
2487 static VALUE
2488 rb_io_sync(VALUE io)
2490 rb_io_t *fptr;
2492 io = GetWriteIO(io);
2493 GetOpenFile(io, fptr);
2494 return RBOOL(fptr->mode & FMODE_SYNC);
2497 #ifdef HAVE_FSYNC
2500 * call-seq:
2501 * sync = boolean -> boolean
2503 * Sets the _sync_ _mode_ for the stream to the given value;
2504 * returns the given value.
2506 * Values for the sync mode:
2508 * - +true+: All output is immediately flushed to the
2509 * underlying operating system and is not buffered internally.
2510 * - +false+: Output may be buffered internally.
2512 * Example;
2514 * f = File.open('t.tmp', 'w')
2515 * f.sync # => false
2516 * f.sync = true
2517 * f.sync # => true
2519 * Related: IO#fsync.
2523 static VALUE
2524 rb_io_set_sync(VALUE io, VALUE sync)
2526 rb_io_t *fptr;
2528 io = GetWriteIO(io);
2529 GetOpenFile(io, fptr);
2530 if (RTEST(sync)) {
2531 fptr->mode |= FMODE_SYNC;
2533 else {
2534 fptr->mode &= ~FMODE_SYNC;
2536 return sync;
2540 * call-seq:
2541 * fsync -> 0
2543 * Immediately writes to disk all data buffered in the stream,
2544 * via the operating system's <tt>fsync(2)</tt>.
2546 * Note this difference:
2548 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2549 * but does not guarantee that the operating system actually writes the data to disk.
2550 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2551 * and that data is written to disk.
2553 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2557 static VALUE
2558 rb_io_fsync(VALUE io)
2560 rb_io_t *fptr;
2562 io = GetWriteIO(io);
2563 GetOpenFile(io, fptr);
2565 if (io_fflush(fptr) < 0)
2566 rb_sys_fail_on_write(fptr);
2567 if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
2568 rb_sys_fail_path(fptr->pathv);
2569 return INT2FIX(0);
2571 #else
2572 # define rb_io_fsync rb_f_notimplement
2573 # define rb_io_sync rb_f_notimplement
2574 static VALUE
2575 rb_io_set_sync(VALUE io, VALUE sync)
2577 rb_notimplement();
2578 UNREACHABLE;
2580 #endif
2582 #ifdef HAVE_FDATASYNC
2583 static VALUE
2584 nogvl_fdatasync(void *ptr)
2586 rb_io_t *fptr = ptr;
2588 #ifdef _WIN32
2589 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2590 return 0;
2591 #endif
2592 return (VALUE)fdatasync(fptr->fd);
2596 * call-seq:
2597 * fdatasync -> 0
2599 * Immediately writes to disk all data buffered in the stream,
2600 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2601 * otherwise via <tt>fsync(2)</tt>, if supported;
2602 * otherwise raises an exception.
2606 static VALUE
2607 rb_io_fdatasync(VALUE io)
2609 rb_io_t *fptr;
2611 io = GetWriteIO(io);
2612 GetOpenFile(io, fptr);
2614 if (io_fflush(fptr) < 0)
2615 rb_sys_fail_on_write(fptr);
2617 if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
2618 return INT2FIX(0);
2620 /* fall back */
2621 return rb_io_fsync(io);
2623 #else
2624 #define rb_io_fdatasync rb_io_fsync
2625 #endif
2628 * call-seq:
2629 * fileno -> integer
2631 * Returns the integer file descriptor for the stream:
2633 * $stdin.fileno # => 0
2634 * $stdout.fileno # => 1
2635 * $stderr.fileno # => 2
2636 * File.open('t.txt').fileno # => 10
2638 * IO#to_i is an alias for IO#fileno.
2642 static VALUE
2643 rb_io_fileno(VALUE io)
2645 rb_io_t *fptr = RFILE(io)->fptr;
2646 int fd;
2648 rb_io_check_closed(fptr);
2649 fd = fptr->fd;
2650 return INT2FIX(fd);
2654 rb_io_descriptor(VALUE io)
2656 if (RB_TYPE_P(io, T_FILE)) {
2657 rb_io_t *fptr = RFILE(io)->fptr;
2658 rb_io_check_closed(fptr);
2659 return fptr->fd;
2661 else {
2662 return RB_NUM2INT(rb_funcall(io, id_fileno, 0));
2667 * call-seq:
2668 * pid -> integer or nil
2670 * Returns the process ID of a child process associated with the stream,
2671 * which will have been set by IO#popen, or +nil+ if the stream was not
2672 * created by IO#popen:
2674 * pipe = IO.popen("-")
2675 * if pipe
2676 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2677 * else
2678 * $stderr.puts "In child, pid is #{$$}"
2679 * end
2681 * Output:
2683 * In child, pid is 26209
2684 * In parent, child pid is 26209
2688 static VALUE
2689 rb_io_pid(VALUE io)
2691 rb_io_t *fptr;
2693 GetOpenFile(io, fptr);
2694 if (!fptr->pid)
2695 return Qnil;
2696 return PIDT2NUM(fptr->pid);
2701 * call-seq:
2702 * inspect -> string
2704 * Returns a string representation of +self+:
2706 * f = File.open('t.txt')
2707 * f.inspect # => "#<File:t.txt>"
2711 static VALUE
2712 rb_io_inspect(VALUE obj)
2714 rb_io_t *fptr;
2715 VALUE result;
2716 static const char closed[] = " (closed)";
2718 fptr = RFILE(obj)->fptr;
2719 if (!fptr) return rb_any_to_s(obj);
2720 result = rb_str_new_cstr("#<");
2721 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2722 rb_str_cat2(result, ":");
2723 if (NIL_P(fptr->pathv)) {
2724 if (fptr->fd < 0) {
2725 rb_str_cat(result, closed+1, strlen(closed)-1);
2727 else {
2728 rb_str_catf(result, "fd %d", fptr->fd);
2731 else {
2732 rb_str_append(result, fptr->pathv);
2733 if (fptr->fd < 0) {
2734 rb_str_cat(result, closed, strlen(closed));
2737 return rb_str_cat2(result, ">");
2741 * call-seq:
2742 * to_io -> self
2744 * Returns +self+.
2748 static VALUE
2749 rb_io_to_io(VALUE io)
2751 return io;
2754 /* reading functions */
2755 static long
2756 read_buffered_data(char *ptr, long len, rb_io_t *fptr)
2758 int n;
2760 n = READ_DATA_PENDING_COUNT(fptr);
2761 if (n <= 0) return 0;
2762 if (n > len) n = (int)len;
2763 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
2764 fptr->rbuf.off += n;
2765 fptr->rbuf.len -= n;
2766 return n;
2769 static long
2770 io_bufread(char *ptr, long len, rb_io_t *fptr)
2772 long offset = 0;
2773 long n = len;
2774 long c;
2776 if (READ_DATA_PENDING(fptr) == 0) {
2777 while (n > 0) {
2778 again:
2779 rb_io_check_closed(fptr);
2780 c = rb_read_internal(fptr, ptr+offset, n);
2781 if (c == 0) break;
2782 if (c < 0) {
2783 if (fptr_wait_readable(fptr))
2784 goto again;
2785 return -1;
2787 offset += c;
2788 if ((n -= c) <= 0) break;
2790 return len - n;
2793 while (n > 0) {
2794 c = read_buffered_data(ptr+offset, n, fptr);
2795 if (c > 0) {
2796 offset += c;
2797 if ((n -= c) <= 0) break;
2799 rb_io_check_closed(fptr);
2800 if (io_fillbuf(fptr) < 0) {
2801 break;
2804 return len - n;
2807 static int io_setstrbuf(VALUE *str, long len);
2809 struct bufread_arg {
2810 char *str_ptr;
2811 long len;
2812 rb_io_t *fptr;
2815 static VALUE
2816 bufread_call(VALUE arg)
2818 struct bufread_arg *p = (struct bufread_arg *)arg;
2819 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
2820 return Qundef;
2823 static long
2824 io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
2826 long len;
2827 struct bufread_arg arg;
2829 io_setstrbuf(&str, offset + size);
2830 arg.str_ptr = RSTRING_PTR(str) + offset;
2831 arg.len = size;
2832 arg.fptr = fptr;
2833 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
2834 len = arg.len;
2835 if (len < 0) rb_sys_fail_path(fptr->pathv);
2836 return len;
2839 static long
2840 remain_size(rb_io_t *fptr)
2842 struct stat st;
2843 off_t siz = READ_DATA_PENDING_COUNT(fptr);
2844 off_t pos;
2846 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
2847 #if defined(__HAIKU__)
2848 && (st.st_dev > 3)
2849 #endif
2852 if (io_fflush(fptr) < 0)
2853 rb_sys_fail_on_write(fptr);
2854 pos = lseek(fptr->fd, 0, SEEK_CUR);
2855 if (st.st_size >= pos && pos >= 0) {
2856 siz += st.st_size - pos;
2857 if (siz > LONG_MAX) {
2858 rb_raise(rb_eIOError, "file too big for single read");
2862 else {
2863 siz += BUFSIZ;
2865 return (long)siz;
2868 static VALUE
2869 io_enc_str(VALUE str, rb_io_t *fptr)
2871 rb_enc_associate(str, io_read_encoding(fptr));
2872 return str;
2875 static void
2876 make_readconv(rb_io_t *fptr, int size)
2878 if (!fptr->readconv) {
2879 int ecflags;
2880 VALUE ecopts;
2881 const char *sname, *dname;
2882 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
2883 ecopts = fptr->encs.ecopts;
2884 if (fptr->encs.enc2) {
2885 sname = rb_enc_name(fptr->encs.enc2);
2886 dname = rb_enc_name(fptr->encs.enc);
2888 else {
2889 sname = dname = "";
2891 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
2892 if (!fptr->readconv)
2893 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
2894 fptr->cbuf.off = 0;
2895 fptr->cbuf.len = 0;
2896 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
2897 fptr->cbuf.capa = size;
2898 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
2902 #define MORE_CHAR_SUSPENDED Qtrue
2903 #define MORE_CHAR_FINISHED Qnil
2904 static VALUE
2905 fill_cbuf(rb_io_t *fptr, int ec_flags)
2907 const unsigned char *ss, *sp, *se;
2908 unsigned char *ds, *dp, *de;
2909 rb_econv_result_t res;
2910 int putbackable;
2911 int cbuf_len0;
2912 VALUE exc;
2914 ec_flags |= ECONV_PARTIAL_INPUT;
2916 if (fptr->cbuf.len == fptr->cbuf.capa)
2917 return MORE_CHAR_SUSPENDED; /* cbuf full */
2918 if (fptr->cbuf.len == 0)
2919 fptr->cbuf.off = 0;
2920 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
2921 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
2922 fptr->cbuf.off = 0;
2925 cbuf_len0 = fptr->cbuf.len;
2927 while (1) {
2928 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
2929 se = sp + fptr->rbuf.len;
2930 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
2931 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
2932 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
2933 fptr->rbuf.off += (int)(sp - ss);
2934 fptr->rbuf.len -= (int)(sp - ss);
2935 fptr->cbuf.len += (int)(dp - ds);
2937 putbackable = rb_econv_putbackable(fptr->readconv);
2938 if (putbackable) {
2939 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
2940 fptr->rbuf.off -= putbackable;
2941 fptr->rbuf.len += putbackable;
2944 exc = rb_econv_make_exception(fptr->readconv);
2945 if (!NIL_P(exc))
2946 return exc;
2948 if (cbuf_len0 != fptr->cbuf.len)
2949 return MORE_CHAR_SUSPENDED;
2951 if (res == econv_finished) {
2952 return MORE_CHAR_FINISHED;
2955 if (res == econv_source_buffer_empty) {
2956 if (fptr->rbuf.len == 0) {
2957 READ_CHECK(fptr);
2958 if (io_fillbuf(fptr) < 0) {
2959 if (!fptr->readconv) {
2960 return MORE_CHAR_FINISHED;
2962 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
2963 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
2964 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
2965 fptr->cbuf.len += (int)(dp - ds);
2966 rb_econv_check_error(fptr->readconv);
2967 break;
2972 if (cbuf_len0 != fptr->cbuf.len)
2973 return MORE_CHAR_SUSPENDED;
2975 return MORE_CHAR_FINISHED;
2978 static VALUE
2979 more_char(rb_io_t *fptr)
2981 VALUE v;
2982 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
2983 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
2984 rb_exc_raise(v);
2985 return v;
2988 static VALUE
2989 io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
2991 VALUE str = Qnil;
2992 if (strp) {
2993 str = *strp;
2994 if (NIL_P(str)) {
2995 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
2997 else {
2998 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3000 rb_enc_associate(str, fptr->encs.enc);
3002 fptr->cbuf.off += len;
3003 fptr->cbuf.len -= len;
3004 /* xxx: set coderange */
3005 if (fptr->cbuf.len == 0)
3006 fptr->cbuf.off = 0;
3007 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3008 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3009 fptr->cbuf.off = 0;
3011 return str;
3014 static int
3015 io_setstrbuf(VALUE *str, long len)
3017 #ifdef _WIN32
3018 len = (len + 1) & ~1L; /* round up for wide char */
3019 #endif
3020 if (NIL_P(*str)) {
3021 *str = rb_str_new(0, len);
3022 return TRUE;
3024 else {
3025 VALUE s = StringValue(*str);
3026 long clen = RSTRING_LEN(s);
3027 if (clen >= len) {
3028 rb_str_modify(s);
3029 return FALSE;
3031 len -= clen;
3033 rb_str_modify_expand(*str, len);
3034 return FALSE;
3037 #define MAX_REALLOC_GAP 4096
3038 static void
3039 io_shrink_read_string(VALUE str, long n)
3041 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3042 rb_str_resize(str, n);
3046 static void
3047 io_set_read_length(VALUE str, long n, int shrinkable)
3049 if (RSTRING_LEN(str) != n) {
3050 rb_str_modify(str);
3051 rb_str_set_len(str, n);
3052 if (shrinkable) io_shrink_read_string(str, n);
3056 static VALUE
3057 read_all(rb_io_t *fptr, long siz, VALUE str)
3059 long bytes;
3060 long n;
3061 long pos;
3062 rb_encoding *enc;
3063 int cr;
3064 int shrinkable;
3066 if (NEED_READCONV(fptr)) {
3067 int first = !NIL_P(str);
3068 SET_BINARY_MODE(fptr);
3069 shrinkable = io_setstrbuf(&str,0);
3070 make_readconv(fptr, 0);
3071 while (1) {
3072 VALUE v;
3073 if (fptr->cbuf.len) {
3074 if (first) rb_str_set_len(str, first = 0);
3075 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3077 v = fill_cbuf(fptr, 0);
3078 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3079 if (fptr->cbuf.len) {
3080 if (first) rb_str_set_len(str, first = 0);
3081 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3083 rb_exc_raise(v);
3085 if (v == MORE_CHAR_FINISHED) {
3086 clear_readconv(fptr);
3087 if (first) rb_str_set_len(str, first = 0);
3088 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3089 return io_enc_str(str, fptr);
3094 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3095 bytes = 0;
3096 pos = 0;
3098 enc = io_read_encoding(fptr);
3099 cr = 0;
3101 if (siz == 0) siz = BUFSIZ;
3102 shrinkable = io_setstrbuf(&str, siz);
3103 for (;;) {
3104 READ_CHECK(fptr);
3105 n = io_fread(str, bytes, siz - bytes, fptr);
3106 if (n == 0 && bytes == 0) {
3107 rb_str_set_len(str, 0);
3108 break;
3110 bytes += n;
3111 rb_str_set_len(str, bytes);
3112 if (cr != ENC_CODERANGE_BROKEN)
3113 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3114 if (bytes < siz) break;
3115 siz += BUFSIZ;
3116 rb_str_modify_expand(str, BUFSIZ);
3118 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3119 str = io_enc_str(str, fptr);
3120 ENC_CODERANGE_SET(str, cr);
3121 return str;
3124 void
3125 rb_io_set_nonblock(rb_io_t *fptr)
3127 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3128 rb_sys_fail_path(fptr->pathv);
3132 static VALUE
3133 read_internal_call(VALUE arg)
3135 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3137 VALUE scheduler = rb_fiber_scheduler_current();
3138 if (scheduler != Qnil) {
3139 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3141 if (result != Qundef) {
3142 // This is actually returned as a pseudo-VALUE and later cast to a long:
3143 return (VALUE)rb_fiber_scheduler_io_result_apply(result);
3147 return rb_thread_io_blocking_region(internal_read_func, iis, iis->fptr->fd);
3150 static long
3151 read_internal_locktmp(VALUE str, struct io_internal_read_struct *iis)
3153 return (long)rb_str_locktmp_ensure(str, read_internal_call, (VALUE)iis);
3156 #define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3158 static VALUE
3159 io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3161 rb_io_t *fptr;
3162 VALUE length, str;
3163 long n, len;
3164 struct io_internal_read_struct iis;
3165 int shrinkable;
3167 rb_scan_args(argc, argv, "11", &length, &str);
3169 if ((len = NUM2LONG(length)) < 0) {
3170 rb_raise(rb_eArgError, "negative length %ld given", len);
3173 shrinkable = io_setstrbuf(&str, len);
3175 GetOpenFile(io, fptr);
3176 rb_io_check_byte_readable(fptr);
3178 if (len == 0) {
3179 io_set_read_length(str, 0, shrinkable);
3180 return str;
3183 if (!nonblock)
3184 READ_CHECK(fptr);
3185 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3186 if (n <= 0) {
3187 again:
3188 if (nonblock) {
3189 rb_io_set_nonblock(fptr);
3191 io_setstrbuf(&str, len);
3192 iis.th = rb_thread_current();
3193 iis.fptr = fptr;
3194 iis.nonblock = nonblock;
3195 iis.buf = RSTRING_PTR(str);
3196 iis.capa = len;
3197 n = read_internal_locktmp(str, &iis);
3198 if (n < 0) {
3199 int e = errno;
3200 if (!nonblock && fptr_wait_readable(fptr))
3201 goto again;
3202 if (nonblock && (io_again_p(e))) {
3203 if (no_exception)
3204 return sym_wait_readable;
3205 else
3206 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3207 e, "read would block");
3209 rb_syserr_fail_path(e, fptr->pathv);
3212 io_set_read_length(str, n, shrinkable);
3214 if (n == 0)
3215 return Qnil;
3216 else
3217 return str;
3221 * call-seq:
3222 * readpartial(maxlen) -> string
3223 * readpartial(maxlen, out_string) -> out_string
3225 * Reads up to +maxlen+ bytes from the stream;
3226 * returns a string (either a new string or the given +out_string+).
3227 * Its encoding is:
3229 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3230 * - ASCII-8BIT, otherwise.
3232 * - Contains +maxlen+ bytes from the stream, if available.
3233 * - Otherwise contains all available bytes, if any available.
3234 * - Otherwise is an empty string.
3236 * With the single non-negative integer argument +maxlen+ given,
3237 * returns a new string:
3239 * f = File.new('t.txt')
3240 * f.readpartial(30) # => "This is line one.\nThis is the"
3241 * f.readpartial(30) # => " second line.\nThis is the thi"
3242 * f.readpartial(30) # => "rd line.\n"
3243 * f.eof # => true
3244 * f.readpartial(30) # Raises EOFError.
3246 * With both argument +maxlen+ and string argument +out_string+ given,
3247 * returns modified +out_string+:
3249 * f = File.new('t.txt')
3250 * s = 'foo'
3251 * f.readpartial(30, s) # => "This is line one.\nThis is the"
3252 * s = 'bar'
3253 * f.readpartial(0, s) # => ""
3255 * This method is useful for a stream such as a pipe, a socket, or a tty.
3256 * It blocks only when no data is immediately available.
3257 * This means that it blocks only when _all_ of the following are true:
3259 * - The byte buffer in the stream is empty.
3260 * - The content of the stream is empty.
3261 * - The stream is not at EOF.
3263 * When blocked, the method waits for either more data or EOF on the stream:
3265 * - If more data is read, the method returns the data.
3266 * - If EOF is reached, the method raises EOFError.
3268 * When not blocked, the method responds immediately:
3270 * - Returns data from the buffer if there is any.
3271 * - Otherwise returns data from the stream if there is any.
3272 * - Otherwise raises EOFError if the stream has reached EOF.
3274 * Note that this method is similar to sysread. The differences are:
3276 * - If the byte buffer is not empty, read from the byte buffer
3277 * instead of "sysread for buffered IO (IOError)".
3278 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3279 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3280 * readpartial retries the system call.
3282 * The latter means that readpartial is non-blocking-flag insensitive.
3283 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3284 * if the fd is blocking mode.
3286 * Examples:
3288 * # # Returned Buffer Content Pipe Content
3289 * r, w = IO.pipe #
3290 * w << 'abc' # "" "abc".
3291 * r.readpartial(4096) # => "abc" "" ""
3292 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3294 * # # Returned Buffer Content Pipe Content
3295 * r, w = IO.pipe #
3296 * w << 'abc' # "" "abc"
3297 * w.close # "" "abc" EOF
3298 * r.readpartial(4096) # => "abc" "" EOF
3299 * r.readpartial(4096) # raises EOFError
3301 * # # Returned Buffer Content Pipe Content
3302 * r, w = IO.pipe #
3303 * w << "abc\ndef\n" # "" "abc\ndef\n"
3304 * r.gets # => "abc\n" "def\n" ""
3305 * w << "ghi\n" # "def\n" "ghi\n"
3306 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3307 * r.readpartial(4096) # => "ghi\n" "" ""
3311 static VALUE
3312 io_readpartial(int argc, VALUE *argv, VALUE io)
3314 VALUE ret;
3316 ret = io_getpartial(argc, argv, io, Qnil, 0);
3317 if (NIL_P(ret))
3318 rb_eof_error();
3319 return ret;
3322 static VALUE
3323 io_nonblock_eof(int no_exception)
3325 if (!no_exception) {
3326 rb_eof_error();
3328 return Qnil;
3331 /* :nodoc: */
3332 static VALUE
3333 io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3335 rb_io_t *fptr;
3336 long n, len;
3337 struct io_internal_read_struct iis;
3338 int shrinkable;
3340 if ((len = NUM2LONG(length)) < 0) {
3341 rb_raise(rb_eArgError, "negative length %ld given", len);
3344 shrinkable = io_setstrbuf(&str, len);
3345 rb_bool_expected(ex, "exception");
3347 GetOpenFile(io, fptr);
3348 rb_io_check_byte_readable(fptr);
3350 if (len == 0) {
3351 io_set_read_length(str, 0, shrinkable);
3352 return str;
3355 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3356 if (n <= 0) {
3357 rb_io_set_nonblock(fptr);
3358 shrinkable |= io_setstrbuf(&str, len);
3359 iis.fptr = fptr;
3360 iis.nonblock = 1;
3361 iis.buf = RSTRING_PTR(str);
3362 iis.capa = len;
3363 n = read_internal_locktmp(str, &iis);
3364 if (n < 0) {
3365 int e = errno;
3366 if (io_again_p(e)) {
3367 if (!ex) return sym_wait_readable;
3368 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3369 e, "read would block");
3371 rb_syserr_fail_path(e, fptr->pathv);
3374 io_set_read_length(str, n, shrinkable);
3376 if (n == 0) {
3377 if (!ex) return Qnil;
3378 rb_eof_error();
3381 return str;
3384 /* :nodoc: */
3385 static VALUE
3386 io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3388 rb_io_t *fptr;
3389 long n;
3391 if (!RB_TYPE_P(str, T_STRING))
3392 str = rb_obj_as_string(str);
3393 rb_bool_expected(ex, "exception");
3395 io = GetWriteIO(io);
3396 GetOpenFile(io, fptr);
3397 rb_io_check_writable(fptr);
3399 if (io_fflush(fptr) < 0)
3400 rb_sys_fail_on_write(fptr);
3402 rb_io_set_nonblock(fptr);
3403 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3404 RB_GC_GUARD(str);
3406 if (n < 0) {
3407 int e = errno;
3408 if (io_again_p(e)) {
3409 if (!ex) {
3410 return sym_wait_writable;
3412 else {
3413 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3416 rb_syserr_fail_path(e, fptr->pathv);
3419 return LONG2FIX(n);
3423 * call-seq:
3424 * read(maxlen = nil) -> string or nil
3425 * read(maxlen = nil, out_string) -> out_string or nil
3427 * Reads bytes from the stream (in binary mode):
3429 * - If +maxlen+ is +nil+, reads all bytes.
3430 * - Otherwise reads +maxlen+ bytes, if available.
3431 * - Otherwise reads all bytes.
3433 * Returns a string (either a new string or the given +out_string+)
3434 * containing the bytes read.
3435 * The encoding of the string depends on both +maxLen+ and +out_string+:
3437 * - +maxlen+ is +nil+: uses internal encoding of +self+
3438 * (regardless of whether +out_string+ was given).
3439 * - +maxlen+ not +nil+:
3441 * - +out_string+ given: encoding of +out_string+ not modified.
3442 * - +out_string+ not given: ASCII-8BIT is used.
3444 * <b>Without Argument +out_string+</b>
3446 * When argument +out_string+ is omitted,
3447 * the returned value is a new string:
3449 * f = File.new('t.txt')
3450 * f.read
3451 * # => "This is line one.\nThis is the second line.\nThis is the third line.\n"
3452 * f.rewind
3453 * f.read(40) # => "This is line one.\r\nThis is the second li"
3454 * f.read(40) # => "ne.\r\nThis is the third line.\r\n"
3455 * f.read(40) # => nil
3457 * If +maxlen+ is zero, returns an empty string.
3459 * <b> With Argument +out_string+</b>
3461 * When argument +out_string+ is given,
3462 * the returned value is +out_string+, whose content is replaced:
3464 * f = File.new('t.txt')
3465 * s = 'foo' # => "foo"
3466 * f.read(nil, s) # => "This is line one.\nThis is the second line.\nThis is the third line.\n"
3467 * s # => "This is line one.\nThis is the second line.\nThis is the third line.\n"
3468 * f.rewind
3469 * s = 'bar'
3470 * f.read(40, s) # => "This is line one.\r\nThis is the second li"
3471 * s # => "This is line one.\r\nThis is the second li"
3472 * s = 'baz'
3473 * f.read(40, s) # => "ne.\r\nThis is the third line.\r\n"
3474 * s # => "ne.\r\nThis is the third line.\r\n"
3475 * s = 'bat'
3476 * f.read(40, s) # => nil
3477 * s # => ""
3479 * Note that this method behaves like the fread() function in C.
3480 * This means it retries to invoke read(2) system calls to read data
3481 * with the specified maxlen (or until EOF).
3483 * This behavior is preserved even if the stream is in non-blocking mode.
3484 * (This method is non-blocking-flag insensitive as other methods.)
3486 * If you need the behavior like a single read(2) system call,
3487 * consider #readpartial, #read_nonblock, and #sysread.
3491 static VALUE
3492 io_read(int argc, VALUE *argv, VALUE io)
3494 rb_io_t *fptr;
3495 long n, len;
3496 VALUE length, str;
3497 int shrinkable;
3498 #if RUBY_CRLF_ENVIRONMENT
3499 int previous_mode;
3500 #endif
3502 rb_scan_args(argc, argv, "02", &length, &str);
3504 if (NIL_P(length)) {
3505 GetOpenFile(io, fptr);
3506 rb_io_check_char_readable(fptr);
3507 return read_all(fptr, remain_size(fptr), str);
3509 len = NUM2LONG(length);
3510 if (len < 0) {
3511 rb_raise(rb_eArgError, "negative length %ld given", len);
3514 shrinkable = io_setstrbuf(&str,len);
3516 GetOpenFile(io, fptr);
3517 rb_io_check_byte_readable(fptr);
3518 if (len == 0) {
3519 io_set_read_length(str, 0, shrinkable);
3520 return str;
3523 READ_CHECK(fptr);
3524 #if RUBY_CRLF_ENVIRONMENT
3525 previous_mode = set_binary_mode_with_seek_cur(fptr);
3526 #endif
3527 n = io_fread(str, 0, len, fptr);
3528 io_set_read_length(str, n, shrinkable);
3529 #if RUBY_CRLF_ENVIRONMENT
3530 if (previous_mode == O_TEXT) {
3531 setmode(fptr->fd, O_TEXT);
3533 #endif
3534 if (n == 0) return Qnil;
3536 return str;
3539 static void
3540 rscheck(const char *rsptr, long rslen, VALUE rs)
3542 if (!rs) return;
3543 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3544 rb_raise(rb_eRuntimeError, "rs modified");
3547 static int
3548 appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
3550 VALUE str = *strp;
3551 long limit = *lp;
3553 if (NEED_READCONV(fptr)) {
3554 SET_BINARY_MODE(fptr);
3555 make_readconv(fptr, 0);
3556 do {
3557 const char *p, *e;
3558 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3559 if (searchlen) {
3560 p = READ_CHAR_PENDING_PTR(fptr);
3561 if (0 < limit && limit < searchlen)
3562 searchlen = (int)limit;
3563 e = memchr(p, delim, searchlen);
3564 if (e) {
3565 int len = (int)(e-p+1);
3566 if (NIL_P(str))
3567 *strp = str = rb_str_new(p, len);
3568 else
3569 rb_str_buf_cat(str, p, len);
3570 fptr->cbuf.off += len;
3571 fptr->cbuf.len -= len;
3572 limit -= len;
3573 *lp = limit;
3574 return delim;
3577 if (NIL_P(str))
3578 *strp = str = rb_str_new(p, searchlen);
3579 else
3580 rb_str_buf_cat(str, p, searchlen);
3581 fptr->cbuf.off += searchlen;
3582 fptr->cbuf.len -= searchlen;
3583 limit -= searchlen;
3585 if (limit == 0) {
3586 *lp = limit;
3587 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3590 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3591 clear_readconv(fptr);
3592 *lp = limit;
3593 return EOF;
3596 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3597 do {
3598 long pending = READ_DATA_PENDING_COUNT(fptr);
3599 if (pending > 0) {
3600 const char *p = READ_DATA_PENDING_PTR(fptr);
3601 const char *e;
3602 long last;
3604 if (limit > 0 && pending > limit) pending = limit;
3605 e = memchr(p, delim, pending);
3606 if (e) pending = e - p + 1;
3607 if (!NIL_P(str)) {
3608 last = RSTRING_LEN(str);
3609 rb_str_resize(str, last + pending);
3611 else {
3612 last = 0;
3613 *strp = str = rb_str_buf_new(pending);
3614 rb_str_set_len(str, pending);
3616 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3617 limit -= pending;
3618 *lp = limit;
3619 if (e) return delim;
3620 if (limit == 0)
3621 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3623 READ_CHECK(fptr);
3624 } while (io_fillbuf(fptr) >= 0);
3625 *lp = limit;
3626 return EOF;
3629 static inline int
3630 swallow(rb_io_t *fptr, int term)
3632 if (NEED_READCONV(fptr)) {
3633 rb_encoding *enc = io_read_encoding(fptr);
3634 int needconv = rb_enc_mbminlen(enc) != 1;
3635 SET_BINARY_MODE(fptr);
3636 make_readconv(fptr, 0);
3637 do {
3638 size_t cnt;
3639 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3640 const char *p = READ_CHAR_PENDING_PTR(fptr);
3641 int i;
3642 if (!needconv) {
3643 if (*p != term) return TRUE;
3644 i = (int)cnt;
3645 while (--i && *++p == term);
3647 else {
3648 const char *e = p + cnt;
3649 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3650 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3651 i = (int)(e - p);
3653 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3655 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3656 return FALSE;
3659 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3660 do {
3661 size_t cnt;
3662 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3663 char buf[1024];
3664 const char *p = READ_DATA_PENDING_PTR(fptr);
3665 int i;
3666 if (cnt > sizeof buf) cnt = sizeof buf;
3667 if (*p != term) return TRUE;
3668 i = (int)cnt;
3669 while (--i && *++p == term);
3670 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
3671 rb_sys_fail_path(fptr->pathv);
3673 READ_CHECK(fptr);
3674 } while (io_fillbuf(fptr) == 0);
3675 return FALSE;
3678 static VALUE
3679 rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
3681 VALUE str = Qnil;
3682 int len = 0;
3683 long pos = 0;
3684 int cr = 0;
3686 do {
3687 int pending = READ_DATA_PENDING_COUNT(fptr);
3689 if (pending > 0) {
3690 const char *p = READ_DATA_PENDING_PTR(fptr);
3691 const char *e;
3692 int chomplen = 0;
3694 e = memchr(p, '\n', pending);
3695 if (e) {
3696 pending = (int)(e - p + 1);
3697 if (chomp) {
3698 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
3701 if (NIL_P(str)) {
3702 str = rb_str_new(p, pending - chomplen);
3703 fptr->rbuf.off += pending;
3704 fptr->rbuf.len -= pending;
3706 else {
3707 rb_str_resize(str, len + pending - chomplen);
3708 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
3709 fptr->rbuf.off += chomplen;
3710 fptr->rbuf.len -= chomplen;
3711 if (pending == 1 && chomplen == 1 && len > 0) {
3712 if (RSTRING_PTR(str)[len-1] == '\r') {
3713 rb_str_resize(str, --len);
3714 break;
3718 len += pending - chomplen;
3719 if (cr != ENC_CODERANGE_BROKEN)
3720 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
3721 if (e) break;
3723 READ_CHECK(fptr);
3724 } while (io_fillbuf(fptr) >= 0);
3725 if (NIL_P(str)) return Qnil;
3727 str = io_enc_str(str, fptr);
3728 ENC_CODERANGE_SET(str, cr);
3729 fptr->lineno++;
3731 return str;
3734 struct getline_arg {
3735 VALUE io;
3736 VALUE rs;
3737 long limit;
3738 unsigned int chomp: 1;
3741 static void
3742 extract_getline_opts(VALUE opts, struct getline_arg *args)
3744 int chomp = FALSE;
3745 if (!NIL_P(opts)) {
3746 static ID kwds[1];
3747 VALUE vchomp;
3748 if (!kwds[0]) {
3749 kwds[0] = rb_intern_const("chomp");
3751 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
3752 chomp = (vchomp != Qundef) && RTEST(vchomp);
3754 args->chomp = chomp;
3757 static void
3758 extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
3760 VALUE rs = rb_rs, lim = Qnil;
3762 if (argc == 1) {
3763 VALUE tmp = Qnil;
3765 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
3766 rs = tmp;
3768 else {
3769 lim = argv[0];
3772 else if (2 <= argc) {
3773 rs = argv[0], lim = argv[1];
3774 if (!NIL_P(rs))
3775 StringValue(rs);
3777 args->rs = rs;
3778 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
3781 static void
3782 check_getline_args(VALUE *rsp, long *limit, VALUE io)
3784 rb_io_t *fptr;
3785 VALUE rs = *rsp;
3787 if (!NIL_P(rs)) {
3788 rb_encoding *enc_rs, *enc_io;
3790 GetOpenFile(io, fptr);
3791 enc_rs = rb_enc_get(rs);
3792 enc_io = io_read_encoding(fptr);
3793 if (enc_io != enc_rs &&
3794 (rb_enc_str_coderange(rs) != ENC_CODERANGE_7BIT ||
3795 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
3796 if (rs == rb_default_rs) {
3797 rs = rb_enc_str_new(0, 0, enc_io);
3798 rb_str_buf_cat_ascii(rs, "\n");
3799 *rsp = rs;
3801 else {
3802 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
3803 rb_enc_name(enc_io),
3804 rb_enc_name(enc_rs));
3810 static void
3811 prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
3813 VALUE opts;
3814 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
3815 extract_getline_args(argc, argv, args);
3816 extract_getline_opts(opts, args);
3817 check_getline_args(&args->rs, &args->limit, io);
3820 static VALUE
3821 rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
3823 VALUE str = Qnil;
3824 int nolimit = 0;
3825 rb_encoding *enc;
3827 rb_io_check_char_readable(fptr);
3828 if (NIL_P(rs) && limit < 0) {
3829 str = read_all(fptr, 0, Qnil);
3830 if (RSTRING_LEN(str) == 0) return Qnil;
3831 if (chomp) rb_str_chomp_string(str, rb_default_rs);
3833 else if (limit == 0) {
3834 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
3836 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
3837 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
3838 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3839 return rb_io_getline_fast(fptr, enc, chomp);
3841 else {
3842 int c, newline = -1;
3843 const char *rsptr = 0;
3844 long rslen = 0;
3845 int rspara = 0;
3846 int extra_limit = 16;
3847 int chomp_cr = chomp;
3849 SET_BINARY_MODE(fptr);
3850 enc = io_read_encoding(fptr);
3852 if (!NIL_P(rs)) {
3853 rslen = RSTRING_LEN(rs);
3854 if (rslen == 0) {
3855 rsptr = "\n\n";
3856 rslen = 2;
3857 rspara = 1;
3858 swallow(fptr, '\n');
3859 rs = 0;
3860 if (!rb_enc_asciicompat(enc)) {
3861 rs = rb_usascii_str_new(rsptr, rslen);
3862 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
3863 OBJ_FREEZE(rs);
3864 rsptr = RSTRING_PTR(rs);
3865 rslen = RSTRING_LEN(rs);
3868 else {
3869 rsptr = RSTRING_PTR(rs);
3871 newline = (unsigned char)rsptr[rslen - 1];
3872 chomp_cr = chomp && rslen == 1 && newline == '\n';
3875 /* MS - Optimization */
3876 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
3877 const char *s, *p, *pp, *e;
3879 if (c == newline) {
3880 if (RSTRING_LEN(str) < rslen) continue;
3881 s = RSTRING_PTR(str);
3882 e = RSTRING_END(str);
3883 p = e - rslen;
3884 pp = rb_enc_left_char_head(s, p, e, enc);
3885 if (pp != p) continue;
3886 if (!rspara) rscheck(rsptr, rslen, rs);
3887 if (memcmp(p, rsptr, rslen) == 0) {
3888 if (chomp) {
3889 if (chomp_cr && p > s && *(p-1) == '\r') --p;
3890 rb_str_set_len(str, p - s);
3892 break;
3895 if (limit == 0) {
3896 s = RSTRING_PTR(str);
3897 p = RSTRING_END(str);
3898 pp = rb_enc_left_char_head(s, p-1, p, enc);
3899 if (extra_limit &&
3900 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
3901 /* relax the limit while incomplete character.
3902 * extra_limit limits the relax length */
3903 limit = 1;
3904 extra_limit--;
3906 else {
3907 nolimit = 1;
3908 break;
3913 if (rspara && c != EOF)
3914 swallow(fptr, '\n');
3915 if (!NIL_P(str))
3916 str = io_enc_str(str, fptr);
3919 if (!NIL_P(str) && !nolimit) {
3920 fptr->lineno++;
3923 return str;
3926 static VALUE
3927 rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
3929 rb_io_t *fptr;
3930 int old_lineno, new_lineno;
3931 VALUE str;
3933 GetOpenFile(io, fptr);
3934 old_lineno = fptr->lineno;
3935 str = rb_io_getline_0(rs, limit, chomp, fptr);
3936 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
3937 if (io == ARGF.current_file) {
3938 ARGF.lineno += new_lineno - old_lineno;
3939 ARGF.last_lineno = ARGF.lineno;
3941 else {
3942 ARGF.last_lineno = new_lineno;
3946 return str;
3949 static VALUE
3950 rb_io_getline(int argc, VALUE *argv, VALUE io)
3952 struct getline_arg args;
3954 prepare_getline_args(argc, argv, &args, io);
3955 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
3958 VALUE
3959 rb_io_gets(VALUE io)
3961 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
3964 VALUE
3965 rb_io_gets_internal(VALUE io)
3967 rb_io_t *fptr;
3968 GetOpenFile(io, fptr);
3969 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
3973 * call-seq:
3974 * gets(sep = $/, **getline_opts) -> string or nil
3975 * gets(limit, **getline_opts) -> string or nil
3976 * gets(sep, limit, **getline_opts) -> string or nil
3978 * Reads and returns data from the stream;
3979 * assigns the return value to <tt>$_</tt>.
3981 * With no arguments given, returns the next line
3982 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
3984 * f = File.open('t.txt')
3985 * f.gets # => "This is line one.\n"
3986 * $_ # => "This is line one.\n"
3987 * f.gets # => "This is the second line.\n"
3988 * f.gets # => "This is the third line.\n"
3989 * f.gets # => nil
3991 * With string argument +sep+ given, but not argument +limit+,
3992 * returns the next line as determined by line separator +sep+,
3993 * or +nil+ if none:
3995 * f = File.open('t.txt')
3996 * f.gets(' is') # => "This is"
3997 * f.gets(' is') # => " line one.\nThis is"
3998 * f.gets(' is') # => " the second line.\nThis is"
3999 * f.gets(' is') # => " the third line.\n"
4000 * f.gets(' is') # => nil
4002 * Note two special values for +sep+:
4004 * - +nil+: The entire stream is read and returned.
4005 * - <tt>''</tt> (empty string): The next "paragraph" is read and returned,
4006 * the paragraph separator being two successive line separators.
4008 * With integer argument +limit+ given,
4009 * returns up to <tt>limit+1</tt> bytes:
4011 * # Text with 1-byte characters.
4012 * File.open('t.txt') {|f| f.gets(1) } # => "T"
4013 * File.open('t.txt') {|f| f.gets(2) } # => "Th"
4014 * File.open('t.txt') {|f| f.gets(3) } # => "Thi"
4015 * File.open('t.txt') {|f| f.gets(4) } # => "This"
4016 * # No more than one line.
4017 * File.open('t.txt') {|f| f.gets(17) } # => "This is line one."
4018 * File.open('t.txt') {|f| f.gets(18) } # => "This is line one.\n"
4019 * File.open('t.txt') {|f| f.gets(19) } # => "This is line one.\n"
4021 * # Text with 2-byte characters, which will not be split.
4022 * File.open('t.rus') {|f| f.gets(1).size } # => 1
4023 * File.open('t.rus') {|f| f.gets(2).size } # => 1
4024 * File.open('t.rus') {|f| f.gets(3).size } # => 2
4025 * File.open('t.rus') {|f| f.gets(4).size } # => 2
4027 * With arguments +sep+ and +limit+,
4028 * combines the two behaviors above:
4030 * - Returns the next line as determined by line separator +sep+,
4031 * or +nil+ if none.
4032 * - But returns no more than <tt>limit+1</tt> bytes.
4034 * For all forms above, trailing optional keyword arguments may be given;
4035 * see {Getline Options}[#class-IO-label-Getline+Options]:
4037 * f = File.open('t.txt')
4038 * # Chomp the lines.
4039 * f.gets(chomp: true) # => "This is line one."
4040 * f.gets(chomp: true) # => "This is the second line."
4041 * f.gets(chomp: true) # => "This is the third line."
4042 * f.gets(chomp: true) # => nil
4046 static VALUE
4047 rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4049 VALUE str;
4051 str = rb_io_getline(argc, argv, io);
4052 rb_lastline_set(str);
4054 return str;
4058 * call-seq:
4059 * ios.lineno -> integer
4061 * Returns the current line number in <em>ios</em>. The stream must be
4062 * opened for reading. #lineno counts the number of times #gets is called
4063 * rather than the number of newlines encountered. The two values will
4064 * differ if #gets is called with a separator other than newline.
4066 * Methods that use <code>$/</code> like #each, #lines and #readline will
4067 * also increment #lineno.
4069 * See also the <code>$.</code> variable.
4071 * f = File.new("testfile")
4072 * f.lineno #=> 0
4073 * f.gets #=> "This is line one\n"
4074 * f.lineno #=> 1
4075 * f.gets #=> "This is line two\n"
4076 * f.lineno #=> 2
4079 static VALUE
4080 rb_io_lineno(VALUE io)
4082 rb_io_t *fptr;
4084 GetOpenFile(io, fptr);
4085 rb_io_check_char_readable(fptr);
4086 return INT2NUM(fptr->lineno);
4090 * call-seq:
4091 * ios.lineno = integer -> integer
4093 * Manually sets the current line number to the given value.
4094 * <code>$.</code> is updated only on the next read.
4096 * f = File.new("testfile")
4097 * f.gets #=> "This is line one\n"
4098 * $. #=> 1
4099 * f.lineno = 1000
4100 * f.lineno #=> 1000
4101 * $. #=> 1 # lineno of last read
4102 * f.gets #=> "This is line two\n"
4103 * $. #=> 1001 # lineno of last read
4106 static VALUE
4107 rb_io_set_lineno(VALUE io, VALUE lineno)
4109 rb_io_t *fptr;
4111 GetOpenFile(io, fptr);
4112 rb_io_check_char_readable(fptr);
4113 fptr->lineno = NUM2INT(lineno);
4114 return lineno;
4118 * call-seq:
4119 * ios.readline(sep=$/ [, getline_args]) -> string
4120 * ios.readline(limit [, getline_args]) -> string
4121 * ios.readline(sep, limit [, getline_args]) -> string
4123 * Reads a line as with IO#gets, but raises an EOFError on end of file.
4126 static VALUE
4127 rb_io_readline(int argc, VALUE *argv, VALUE io)
4129 VALUE line = rb_io_gets_m(argc, argv, io);
4131 if (NIL_P(line)) {
4132 rb_eof_error();
4134 return line;
4137 static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4140 * call-seq:
4141 * ios.readlines(sep=$/ [, getline_args]) -> array
4142 * ios.readlines(limit [, getline_args]) -> array
4143 * ios.readlines(sep, limit [, getline_args]) -> array
4145 * Reads all of the lines in <em>ios</em>, and returns them in
4146 * an array. Lines are separated by the optional <i>sep</i>. If
4147 * <i>sep</i> is +nil+, the rest of the stream is returned
4148 * as a single record.
4149 * If the first argument is an integer, or an
4150 * optional second argument is given, the returning string would not be
4151 * longer than the given value in bytes. The stream must be opened for
4152 * reading or an IOError will be raised.
4154 * f = File.new("testfile")
4155 * f.readlines[0] #=> "This is line one\n"
4157 * f = File.new("testfile", chomp: true)
4158 * f.readlines[0] #=> "This is line one"
4160 * See IO.readlines for details about getline_args.
4163 static VALUE
4164 rb_io_readlines(int argc, VALUE *argv, VALUE io)
4166 struct getline_arg args;
4168 prepare_getline_args(argc, argv, &args, io);
4169 return io_readlines(&args, io);
4172 static VALUE
4173 io_readlines(const struct getline_arg *arg, VALUE io)
4175 VALUE line, ary;
4177 if (arg->limit == 0)
4178 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4179 ary = rb_ary_new();
4180 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4181 rb_ary_push(ary, line);
4183 return ary;
4187 * call-seq:
4188 * ios.each(sep=$/ [, getline_args]) {|line| block } -> ios
4189 * ios.each(limit [, getline_args]) {|line| block } -> ios
4190 * ios.each(sep, limit [, getline_args]) {|line| block } -> ios
4191 * ios.each(...) -> an_enumerator
4193 * ios.each_line(sep=$/ [, getline_args]) {|line| block } -> ios
4194 * ios.each_line(limit [, getline_args]) {|line| block } -> ios
4195 * ios.each_line(sep, limit [, getline_args]) {|line| block } -> ios
4196 * ios.each_line(...) -> an_enumerator
4198 * Executes the block for every line in <em>ios</em>, where lines are
4199 * separated by <i>sep</i>. <em>ios</em> must be opened for
4200 * reading or an IOError will be raised.
4202 * If no block is given, an enumerator is returned instead.
4204 * f = File.new("testfile")
4205 * f.each {|line| puts "#{f.lineno}: #{line}" }
4207 * <em>produces:</em>
4209 * 1: This is line one
4210 * 2: This is line two
4211 * 3: This is line three
4212 * 4: And so on...
4214 * See IO.readlines for details about getline_args.
4217 static VALUE
4218 rb_io_each_line(int argc, VALUE *argv, VALUE io)
4220 VALUE str;
4221 struct getline_arg args;
4223 RETURN_ENUMERATOR(io, argc, argv);
4224 prepare_getline_args(argc, argv, &args, io);
4225 if (args.limit == 0)
4226 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4227 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4228 rb_yield(str);
4230 return io;
4234 * call-seq:
4235 * ios.each_byte {|byte| block } -> ios
4236 * ios.each_byte -> an_enumerator
4238 * Calls the given block once for each byte (0..255) in <em>ios</em>,
4239 * passing the byte as an argument. The stream must be opened for
4240 * reading or an IOError will be raised.
4242 * If no block is given, an enumerator is returned instead.
4244 * f = File.new("testfile")
4245 * checksum = 0
4246 * f.each_byte {|x| checksum ^= x } #=> #<File:testfile>
4247 * checksum #=> 12
4250 static VALUE
4251 rb_io_each_byte(VALUE io)
4253 rb_io_t *fptr;
4255 RETURN_ENUMERATOR(io, 0, 0);
4256 GetOpenFile(io, fptr);
4258 do {
4259 while (fptr->rbuf.len > 0) {
4260 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4261 fptr->rbuf.len--;
4262 rb_yield(INT2FIX(*p & 0xff));
4263 rb_io_check_byte_readable(fptr);
4264 errno = 0;
4266 READ_CHECK(fptr);
4267 } while (io_fillbuf(fptr) >= 0);
4268 return io;
4271 static VALUE
4272 io_getc(rb_io_t *fptr, rb_encoding *enc)
4274 int r, n, cr = 0;
4275 VALUE str;
4277 if (NEED_READCONV(fptr)) {
4278 rb_encoding *read_enc = io_read_encoding(fptr);
4280 str = Qnil;
4281 SET_BINARY_MODE(fptr);
4282 make_readconv(fptr, 0);
4284 while (1) {
4285 if (fptr->cbuf.len) {
4286 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4287 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4288 read_enc);
4289 if (!MBCLEN_NEEDMORE_P(r))
4290 break;
4291 if (fptr->cbuf.len == fptr->cbuf.capa) {
4292 rb_raise(rb_eIOError, "too long character");
4296 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4297 if (fptr->cbuf.len == 0) {
4298 clear_readconv(fptr);
4299 return Qnil;
4301 /* return an unit of an incomplete character just before EOF */
4302 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4303 fptr->cbuf.off += 1;
4304 fptr->cbuf.len -= 1;
4305 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4306 ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
4307 return str;
4310 if (MBCLEN_INVALID_P(r)) {
4311 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4312 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4313 read_enc);
4314 io_shift_cbuf(fptr, r, &str);
4315 cr = ENC_CODERANGE_BROKEN;
4317 else {
4318 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4319 cr = ENC_CODERANGE_VALID;
4320 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4321 ISASCII(RSTRING_PTR(str)[0])) {
4322 cr = ENC_CODERANGE_7BIT;
4325 str = io_enc_str(str, fptr);
4326 ENC_CODERANGE_SET(str, cr);
4327 return str;
4330 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4331 if (io_fillbuf(fptr) < 0) {
4332 return Qnil;
4334 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4335 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4336 fptr->rbuf.off += 1;
4337 fptr->rbuf.len -= 1;
4338 cr = ENC_CODERANGE_7BIT;
4340 else {
4341 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4342 if (MBCLEN_CHARFOUND_P(r) &&
4343 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4344 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4345 fptr->rbuf.off += n;
4346 fptr->rbuf.len -= n;
4347 cr = ENC_CODERANGE_VALID;
4349 else if (MBCLEN_NEEDMORE_P(r)) {
4350 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4351 fptr->rbuf.len = 0;
4352 getc_needmore:
4353 if (io_fillbuf(fptr) != -1) {
4354 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4355 fptr->rbuf.off++;
4356 fptr->rbuf.len--;
4357 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4358 if (MBCLEN_NEEDMORE_P(r)) {
4359 goto getc_needmore;
4361 else if (MBCLEN_CHARFOUND_P(r)) {
4362 cr = ENC_CODERANGE_VALID;
4366 else {
4367 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4368 fptr->rbuf.off++;
4369 fptr->rbuf.len--;
4372 if (!cr) cr = ENC_CODERANGE_BROKEN;
4373 str = io_enc_str(str, fptr);
4374 ENC_CODERANGE_SET(str, cr);
4375 return str;
4379 * call-seq:
4380 * ios.each_char {|c| block } -> ios
4381 * ios.each_char -> an_enumerator
4383 * Calls the given block once for each character in <em>ios</em>,
4384 * passing the character as an argument. The stream must be opened for
4385 * reading or an IOError will be raised.
4387 * If no block is given, an enumerator is returned instead.
4389 * f = File.new("testfile")
4390 * f.each_char {|c| print c, ' ' } #=> #<File:testfile>
4393 static VALUE
4394 rb_io_each_char(VALUE io)
4396 rb_io_t *fptr;
4397 rb_encoding *enc;
4398 VALUE c;
4400 RETURN_ENUMERATOR(io, 0, 0);
4401 GetOpenFile(io, fptr);
4402 rb_io_check_char_readable(fptr);
4404 enc = io_input_encoding(fptr);
4405 READ_CHECK(fptr);
4406 while (!NIL_P(c = io_getc(fptr, enc))) {
4407 rb_yield(c);
4409 return io;
4413 * call-seq:
4414 * ios.each_codepoint {|c| block } -> ios
4415 * ios.each_codepoint -> an_enumerator
4417 * Passes the Integer ordinal of each character in <i>ios</i>,
4418 * passing the codepoint as an argument. The stream must be opened for
4419 * reading or an IOError will be raised.
4421 * If no block is given, an enumerator is returned instead.
4425 static VALUE
4426 rb_io_each_codepoint(VALUE io)
4428 rb_io_t *fptr;
4429 rb_encoding *enc;
4430 unsigned int c;
4431 int r, n;
4433 RETURN_ENUMERATOR(io, 0, 0);
4434 GetOpenFile(io, fptr);
4435 rb_io_check_char_readable(fptr);
4437 READ_CHECK(fptr);
4438 if (NEED_READCONV(fptr)) {
4439 SET_BINARY_MODE(fptr);
4440 r = 1; /* no invalid char yet */
4441 for (;;) {
4442 make_readconv(fptr, 0);
4443 for (;;) {
4444 if (fptr->cbuf.len) {
4445 if (fptr->encs.enc)
4446 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4447 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4448 fptr->encs.enc);
4449 else
4450 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4451 if (!MBCLEN_NEEDMORE_P(r))
4452 break;
4453 if (fptr->cbuf.len == fptr->cbuf.capa) {
4454 rb_raise(rb_eIOError, "too long character");
4457 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4458 clear_readconv(fptr);
4459 if (!MBCLEN_CHARFOUND_P(r)) {
4460 enc = fptr->encs.enc;
4461 goto invalid;
4463 return io;
4466 if (MBCLEN_INVALID_P(r)) {
4467 enc = fptr->encs.enc;
4468 goto invalid;
4470 n = MBCLEN_CHARFOUND_LEN(r);
4471 if (fptr->encs.enc) {
4472 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4473 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4474 fptr->encs.enc);
4476 else {
4477 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4479 fptr->cbuf.off += n;
4480 fptr->cbuf.len -= n;
4481 rb_yield(UINT2NUM(c));
4482 rb_io_check_byte_readable(fptr);
4485 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4486 enc = io_input_encoding(fptr);
4487 while (io_fillbuf(fptr) >= 0) {
4488 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4489 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4490 if (MBCLEN_CHARFOUND_P(r) &&
4491 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4492 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4493 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4494 fptr->rbuf.off += n;
4495 fptr->rbuf.len -= n;
4496 rb_yield(UINT2NUM(c));
4498 else if (MBCLEN_INVALID_P(r)) {
4499 goto invalid;
4501 else if (MBCLEN_NEEDMORE_P(r)) {
4502 char cbuf[8], *p = cbuf;
4503 int more = MBCLEN_NEEDMORE_LEN(r);
4504 if (more > numberof(cbuf)) goto invalid;
4505 more += n = fptr->rbuf.len;
4506 if (more > numberof(cbuf)) goto invalid;
4507 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4508 (p += n, (more -= n) > 0)) {
4509 if (io_fillbuf(fptr) < 0) goto invalid;
4510 if ((n = fptr->rbuf.len) > more) n = more;
4512 r = rb_enc_precise_mbclen(cbuf, p, enc);
4513 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4514 c = rb_enc_codepoint(cbuf, p, enc);
4515 rb_yield(UINT2NUM(c));
4517 else {
4518 continue;
4520 rb_io_check_byte_readable(fptr);
4522 return io;
4524 invalid:
4525 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4526 UNREACHABLE_RETURN(Qundef);
4530 * call-seq:
4531 * ios.getc -> string or nil
4533 * Reads a one-character string from <em>ios</em>. Returns
4534 * +nil+ if called at end of file.
4536 * f = File.new("testfile")
4537 * f.getc #=> "h"
4538 * f.getc #=> "e"
4541 static VALUE
4542 rb_io_getc(VALUE io)
4544 rb_io_t *fptr;
4545 rb_encoding *enc;
4547 GetOpenFile(io, fptr);
4548 rb_io_check_char_readable(fptr);
4550 enc = io_input_encoding(fptr);
4551 READ_CHECK(fptr);
4552 return io_getc(fptr, enc);
4556 * call-seq:
4557 * ios.readchar -> string
4559 * Reads a one-character string from <em>ios</em>. Raises an
4560 * EOFError on end of file.
4562 * f = File.new("testfile")
4563 * f.readchar #=> "h"
4564 * f.readchar #=> "e"
4567 static VALUE
4568 rb_io_readchar(VALUE io)
4570 VALUE c = rb_io_getc(io);
4572 if (NIL_P(c)) {
4573 rb_eof_error();
4575 return c;
4579 * call-seq:
4580 * ios.getbyte -> integer or nil
4582 * Gets the next 8-bit byte (0..255) from <em>ios</em>. Returns
4583 * +nil+ if called at end of file.
4585 * f = File.new("testfile")
4586 * f.getbyte #=> 84
4587 * f.getbyte #=> 104
4590 VALUE
4591 rb_io_getbyte(VALUE io)
4593 rb_io_t *fptr;
4594 int c;
4596 GetOpenFile(io, fptr);
4597 rb_io_check_byte_readable(fptr);
4598 READ_CHECK(fptr);
4599 VALUE r_stdout = rb_ractor_stdout();
4600 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
4601 rb_io_t *ofp;
4602 GetOpenFile(r_stdout, ofp);
4603 if (ofp->mode & FMODE_TTY) {
4604 rb_io_flush(r_stdout);
4607 if (io_fillbuf(fptr) < 0) {
4608 return Qnil;
4610 fptr->rbuf.off++;
4611 fptr->rbuf.len--;
4612 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
4613 return INT2FIX(c & 0xff);
4617 * call-seq:
4618 * ios.readbyte -> integer
4620 * Reads a byte as with IO#getbyte, but raises an EOFError on end of
4621 * file.
4624 static VALUE
4625 rb_io_readbyte(VALUE io)
4627 VALUE c = rb_io_getbyte(io);
4629 if (NIL_P(c)) {
4630 rb_eof_error();
4632 return c;
4636 * call-seq:
4637 * ios.ungetbyte(string) -> nil
4638 * ios.ungetbyte(integer) -> nil
4640 * Pushes back bytes (passed as a parameter) onto <em>ios</em>,
4641 * such that a subsequent buffered read will return it.
4642 * It is only guaranteed to support a single byte, and only if ungetbyte
4643 * or ungetc has not already been called on <em>ios</em> since the previous
4644 * read of at least a single byte from <em>ios</em>.
4645 * However, it can support additional bytes if there is space in the
4646 * internal buffer to allow for it.
4648 * f = File.new("testfile") #=> #<File:testfile>
4649 * b = f.getbyte #=> 0x38
4650 * f.ungetbyte(b) #=> nil
4651 * f.getbyte #=> 0x38
4653 * If given an integer, only uses the lower 8 bits of the integer as the byte
4654 * to push.
4656 * f = File.new("testfile") #=> #<File:testfile>
4657 * f.ungetbyte(0x102) #=> nil
4658 * f.getbyte #=> 0x2
4660 * Calling this method prepends to the existing buffer, even if the method
4661 * has already been called previously:
4663 * f = File.new("testfile") #=> #<File:testfile>
4664 * f.ungetbyte("ab") #=> nil
4665 * f.ungetbyte("cd") #=> nil
4666 * f.read(5) #=> "cdab8"
4668 * Has no effect with unbuffered reads (such as IO#sysread).
4671 VALUE
4672 rb_io_ungetbyte(VALUE io, VALUE b)
4674 rb_io_t *fptr;
4676 GetOpenFile(io, fptr);
4677 rb_io_check_byte_readable(fptr);
4678 switch (TYPE(b)) {
4679 case T_NIL:
4680 return Qnil;
4681 case T_FIXNUM:
4682 case T_BIGNUM: ;
4683 VALUE v = rb_int_modulo(b, INT2FIX(256));
4684 unsigned char c = NUM2INT(v) & 0xFF;
4685 b = rb_str_new((const char *)&c, 1);
4686 break;
4687 default:
4688 SafeStringValue(b);
4690 io_ungetbyte(b, fptr);
4691 return Qnil;
4695 * call-seq:
4696 * ios.ungetc(integer) -> nil
4697 * ios.ungetc(string) -> nil
4699 * Pushes back characters (passed as a parameter) onto <em>ios</em>,
4700 * such that a subsequent buffered read will return it.
4701 * It is only guaranteed to support a single byte, and only if ungetbyte
4702 * or ungetc has not already been called on <em>ios</em> since the previous
4703 * read of at least a single byte from <em>ios</em>.
4704 * However, it can support additional bytes if there is space in the
4705 * internal buffer to allow for it.
4707 * f = File.new("testfile") #=> #<File:testfile>
4708 * c = f.getc #=> "8"
4709 * f.ungetc(c) #=> nil
4710 * f.getc #=> "8"
4712 * If given an integer, the integer must represent a valid codepoint in the
4713 * external encoding of <em>ios</em>.
4715 * Calling this method prepends to the existing buffer, even if the method
4716 * has already been called previously:
4718 * f = File.new("testfile") #=> #<File:testfile>
4719 * f.ungetc("ab") #=> nil
4720 * f.ungetc("cd") #=> nil
4721 * f.read(5) #=> "cdab8"
4723 * Has no effect with unbuffered reads (such as IO#sysread).
4726 VALUE
4727 rb_io_ungetc(VALUE io, VALUE c)
4729 rb_io_t *fptr;
4730 long len;
4732 GetOpenFile(io, fptr);
4733 rb_io_check_char_readable(fptr);
4734 if (FIXNUM_P(c)) {
4735 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
4737 else if (RB_BIGNUM_TYPE_P(c)) {
4738 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
4740 else {
4741 SafeStringValue(c);
4743 if (NEED_READCONV(fptr)) {
4744 SET_BINARY_MODE(fptr);
4745 len = RSTRING_LEN(c);
4746 #if SIZEOF_LONG > SIZEOF_INT
4747 if (len > INT_MAX)
4748 rb_raise(rb_eIOError, "ungetc failed");
4749 #endif
4750 make_readconv(fptr, (int)len);
4751 if (fptr->cbuf.capa - fptr->cbuf.len < len)
4752 rb_raise(rb_eIOError, "ungetc failed");
4753 if (fptr->cbuf.off < len) {
4754 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
4755 fptr->cbuf.ptr+fptr->cbuf.off,
4756 char, fptr->cbuf.len);
4757 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
4759 fptr->cbuf.off -= (int)len;
4760 fptr->cbuf.len += (int)len;
4761 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
4763 else {
4764 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4765 io_ungetbyte(c, fptr);
4767 return Qnil;
4771 * call-seq:
4772 * ios.isatty -> true or false
4773 * ios.tty? -> true or false
4775 * Returns <code>true</code> if <em>ios</em> is associated with a
4776 * terminal device (tty), <code>false</code> otherwise.
4778 * File.new("testfile").isatty #=> false
4779 * File.new("/dev/tty").isatty #=> true
4782 static VALUE
4783 rb_io_isatty(VALUE io)
4785 rb_io_t *fptr;
4787 GetOpenFile(io, fptr);
4788 return RBOOL(isatty(fptr->fd) != 0);
4791 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
4793 * call-seq:
4794 * ios.close_on_exec? -> true or false
4796 * Returns <code>true</code> if <em>ios</em> will be closed on exec.
4798 * f = open("/dev/null")
4799 * f.close_on_exec? #=> false
4800 * f.close_on_exec = true
4801 * f.close_on_exec? #=> true
4802 * f.close_on_exec = false
4803 * f.close_on_exec? #=> false
4806 static VALUE
4807 rb_io_close_on_exec_p(VALUE io)
4809 rb_io_t *fptr;
4810 VALUE write_io;
4811 int fd, ret;
4813 write_io = GetWriteIO(io);
4814 if (io != write_io) {
4815 GetOpenFile(write_io, fptr);
4816 if (fptr && 0 <= (fd = fptr->fd)) {
4817 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
4818 if (!(ret & FD_CLOEXEC)) return Qfalse;
4822 GetOpenFile(io, fptr);
4823 if (fptr && 0 <= (fd = fptr->fd)) {
4824 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
4825 if (!(ret & FD_CLOEXEC)) return Qfalse;
4827 return Qtrue;
4829 #else
4830 #define rb_io_close_on_exec_p rb_f_notimplement
4831 #endif
4833 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
4835 * call-seq:
4836 * ios.close_on_exec = bool -> true or false
4838 * Sets a close-on-exec flag.
4840 * f = open("/dev/null")
4841 * f.close_on_exec = true
4842 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
4843 * f.closed? #=> false
4845 * Ruby sets close-on-exec flags of all file descriptors by default
4846 * since Ruby 2.0.0.
4847 * So you don't need to set by yourself.
4848 * Also, unsetting a close-on-exec flag can cause file descriptor leak
4849 * if another thread use fork() and exec() (via system() method for example).
4850 * If you really needs file descriptor inheritance to child process,
4851 * use spawn()'s argument such as fd=>fd.
4854 static VALUE
4855 rb_io_set_close_on_exec(VALUE io, VALUE arg)
4857 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
4858 rb_io_t *fptr;
4859 VALUE write_io;
4860 int fd, ret;
4862 write_io = GetWriteIO(io);
4863 if (io != write_io) {
4864 GetOpenFile(write_io, fptr);
4865 if (fptr && 0 <= (fd = fptr->fd)) {
4866 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
4867 if ((ret & FD_CLOEXEC) != flag) {
4868 ret = (ret & ~FD_CLOEXEC) | flag;
4869 ret = fcntl(fd, F_SETFD, ret);
4870 if (ret != 0) rb_sys_fail_path(fptr->pathv);
4876 GetOpenFile(io, fptr);
4877 if (fptr && 0 <= (fd = fptr->fd)) {
4878 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
4879 if ((ret & FD_CLOEXEC) != flag) {
4880 ret = (ret & ~FD_CLOEXEC) | flag;
4881 ret = fcntl(fd, F_SETFD, ret);
4882 if (ret != 0) rb_sys_fail_path(fptr->pathv);
4885 return Qnil;
4887 #else
4888 #define rb_io_set_close_on_exec rb_f_notimplement
4889 #endif
4891 #define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
4892 #define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
4894 static VALUE
4895 finish_writeconv(rb_io_t *fptr, int noalloc)
4897 unsigned char *ds, *dp, *de;
4898 rb_econv_result_t res;
4900 if (!fptr->wbuf.ptr) {
4901 unsigned char buf[1024];
4902 long r;
4904 res = econv_destination_buffer_full;
4905 while (res == econv_destination_buffer_full) {
4906 ds = dp = buf;
4907 de = buf + sizeof(buf);
4908 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
4909 while (dp-ds) {
4910 retry:
4911 r = rb_write_internal(fptr, ds, dp-ds);
4912 if (r == dp-ds)
4913 break;
4914 if (0 <= r) {
4915 ds += r;
4917 if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) {
4918 if (fptr->fd < 0)
4919 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
4920 goto retry;
4922 return noalloc ? Qtrue : INT2NUM(errno);
4924 if (res == econv_invalid_byte_sequence ||
4925 res == econv_incomplete_input ||
4926 res == econv_undefined_conversion) {
4927 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
4931 return Qnil;
4934 res = econv_destination_buffer_full;
4935 while (res == econv_destination_buffer_full) {
4936 if (fptr->wbuf.len == fptr->wbuf.capa) {
4937 if (io_fflush(fptr) < 0)
4938 return noalloc ? Qtrue : INT2NUM(errno);
4941 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
4942 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
4943 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
4944 fptr->wbuf.len += (int)(dp - ds);
4945 if (res == econv_invalid_byte_sequence ||
4946 res == econv_incomplete_input ||
4947 res == econv_undefined_conversion) {
4948 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
4951 return Qnil;
4954 struct finish_writeconv_arg {
4955 rb_io_t *fptr;
4956 int noalloc;
4959 static VALUE
4960 finish_writeconv_sync(VALUE arg)
4962 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
4963 return finish_writeconv(p->fptr, p->noalloc);
4966 static void*
4967 nogvl_close(void *ptr)
4969 int *fd = ptr;
4971 return (void*)(intptr_t)close(*fd);
4974 static int
4975 maygvl_close(int fd, int keepgvl)
4977 if (keepgvl)
4978 return close(fd);
4981 * close() may block for certain file types (NFS, SO_LINGER sockets,
4982 * inotify), so let other threads run.
4984 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
4987 static void*
4988 nogvl_fclose(void *ptr)
4990 FILE *file = ptr;
4992 return (void*)(intptr_t)fclose(file);
4995 static int
4996 maygvl_fclose(FILE *file, int keepgvl)
4998 if (keepgvl)
4999 return fclose(file);
5001 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
5004 static void free_io_buffer(rb_io_buffer_t *buf);
5005 static void clear_codeconv(rb_io_t *fptr);
5007 static void
5008 fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5009 struct list_head *busy)
5011 VALUE err = Qnil;
5012 int fd = fptr->fd;
5013 FILE *stdio_file = fptr->stdio_file;
5014 int mode = fptr->mode;
5016 if (fptr->writeconv) {
5017 if (fptr->write_lock && !noraise) {
5018 struct finish_writeconv_arg arg;
5019 arg.fptr = fptr;
5020 arg.noalloc = noraise;
5021 err = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5023 else {
5024 err = finish_writeconv(fptr, noraise);
5027 if (fptr->wbuf.len) {
5028 if (noraise) {
5029 io_flush_buffer_sync(fptr);
5031 else {
5032 if (io_fflush(fptr) < 0 && NIL_P(err))
5033 err = INT2NUM(errno);
5037 int done = 0;
5039 if (IS_PREP_STDIO(fptr) || fd <= 2) {
5040 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5041 done = 1;
5044 fptr->fd = -1;
5045 fptr->stdio_file = 0;
5046 fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
5048 // Ensure waiting_fd users do not hit EBADF.
5049 if (busy) {
5050 // Wait for them to exit before we call close().
5051 do rb_thread_schedule(); while (!list_empty(busy));
5054 // Disable for now.
5055 // if (!done && fd >= 0) {
5056 // VALUE scheduler = rb_fiber_scheduler_current();
5057 // if (scheduler != Qnil) {
5058 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5059 // if (result != Qundef) done = 1;
5060 // }
5061 // }
5063 if (!done && stdio_file) {
5064 // stdio_file is deallocated anyway even if fclose failed.
5065 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(err))
5066 if (!noraise) err = INT2NUM(errno);
5068 done = 1;
5071 if (!done && fd >= 0) {
5072 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5073 // We assumes it is closed.
5075 keepgvl |= !(mode & FMODE_WRITABLE);
5076 keepgvl |= noraise;
5077 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(err))
5078 if (!noraise) err = INT2NUM(errno);
5080 done = 1;
5083 if (!NIL_P(err) && !noraise) {
5084 if (RB_INTEGER_TYPE_P(err))
5085 rb_syserr_fail_path(NUM2INT(err), fptr->pathv);
5086 else
5087 rb_exc_raise(err);
5091 static void
5092 fptr_finalize(rb_io_t *fptr, int noraise)
5094 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5095 free_io_buffer(&fptr->rbuf);
5096 free_io_buffer(&fptr->wbuf);
5097 clear_codeconv(fptr);
5100 static void
5101 rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5103 if (fptr->finalize) {
5104 (*fptr->finalize)(fptr, noraise);
5106 else {
5107 fptr_finalize(fptr, noraise);
5111 static void
5112 free_io_buffer(rb_io_buffer_t *buf)
5114 if (buf->ptr) {
5115 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5116 buf->ptr = NULL;
5120 static void
5121 clear_readconv(rb_io_t *fptr)
5123 if (fptr->readconv) {
5124 rb_econv_close(fptr->readconv);
5125 fptr->readconv = NULL;
5127 free_io_buffer(&fptr->cbuf);
5130 static void
5131 clear_writeconv(rb_io_t *fptr)
5133 if (fptr->writeconv) {
5134 rb_econv_close(fptr->writeconv);
5135 fptr->writeconv = NULL;
5137 fptr->writeconv_initialized = 0;
5140 static void
5141 clear_codeconv(rb_io_t *fptr)
5143 clear_readconv(fptr);
5144 clear_writeconv(fptr);
5147 void
5148 rb_io_fptr_finalize_internal(void *ptr)
5150 rb_io_t *fptr = ptr;
5152 if (!ptr) return;
5153 fptr->pathv = Qnil;
5154 if (0 <= fptr->fd)
5155 rb_io_fptr_cleanup(fptr, TRUE);
5156 fptr->write_lock = 0;
5157 free_io_buffer(&fptr->rbuf);
5158 free_io_buffer(&fptr->wbuf);
5159 clear_codeconv(fptr);
5160 free(fptr);
5163 #undef rb_io_fptr_finalize
5165 rb_io_fptr_finalize(rb_io_t *fptr)
5167 if (!fptr) {
5168 return 0;
5170 else {
5171 rb_io_fptr_finalize_internal(fptr);
5172 return 1;
5175 #define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5177 RUBY_FUNC_EXPORTED size_t
5178 rb_io_memsize(const rb_io_t *fptr)
5180 size_t size = sizeof(rb_io_t);
5181 size += fptr->rbuf.capa;
5182 size += fptr->wbuf.capa;
5183 size += fptr->cbuf.capa;
5184 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5185 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5186 return size;
5189 #ifdef _WIN32
5190 /* keep GVL while closing to prevent crash on Windows */
5191 # define KEEPGVL TRUE
5192 #else
5193 # define KEEPGVL FALSE
5194 #endif
5196 int rb_notify_fd_close(int fd, struct list_head *);
5197 static rb_io_t *
5198 io_close_fptr(VALUE io)
5200 rb_io_t *fptr;
5201 VALUE write_io;
5202 rb_io_t *write_fptr;
5203 struct list_head busy;
5205 list_head_init(&busy);
5206 write_io = GetWriteIO(io);
5207 if (io != write_io) {
5208 write_fptr = RFILE(write_io)->fptr;
5209 if (write_fptr && 0 <= write_fptr->fd) {
5210 rb_io_fptr_cleanup(write_fptr, TRUE);
5214 fptr = RFILE(io)->fptr;
5215 if (!fptr) return 0;
5216 if (fptr->fd < 0) return 0;
5218 if (rb_notify_fd_close(fptr->fd, &busy)) {
5219 /* calls close(fptr->fd): */
5220 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5222 rb_io_fptr_cleanup(fptr, FALSE);
5223 return fptr;
5226 static void
5227 fptr_waitpid(rb_io_t *fptr, int nohang)
5229 int status;
5230 if (fptr->pid) {
5231 rb_last_status_clear();
5232 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5233 fptr->pid = 0;
5237 VALUE
5238 rb_io_close(VALUE io)
5240 rb_io_t *fptr = io_close_fptr(io);
5241 if (fptr) fptr_waitpid(fptr, 0);
5242 return Qnil;
5246 * call-seq:
5247 * ios.close -> nil
5249 * Closes <em>ios</em> and flushes any pending writes to the operating
5250 * system. The stream is unavailable for any further data operations;
5251 * an IOError is raised if such an attempt is made. I/O streams are
5252 * automatically closed when they are claimed by the garbage collector.
5254 * If <em>ios</em> is opened by IO.popen, #close sets
5255 * <code>$?</code>.
5257 * Calling this method on closed IO object is just ignored since Ruby 2.3.
5260 static VALUE
5261 rb_io_close_m(VALUE io)
5263 rb_io_t *fptr = rb_io_get_fptr(io);
5264 if (fptr->fd < 0) {
5265 return Qnil;
5267 rb_io_close(io);
5268 return Qnil;
5271 static VALUE
5272 io_call_close(VALUE io)
5274 rb_check_funcall(io, rb_intern("close"), 0, 0);
5275 return io;
5278 static VALUE
5279 ignore_closed_stream(VALUE io, VALUE exc)
5281 enum {mesg_len = sizeof(closed_stream)-1};
5282 VALUE mesg = rb_attr_get(exc, idMesg);
5283 if (!RB_TYPE_P(mesg, T_STRING) ||
5284 RSTRING_LEN(mesg) != mesg_len ||
5285 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5286 rb_exc_raise(exc);
5288 return io;
5291 static VALUE
5292 io_close(VALUE io)
5294 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5295 if (closed != Qundef && RTEST(closed)) return io;
5296 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5297 rb_eIOError, (VALUE)0);
5298 return io;
5302 * call-seq:
5303 * ios.closed? -> true or false
5305 * Returns <code>true</code> if <em>ios</em> is completely closed (for
5306 * duplex streams, both reader and writer), <code>false</code>
5307 * otherwise.
5309 * f = File.new("testfile")
5310 * f.close #=> nil
5311 * f.closed? #=> true
5312 * f = IO.popen("/bin/sh","r+")
5313 * f.close_write #=> nil
5314 * f.closed? #=> false
5315 * f.close_read #=> nil
5316 * f.closed? #=> true
5320 static VALUE
5321 rb_io_closed(VALUE io)
5323 rb_io_t *fptr;
5324 VALUE write_io;
5325 rb_io_t *write_fptr;
5327 write_io = GetWriteIO(io);
5328 if (io != write_io) {
5329 write_fptr = RFILE(write_io)->fptr;
5330 if (write_fptr && 0 <= write_fptr->fd) {
5331 return Qfalse;
5335 fptr = rb_io_get_fptr(io);
5336 return RBOOL(0 > fptr->fd);
5340 * call-seq:
5341 * ios.close_read -> nil
5343 * Closes the read end of a duplex I/O stream (i.e., one that contains
5344 * both a read and a write stream, such as a pipe). Will raise an
5345 * IOError if the stream is not duplexed.
5347 * f = IO.popen("/bin/sh","r+")
5348 * f.close_read
5349 * f.readlines
5351 * <em>produces:</em>
5353 * prog.rb:3:in `readlines': not opened for reading (IOError)
5354 * from prog.rb:3
5356 * Calling this method on closed IO object is just ignored since Ruby 2.3.
5359 static VALUE
5360 rb_io_close_read(VALUE io)
5362 rb_io_t *fptr;
5363 VALUE write_io;
5365 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5366 if (fptr->fd < 0) return Qnil;
5367 if (is_socket(fptr->fd, fptr->pathv)) {
5368 #ifndef SHUT_RD
5369 # define SHUT_RD 0
5370 #endif
5371 if (shutdown(fptr->fd, SHUT_RD) < 0)
5372 rb_sys_fail_path(fptr->pathv);
5373 fptr->mode &= ~FMODE_READABLE;
5374 if (!(fptr->mode & FMODE_WRITABLE))
5375 return rb_io_close(io);
5376 return Qnil;
5379 write_io = GetWriteIO(io);
5380 if (io != write_io) {
5381 rb_io_t *wfptr;
5382 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5383 wfptr->pid = fptr->pid;
5384 fptr->pid = 0;
5385 RFILE(io)->fptr = wfptr;
5386 /* bind to write_io temporarily to get rid of memory/fd leak */
5387 fptr->tied_io_for_writing = 0;
5388 RFILE(write_io)->fptr = fptr;
5389 rb_io_fptr_cleanup(fptr, FALSE);
5390 /* should not finalize fptr because another thread may be reading it */
5391 return Qnil;
5394 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5395 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5397 return rb_io_close(io);
5401 * call-seq:
5402 * ios.close_write -> nil
5404 * Closes the write end of a duplex I/O stream (i.e., one that contains
5405 * both a read and a write stream, such as a pipe). Will raise an
5406 * IOError if the stream is not duplexed.
5408 * f = IO.popen("/bin/sh","r+")
5409 * f.close_write
5410 * f.print "nowhere"
5412 * <em>produces:</em>
5414 * prog.rb:3:in `write': not opened for writing (IOError)
5415 * from prog.rb:3:in `print'
5416 * from prog.rb:3
5418 * Calling this method on closed IO object is just ignored since Ruby 2.3.
5421 static VALUE
5422 rb_io_close_write(VALUE io)
5424 rb_io_t *fptr;
5425 VALUE write_io;
5427 write_io = GetWriteIO(io);
5428 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5429 if (fptr->fd < 0) return Qnil;
5430 if (is_socket(fptr->fd, fptr->pathv)) {
5431 #ifndef SHUT_WR
5432 # define SHUT_WR 1
5433 #endif
5434 if (shutdown(fptr->fd, SHUT_WR) < 0)
5435 rb_sys_fail_path(fptr->pathv);
5436 fptr->mode &= ~FMODE_WRITABLE;
5437 if (!(fptr->mode & FMODE_READABLE))
5438 return rb_io_close(write_io);
5439 return Qnil;
5442 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
5443 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
5446 if (io != write_io) {
5447 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5448 fptr->tied_io_for_writing = 0;
5450 rb_io_close(write_io);
5451 return Qnil;
5455 * call-seq:
5456 * ios.sysseek(offset, whence=IO::SEEK_SET) -> integer
5458 * Seeks to a given <i>offset</i> in the stream according to the value
5459 * of <i>whence</i> (see IO#seek for values of <i>whence</i>). Returns
5460 * the new offset into the file.
5462 * f = File.new("testfile")
5463 * f.sysseek(-13, IO::SEEK_END) #=> 53
5464 * f.sysread(10) #=> "And so on."
5467 static VALUE
5468 rb_io_sysseek(int argc, VALUE *argv, VALUE io)
5470 VALUE offset, ptrname;
5471 int whence = SEEK_SET;
5472 rb_io_t *fptr;
5473 off_t pos;
5475 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
5476 whence = interpret_seek_whence(ptrname);
5478 pos = NUM2OFFT(offset);
5479 GetOpenFile(io, fptr);
5480 if ((fptr->mode & FMODE_READABLE) &&
5481 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5482 rb_raise(rb_eIOError, "sysseek for buffered IO");
5484 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
5485 rb_warn("sysseek for buffered IO");
5487 errno = 0;
5488 pos = lseek(fptr->fd, pos, whence);
5489 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
5491 return OFFT2NUM(pos);
5495 * call-seq:
5496 * ios.syswrite(string) -> integer
5498 * Writes the given string to <em>ios</em> using a low-level write.
5499 * Returns the number of bytes written. Do not mix with other methods
5500 * that write to <em>ios</em> or you may get unpredictable results.
5501 * Raises SystemCallError on error.
5503 * f = File.new("out", "w")
5504 * f.syswrite("ABCDEF") #=> 6
5507 static VALUE
5508 rb_io_syswrite(VALUE io, VALUE str)
5510 VALUE tmp;
5511 rb_io_t *fptr;
5512 long n, len;
5513 const char *ptr;
5515 if (!RB_TYPE_P(str, T_STRING))
5516 str = rb_obj_as_string(str);
5518 io = GetWriteIO(io);
5519 GetOpenFile(io, fptr);
5520 rb_io_check_writable(fptr);
5522 if (fptr->wbuf.len) {
5523 rb_warn("syswrite for buffered IO");
5526 tmp = rb_str_tmp_frozen_acquire(str);
5527 RSTRING_GETMEM(tmp, ptr, len);
5528 n = rb_write_internal(fptr, ptr, len);
5529 if (n < 0) rb_sys_fail_path(fptr->pathv);
5530 rb_str_tmp_frozen_release(str, tmp);
5532 return LONG2FIX(n);
5536 * call-seq:
5537 * ios.sysread(maxlen[, outbuf]) -> string
5539 * Reads <i>maxlen</i> bytes from <em>ios</em> using a low-level
5540 * read and returns them as a string. Do not mix with other methods
5541 * that read from <em>ios</em> or you may get unpredictable results.
5543 * If the optional _outbuf_ argument is present,
5544 * it must reference a String, which will receive the data.
5545 * The _outbuf_ will contain only the received data after the method call
5546 * even if it is not empty at the beginning.
5548 * Raises SystemCallError on error and EOFError at end of file.
5550 * f = File.new("testfile")
5551 * f.sysread(16) #=> "This is line one"
5554 static VALUE
5555 rb_io_sysread(int argc, VALUE *argv, VALUE io)
5557 VALUE len, str;
5558 rb_io_t *fptr;
5559 long n, ilen;
5560 struct io_internal_read_struct iis;
5561 int shrinkable;
5563 rb_scan_args(argc, argv, "11", &len, &str);
5564 ilen = NUM2LONG(len);
5566 shrinkable = io_setstrbuf(&str, ilen);
5567 if (ilen == 0) return str;
5569 GetOpenFile(io, fptr);
5570 rb_io_check_byte_readable(fptr);
5572 if (READ_DATA_BUFFERED(fptr)) {
5573 rb_raise(rb_eIOError, "sysread for buffered IO");
5576 rb_io_check_closed(fptr);
5578 io_setstrbuf(&str, ilen);
5579 iis.th = rb_thread_current();
5580 iis.fptr = fptr;
5581 iis.nonblock = 0;
5582 iis.buf = RSTRING_PTR(str);
5583 iis.capa = ilen;
5584 n = read_internal_locktmp(str, &iis);
5586 if (n < 0) {
5587 rb_sys_fail_path(fptr->pathv);
5590 io_set_read_length(str, n, shrinkable);
5592 if (n == 0 && ilen > 0) {
5593 rb_eof_error();
5596 return str;
5599 #if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
5600 struct prdwr_internal_arg {
5601 int fd;
5602 void *buf;
5603 size_t count;
5604 off_t offset;
5606 #endif /* HAVE_PREAD || HAVE_PWRITE */
5608 #if defined(HAVE_PREAD)
5609 static VALUE
5610 internal_pread_func(void *arg)
5612 struct prdwr_internal_arg *p = arg;
5613 return (VALUE)pread(p->fd, p->buf, p->count, p->offset);
5616 static VALUE
5617 pread_internal_call(VALUE arg)
5619 struct prdwr_internal_arg *p = (struct prdwr_internal_arg *)arg;
5620 return rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
5624 * call-seq:
5625 * ios.pread(maxlen, offset[, outbuf]) -> string
5627 * Reads <i>maxlen</i> bytes from <em>ios</em> using the pread system call
5628 * and returns them as a string without modifying the underlying
5629 * descriptor offset. This is advantageous compared to combining IO#seek
5630 * and IO#read in that it is atomic, allowing multiple threads/process to
5631 * share the same IO object for reading the file at various locations.
5632 * This bypasses any userspace buffering of the IO layer.
5633 * If the optional <i>outbuf</i> argument is present, it must
5634 * reference a String, which will receive the data.
5635 * Raises SystemCallError on error, EOFError at end of file and
5636 * NotImplementedError if platform does not implement the system call.
5638 * File.write("testfile", "This is line one\nThis is line two\n")
5639 * File.open("testfile") do |f|
5640 * p f.read # => "This is line one\nThis is line two\n"
5641 * p f.pread(12, 0) # => "This is line"
5642 * p f.pread(9, 8) # => "line one\n"
5643 * end
5645 static VALUE
5646 rb_io_pread(int argc, VALUE *argv, VALUE io)
5648 VALUE len, offset, str;
5649 rb_io_t *fptr;
5650 ssize_t n;
5651 struct prdwr_internal_arg arg;
5652 int shrinkable;
5654 rb_scan_args(argc, argv, "21", &len, &offset, &str);
5655 arg.count = NUM2SIZET(len);
5656 arg.offset = NUM2OFFT(offset);
5658 shrinkable = io_setstrbuf(&str, (long)arg.count);
5659 if (arg.count == 0) return str;
5660 arg.buf = RSTRING_PTR(str);
5662 GetOpenFile(io, fptr);
5663 rb_io_check_byte_readable(fptr);
5665 arg.fd = fptr->fd;
5666 rb_io_check_closed(fptr);
5668 rb_str_locktmp(str);
5669 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
5671 if (n < 0) {
5672 rb_sys_fail_path(fptr->pathv);
5674 io_set_read_length(str, n, shrinkable);
5675 if (n == 0 && arg.count > 0) {
5676 rb_eof_error();
5679 return str;
5681 #else
5682 # define rb_io_pread rb_f_notimplement
5683 #endif /* HAVE_PREAD */
5685 #if defined(HAVE_PWRITE)
5686 static VALUE
5687 internal_pwrite_func(void *ptr)
5689 struct prdwr_internal_arg *arg = ptr;
5691 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
5695 * call-seq:
5696 * ios.pwrite(string, offset) -> integer
5698 * Writes the given string to <em>ios</em> at <i>offset</i> using pwrite()
5699 * system call. This is advantageous to combining IO#seek and IO#write
5700 * in that it is atomic, allowing multiple threads/process to share the
5701 * same IO object for reading the file at various locations.
5702 * This bypasses any userspace buffering of the IO layer.
5703 * Returns the number of bytes written.
5704 * Raises SystemCallError on error and NotImplementedError
5705 * if platform does not implement the system call.
5707 * File.open("out", "w") do |f|
5708 * f.pwrite("ABCDEF", 3) #=> 6
5709 * end
5711 * File.read("out") #=> "\u0000\u0000\u0000ABCDEF"
5713 static VALUE
5714 rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
5716 rb_io_t *fptr;
5717 ssize_t n;
5718 struct prdwr_internal_arg arg;
5719 VALUE tmp;
5721 if (!RB_TYPE_P(str, T_STRING))
5722 str = rb_obj_as_string(str);
5724 arg.offset = NUM2OFFT(offset);
5726 io = GetWriteIO(io);
5727 GetOpenFile(io, fptr);
5728 rb_io_check_writable(fptr);
5729 arg.fd = fptr->fd;
5731 tmp = rb_str_tmp_frozen_acquire(str);
5732 arg.buf = RSTRING_PTR(tmp);
5733 arg.count = (size_t)RSTRING_LEN(tmp);
5735 n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
5736 if (n < 0) rb_sys_fail_path(fptr->pathv);
5737 rb_str_tmp_frozen_release(str, tmp);
5739 return SSIZET2NUM(n);
5741 #else
5742 # define rb_io_pwrite rb_f_notimplement
5743 #endif /* HAVE_PWRITE */
5745 VALUE
5746 rb_io_binmode(VALUE io)
5748 rb_io_t *fptr;
5750 GetOpenFile(io, fptr);
5751 if (fptr->readconv)
5752 rb_econv_binmode(fptr->readconv);
5753 if (fptr->writeconv)
5754 rb_econv_binmode(fptr->writeconv);
5755 fptr->mode |= FMODE_BINMODE;
5756 fptr->mode &= ~FMODE_TEXTMODE;
5757 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
5758 #ifdef O_BINARY
5759 if (!fptr->readconv) {
5760 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
5762 else {
5763 setmode(fptr->fd, O_BINARY);
5765 #endif
5766 return io;
5769 static void
5770 io_ascii8bit_binmode(rb_io_t *fptr)
5772 if (fptr->readconv) {
5773 rb_econv_close(fptr->readconv);
5774 fptr->readconv = NULL;
5776 if (fptr->writeconv) {
5777 rb_econv_close(fptr->writeconv);
5778 fptr->writeconv = NULL;
5780 fptr->mode |= FMODE_BINMODE;
5781 fptr->mode &= ~FMODE_TEXTMODE;
5782 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
5784 fptr->encs.enc = rb_ascii8bit_encoding();
5785 fptr->encs.enc2 = NULL;
5786 fptr->encs.ecflags = 0;
5787 fptr->encs.ecopts = Qnil;
5788 clear_codeconv(fptr);
5791 VALUE
5792 rb_io_ascii8bit_binmode(VALUE io)
5794 rb_io_t *fptr;
5796 GetOpenFile(io, fptr);
5797 io_ascii8bit_binmode(fptr);
5799 return io;
5803 * call-seq:
5804 * ios.binmode -> ios
5806 * Puts <em>ios</em> into binary mode.
5807 * Once a stream is in binary mode, it cannot be reset to nonbinary mode.
5809 * - newline conversion disabled
5810 * - encoding conversion disabled
5811 * - content is treated as ASCII-8BIT
5814 static VALUE
5815 rb_io_binmode_m(VALUE io)
5817 VALUE write_io;
5819 rb_io_ascii8bit_binmode(io);
5821 write_io = GetWriteIO(io);
5822 if (write_io != io)
5823 rb_io_ascii8bit_binmode(write_io);
5824 return io;
5828 * call-seq:
5829 * ios.binmode? -> true or false
5831 * Returns <code>true</code> if <em>ios</em> is binmode.
5833 static VALUE
5834 rb_io_binmode_p(VALUE io)
5836 rb_io_t *fptr;
5837 GetOpenFile(io, fptr);
5838 return RBOOL(fptr->mode & FMODE_BINMODE);
5841 static const char*
5842 rb_io_fmode_modestr(int fmode)
5844 if (fmode & FMODE_APPEND) {
5845 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
5846 return MODE_BTMODE("a+", "ab+", "at+");
5848 return MODE_BTMODE("a", "ab", "at");
5850 switch (fmode & FMODE_READWRITE) {
5851 default:
5852 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
5853 case FMODE_READABLE:
5854 return MODE_BTMODE("r", "rb", "rt");
5855 case FMODE_WRITABLE:
5856 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
5857 case FMODE_READWRITE:
5858 if (fmode & FMODE_CREATE) {
5859 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
5861 return MODE_BTMODE("r+", "rb+", "rt+");
5865 static const char bom_prefix[] = "bom|";
5866 static const char utf_prefix[] = "utf-";
5867 enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
5868 enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
5870 static int
5871 io_encname_bom_p(const char *name, long len)
5873 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
5877 rb_io_modestr_fmode(const char *modestr)
5879 int fmode = 0;
5880 const char *m = modestr, *p = NULL;
5882 switch (*m++) {
5883 case 'r':
5884 fmode |= FMODE_READABLE;
5885 break;
5886 case 'w':
5887 fmode |= FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE;
5888 break;
5889 case 'a':
5890 fmode |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
5891 break;
5892 default:
5893 goto error;
5896 while (*m) {
5897 switch (*m++) {
5898 case 'b':
5899 fmode |= FMODE_BINMODE;
5900 break;
5901 case 't':
5902 fmode |= FMODE_TEXTMODE;
5903 break;
5904 case '+':
5905 fmode |= FMODE_READWRITE;
5906 break;
5907 case 'x':
5908 if (modestr[0] != 'w')
5909 goto error;
5910 fmode |= FMODE_EXCL;
5911 break;
5912 default:
5913 goto error;
5914 case ':':
5915 p = strchr(m, ':');
5916 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
5917 fmode |= FMODE_SETENC_BY_BOM;
5918 goto finished;
5922 finished:
5923 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
5924 goto error;
5926 return fmode;
5928 error:
5929 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
5930 UNREACHABLE_RETURN(Qundef);
5934 rb_io_oflags_fmode(int oflags)
5936 int fmode = 0;
5938 switch (oflags & O_ACCMODE) {
5939 case O_RDONLY:
5940 fmode = FMODE_READABLE;
5941 break;
5942 case O_WRONLY:
5943 fmode = FMODE_WRITABLE;
5944 break;
5945 case O_RDWR:
5946 fmode = FMODE_READWRITE;
5947 break;
5950 if (oflags & O_APPEND) {
5951 fmode |= FMODE_APPEND;
5953 if (oflags & O_TRUNC) {
5954 fmode |= FMODE_TRUNC;
5956 if (oflags & O_CREAT) {
5957 fmode |= FMODE_CREATE;
5959 if (oflags & O_EXCL) {
5960 fmode |= FMODE_EXCL;
5962 #ifdef O_BINARY
5963 if (oflags & O_BINARY) {
5964 fmode |= FMODE_BINMODE;
5966 #endif
5968 return fmode;
5971 static int
5972 rb_io_fmode_oflags(int fmode)
5974 int oflags = 0;
5976 switch (fmode & FMODE_READWRITE) {
5977 case FMODE_READABLE:
5978 oflags |= O_RDONLY;
5979 break;
5980 case FMODE_WRITABLE:
5981 oflags |= O_WRONLY;
5982 break;
5983 case FMODE_READWRITE:
5984 oflags |= O_RDWR;
5985 break;
5988 if (fmode & FMODE_APPEND) {
5989 oflags |= O_APPEND;
5991 if (fmode & FMODE_TRUNC) {
5992 oflags |= O_TRUNC;
5994 if (fmode & FMODE_CREATE) {
5995 oflags |= O_CREAT;
5997 if (fmode & FMODE_EXCL) {
5998 oflags |= O_EXCL;
6000 #ifdef O_BINARY
6001 if (fmode & FMODE_BINMODE) {
6002 oflags |= O_BINARY;
6004 #endif
6006 return oflags;
6010 rb_io_modestr_oflags(const char *modestr)
6012 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6015 static const char*
6016 rb_io_oflags_modestr(int oflags)
6018 #ifdef O_BINARY
6019 # define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6020 #else
6021 # define MODE_BINARY(a,b) (a)
6022 #endif
6023 int accmode;
6024 if (oflags & O_EXCL) {
6025 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6027 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6028 if (oflags & O_APPEND) {
6029 if (accmode == O_WRONLY) {
6030 return MODE_BINARY("a", "ab");
6032 if (accmode == O_RDWR) {
6033 return MODE_BINARY("a+", "ab+");
6036 switch (accmode) {
6037 default:
6038 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6039 case O_RDONLY:
6040 return MODE_BINARY("r", "rb");
6041 case O_WRONLY:
6042 return MODE_BINARY("w", "wb");
6043 case O_RDWR:
6044 if (oflags & O_TRUNC) {
6045 return MODE_BINARY("w+", "wb+");
6047 return MODE_BINARY("r+", "rb+");
6052 * Convert external/internal encodings to enc/enc2
6053 * NULL => use default encoding
6054 * Qnil => no encoding specified (internal only)
6056 static void
6057 rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6059 int default_ext = 0;
6061 if (ext == NULL) {
6062 ext = rb_default_external_encoding();
6063 default_ext = 1;
6065 if (ext == rb_ascii8bit_encoding()) {
6066 /* If external is ASCII-8BIT, no transcoding */
6067 intern = NULL;
6069 else if (intern == NULL) {
6070 intern = rb_default_internal_encoding();
6072 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6073 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6074 /* No internal encoding => use external + no transcoding */
6075 *enc = (default_ext && intern != ext) ? NULL : ext;
6076 *enc2 = NULL;
6078 else {
6079 *enc = intern;
6080 *enc2 = ext;
6084 static void
6085 unsupported_encoding(const char *name, rb_encoding *enc)
6087 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6090 static void
6091 parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6092 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6094 const char *p;
6095 char encname[ENCODING_MAXNAMELEN+1];
6096 int idx, idx2;
6097 int fmode = fmode_p ? *fmode_p : 0;
6098 rb_encoding *ext_enc, *int_enc;
6099 long len;
6101 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6103 p = strrchr(estr, ':');
6104 len = p ? (p++ - estr) : (long)strlen(estr);
6105 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6106 estr += bom_prefix_len;
6107 len -= bom_prefix_len;
6108 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6109 fmode |= FMODE_SETENC_BY_BOM;
6111 else {
6112 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6113 fmode &= ~FMODE_SETENC_BY_BOM;
6116 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6117 idx = -1;
6119 else {
6120 if (p) {
6121 memcpy(encname, estr, len);
6122 encname[len] = '\0';
6123 estr = encname;
6125 idx = rb_enc_find_index(estr);
6127 if (fmode_p) *fmode_p = fmode;
6129 if (idx >= 0)
6130 ext_enc = rb_enc_from_index(idx);
6131 else {
6132 if (idx != -2)
6133 unsupported_encoding(estr, estr_enc);
6134 ext_enc = NULL;
6137 int_enc = NULL;
6138 if (p) {
6139 if (*p == '-' && *(p+1) == '\0') {
6140 /* Special case - "-" => no transcoding */
6141 int_enc = (rb_encoding *)Qnil;
6143 else {
6144 idx2 = rb_enc_find_index(p);
6145 if (idx2 < 0)
6146 unsupported_encoding(p, estr_enc);
6147 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6148 int_enc = (rb_encoding *)Qnil;
6150 else
6151 int_enc = rb_enc_from_index(idx2);
6155 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6159 rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6161 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6162 int extracted = 0;
6163 rb_encoding *extencoding = NULL;
6164 rb_encoding *intencoding = NULL;
6166 if (!NIL_P(opt)) {
6167 VALUE v;
6168 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6169 if (v != Qnil) encoding = v;
6170 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6171 if (v != Qnil) extenc = v;
6172 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6173 if (v != Qundef) intenc = v;
6175 if ((extenc != Qundef || intenc != Qundef) && !NIL_P(encoding)) {
6176 if (!NIL_P(ruby_verbose)) {
6177 int idx = rb_to_encoding_index(encoding);
6178 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6179 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6180 encoding, extenc == Qundef ? "internal" : "external");
6182 encoding = Qnil;
6184 if (extenc != Qundef && !NIL_P(extenc)) {
6185 extencoding = rb_to_encoding(extenc);
6187 if (intenc != Qundef) {
6188 if (NIL_P(intenc)) {
6189 /* internal_encoding: nil => no transcoding */
6190 intencoding = (rb_encoding *)Qnil;
6192 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6193 char *p = StringValueCStr(tmp);
6195 if (*p == '-' && *(p+1) == '\0') {
6196 /* Special case - "-" => no transcoding */
6197 intencoding = (rb_encoding *)Qnil;
6199 else {
6200 intencoding = rb_to_encoding(intenc);
6203 else {
6204 intencoding = rb_to_encoding(intenc);
6206 if (extencoding == intencoding) {
6207 intencoding = (rb_encoding *)Qnil;
6210 if (!NIL_P(encoding)) {
6211 extracted = 1;
6212 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6213 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6214 enc_p, enc2_p, fmode_p);
6216 else {
6217 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6220 else if (extenc != Qundef || intenc != Qundef) {
6221 extracted = 1;
6222 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6224 return extracted;
6227 typedef struct rb_io_enc_t convconfig_t;
6229 static void
6230 validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6232 int fmode = *fmode_p;
6234 if ((fmode & FMODE_READABLE) &&
6235 !enc2 &&
6236 !(fmode & FMODE_BINMODE) &&
6237 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6238 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6240 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6241 rb_raise(rb_eArgError, "newline decorator with binary mode");
6243 if (!(fmode & FMODE_BINMODE) &&
6244 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6245 fmode |= FMODE_TEXTMODE;
6246 *fmode_p = fmode;
6248 #if !DEFAULT_TEXTMODE
6249 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6250 fmode &= ~FMODE_TEXTMODE;
6251 *fmode_p = fmode;
6253 #endif
6256 static void
6257 extract_binmode(VALUE opthash, int *fmode)
6259 if (!NIL_P(opthash)) {
6260 VALUE v;
6261 v = rb_hash_aref(opthash, sym_textmode);
6262 if (!NIL_P(v)) {
6263 if (*fmode & FMODE_TEXTMODE)
6264 rb_raise(rb_eArgError, "textmode specified twice");
6265 if (*fmode & FMODE_BINMODE)
6266 rb_raise(rb_eArgError, "both textmode and binmode specified");
6267 if (RTEST(v))
6268 *fmode |= FMODE_TEXTMODE;
6270 v = rb_hash_aref(opthash, sym_binmode);
6271 if (!NIL_P(v)) {
6272 if (*fmode & FMODE_BINMODE)
6273 rb_raise(rb_eArgError, "binmode specified twice");
6274 if (*fmode & FMODE_TEXTMODE)
6275 rb_raise(rb_eArgError, "both textmode and binmode specified");
6276 if (RTEST(v))
6277 *fmode |= FMODE_BINMODE;
6280 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6281 rb_raise(rb_eArgError, "both textmode and binmode specified");
6285 void
6286 rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6287 int *oflags_p, int *fmode_p, convconfig_t *convconfig_p)
6289 VALUE vmode;
6290 int oflags, fmode;
6291 rb_encoding *enc, *enc2;
6292 int ecflags;
6293 VALUE ecopts;
6294 int has_enc = 0, has_vmode = 0;
6295 VALUE intmode;
6297 vmode = *vmode_p;
6299 /* Set to defaults */
6300 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6302 vmode_handle:
6303 if (NIL_P(vmode)) {
6304 fmode = FMODE_READABLE;
6305 oflags = O_RDONLY;
6307 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6308 vmode = intmode;
6309 oflags = NUM2INT(intmode);
6310 fmode = rb_io_oflags_fmode(oflags);
6312 else {
6313 const char *p;
6315 SafeStringValue(vmode);
6316 p = StringValueCStr(vmode);
6317 fmode = rb_io_modestr_fmode(p);
6318 oflags = rb_io_fmode_oflags(fmode);
6319 p = strchr(p, ':');
6320 if (p) {
6321 has_enc = 1;
6322 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6324 else {
6325 rb_encoding *e;
6327 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6328 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6332 if (NIL_P(opthash)) {
6333 ecflags = (fmode & FMODE_READABLE) ?
6334 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6335 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6336 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6337 ecflags |= (fmode & FMODE_WRITABLE) ?
6338 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6339 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6340 #endif
6341 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6342 ecopts = Qnil;
6343 if (fmode & FMODE_BINMODE) {
6344 #ifdef O_BINARY
6345 oflags |= O_BINARY;
6346 #endif
6347 if (!has_enc)
6348 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6350 #if DEFAULT_TEXTMODE
6351 else if (NIL_P(vmode)) {
6352 fmode |= DEFAULT_TEXTMODE;
6354 #endif
6356 else {
6357 VALUE v;
6358 if (!has_vmode) {
6359 v = rb_hash_aref(opthash, sym_mode);
6360 if (!NIL_P(v)) {
6361 if (!NIL_P(vmode)) {
6362 rb_raise(rb_eArgError, "mode specified twice");
6364 has_vmode = 1;
6365 vmode = v;
6366 goto vmode_handle;
6369 v = rb_hash_aref(opthash, sym_flags);
6370 if (!NIL_P(v)) {
6371 v = rb_to_int(v);
6372 oflags |= NUM2INT(v);
6373 vmode = INT2NUM(oflags);
6374 fmode = rb_io_oflags_fmode(oflags);
6376 extract_binmode(opthash, &fmode);
6377 if (fmode & FMODE_BINMODE) {
6378 #ifdef O_BINARY
6379 oflags |= O_BINARY;
6380 #endif
6381 if (!has_enc)
6382 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6384 #if DEFAULT_TEXTMODE
6385 else if (NIL_P(vmode)) {
6386 fmode |= DEFAULT_TEXTMODE;
6388 #endif
6389 v = rb_hash_aref(opthash, sym_perm);
6390 if (!NIL_P(v)) {
6391 if (vperm_p) {
6392 if (!NIL_P(*vperm_p)) {
6393 rb_raise(rb_eArgError, "perm specified twice");
6395 *vperm_p = v;
6397 else {
6398 /* perm no use, just ignore */
6401 ecflags = (fmode & FMODE_READABLE) ?
6402 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6403 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6404 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6405 ecflags |= (fmode & FMODE_WRITABLE) ?
6406 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6407 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6408 #endif
6410 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6411 if (has_enc) {
6412 rb_raise(rb_eArgError, "encoding specified twice");
6415 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6416 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
6419 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6421 *vmode_p = vmode;
6423 *oflags_p = oflags;
6424 *fmode_p = fmode;
6425 convconfig_p->enc = enc;
6426 convconfig_p->enc2 = enc2;
6427 convconfig_p->ecflags = ecflags;
6428 convconfig_p->ecopts = ecopts;
6431 struct sysopen_struct {
6432 VALUE fname;
6433 int oflags;
6434 mode_t perm;
6437 static void *
6438 sysopen_func(void *ptr)
6440 const struct sysopen_struct *data = ptr;
6441 const char *fname = RSTRING_PTR(data->fname);
6442 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
6445 static inline int
6446 rb_sysopen_internal(struct sysopen_struct *data)
6448 int fd;
6449 fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
6450 if (0 <= fd)
6451 rb_update_max_fd(fd);
6452 return fd;
6455 static int
6456 rb_sysopen(VALUE fname, int oflags, mode_t perm)
6458 int fd;
6459 struct sysopen_struct data;
6461 data.fname = rb_str_encode_ospath(fname);
6462 StringValueCStr(data.fname);
6463 data.oflags = oflags;
6464 data.perm = perm;
6466 fd = rb_sysopen_internal(&data);
6467 if (fd < 0) {
6468 int e = errno;
6469 if (rb_gc_for_fd(e)) {
6470 fd = rb_sysopen_internal(&data);
6472 if (fd < 0) {
6473 rb_syserr_fail_path(e, fname);
6476 return fd;
6479 FILE *
6480 rb_fdopen(int fd, const char *modestr)
6482 FILE *file;
6484 #if defined(__sun)
6485 errno = 0;
6486 #endif
6487 file = fdopen(fd, modestr);
6488 if (!file) {
6489 int e = errno;
6490 #if defined(__sun)
6491 if (e == 0) {
6492 rb_gc();
6493 errno = 0;
6494 file = fdopen(fd, modestr);
6496 else
6497 #endif
6498 if (rb_gc_for_fd(e)) {
6499 file = fdopen(fd, modestr);
6501 if (!file) {
6502 #ifdef _WIN32
6503 if (e == 0) e = EINVAL;
6504 #elif defined(__sun)
6505 if (e == 0) e = EMFILE;
6506 #endif
6507 rb_syserr_fail(e, 0);
6511 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
6512 #ifdef USE_SETVBUF
6513 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
6514 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
6515 #endif
6516 return file;
6519 static int
6520 io_check_tty(rb_io_t *fptr)
6522 int t = isatty(fptr->fd);
6523 if (t)
6524 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
6525 return t;
6528 static VALUE rb_io_internal_encoding(VALUE);
6529 static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
6531 static int
6532 io_strip_bom(VALUE io)
6534 VALUE b1, b2, b3, b4;
6535 rb_io_t *fptr;
6537 GetOpenFile(io, fptr);
6538 if (!(fptr->mode & FMODE_READABLE)) return 0;
6539 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
6540 switch (b1) {
6541 case INT2FIX(0xEF):
6542 if (NIL_P(b2 = rb_io_getbyte(io))) break;
6543 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
6544 if (b3 == INT2FIX(0xBF)) {
6545 return rb_utf8_encindex();
6547 rb_io_ungetbyte(io, b3);
6549 rb_io_ungetbyte(io, b2);
6550 break;
6552 case INT2FIX(0xFE):
6553 if (NIL_P(b2 = rb_io_getbyte(io))) break;
6554 if (b2 == INT2FIX(0xFF)) {
6555 return ENCINDEX_UTF_16BE;
6557 rb_io_ungetbyte(io, b2);
6558 break;
6560 case INT2FIX(0xFF):
6561 if (NIL_P(b2 = rb_io_getbyte(io))) break;
6562 if (b2 == INT2FIX(0xFE)) {
6563 b3 = rb_io_getbyte(io);
6564 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
6565 if (b4 == INT2FIX(0)) {
6566 return ENCINDEX_UTF_32LE;
6568 rb_io_ungetbyte(io, b4);
6570 rb_io_ungetbyte(io, b3);
6571 return ENCINDEX_UTF_16LE;
6573 rb_io_ungetbyte(io, b2);
6574 break;
6576 case INT2FIX(0):
6577 if (NIL_P(b2 = rb_io_getbyte(io))) break;
6578 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
6579 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
6580 if (b4 == INT2FIX(0xFF)) {
6581 return ENCINDEX_UTF_32BE;
6583 rb_io_ungetbyte(io, b4);
6585 rb_io_ungetbyte(io, b3);
6587 rb_io_ungetbyte(io, b2);
6588 break;
6590 rb_io_ungetbyte(io, b1);
6591 return 0;
6594 static rb_encoding *
6595 io_set_encoding_by_bom(VALUE io)
6597 int idx = io_strip_bom(io);
6598 rb_io_t *fptr;
6599 rb_encoding *extenc = NULL;
6601 GetOpenFile(io, fptr);
6602 if (idx) {
6603 extenc = rb_enc_from_index(idx);
6604 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
6605 rb_io_internal_encoding(io), Qnil);
6607 else {
6608 fptr->encs.enc2 = NULL;
6610 return extenc;
6613 static VALUE
6614 rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
6615 const convconfig_t *convconfig, mode_t perm)
6617 VALUE pathv;
6618 rb_io_t *fptr;
6619 convconfig_t cc;
6620 if (!convconfig) {
6621 /* Set to default encodings */
6622 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
6623 cc.ecflags = 0;
6624 cc.ecopts = Qnil;
6625 convconfig = &cc;
6627 validate_enc_binmode(&fmode, convconfig->ecflags,
6628 convconfig->enc, convconfig->enc2);
6630 MakeOpenFile(io, fptr);
6631 fptr->mode = fmode;
6632 fptr->encs = *convconfig;
6633 pathv = rb_str_new_frozen(filename);
6634 #ifdef O_TMPFILE
6635 if (!(oflags & O_TMPFILE)) {
6636 fptr->pathv = pathv;
6638 #else
6639 fptr->pathv = pathv;
6640 #endif
6641 fptr->fd = rb_sysopen(pathv, oflags, perm);
6642 io_check_tty(fptr);
6643 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
6645 return io;
6648 static VALUE
6649 rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
6651 int fmode = rb_io_modestr_fmode(modestr);
6652 const char *p = strchr(modestr, ':');
6653 convconfig_t convconfig;
6655 if (p) {
6656 parse_mode_enc(p+1, rb_usascii_encoding(),
6657 &convconfig.enc, &convconfig.enc2, &fmode);
6658 convconfig.ecflags = 0;
6659 convconfig.ecopts = Qnil;
6661 else {
6662 rb_encoding *e;
6663 /* Set to default encodings */
6665 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6666 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
6667 convconfig.ecflags = 0;
6668 convconfig.ecopts = Qnil;
6671 return rb_file_open_generic(io, filename,
6672 rb_io_fmode_oflags(fmode),
6673 fmode,
6674 &convconfig,
6675 0666);
6678 VALUE
6679 rb_file_open_str(VALUE fname, const char *modestr)
6681 FilePathValue(fname);
6682 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
6685 VALUE
6686 rb_file_open(const char *fname, const char *modestr)
6688 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
6691 #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
6692 static struct pipe_list {
6693 rb_io_t *fptr;
6694 struct pipe_list *next;
6695 } *pipe_list;
6697 static void
6698 pipe_add_fptr(rb_io_t *fptr)
6700 struct pipe_list *list;
6702 list = ALLOC(struct pipe_list);
6703 list->fptr = fptr;
6704 list->next = pipe_list;
6705 pipe_list = list;
6708 static void
6709 pipe_del_fptr(rb_io_t *fptr)
6711 struct pipe_list **prev = &pipe_list;
6712 struct pipe_list *tmp;
6714 while ((tmp = *prev) != 0) {
6715 if (tmp->fptr == fptr) {
6716 *prev = tmp->next;
6717 free(tmp);
6718 return;
6720 prev = &tmp->next;
6724 #if defined (_WIN32) || defined(__CYGWIN__)
6725 static void
6726 pipe_atexit(void)
6728 struct pipe_list *list = pipe_list;
6729 struct pipe_list *tmp;
6731 while (list) {
6732 tmp = list->next;
6733 rb_io_fptr_finalize(list->fptr);
6734 list = tmp;
6737 #endif
6739 static void
6740 pipe_finalize(rb_io_t *fptr, int noraise)
6742 #if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
6743 int status = 0;
6744 if (fptr->stdio_file) {
6745 status = pclose(fptr->stdio_file);
6747 fptr->fd = -1;
6748 fptr->stdio_file = 0;
6749 rb_last_status_set(status, fptr->pid);
6750 #else
6751 fptr_finalize(fptr, noraise);
6752 #endif
6753 pipe_del_fptr(fptr);
6755 #endif
6757 static void
6758 fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
6760 #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
6761 void (*const old_finalize)(struct rb_io_t*,int) = fptr->finalize;
6763 if (old_finalize == orig->finalize) return;
6764 #endif
6766 fptr->finalize = orig->finalize;
6768 #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
6769 if (old_finalize != pipe_finalize) {
6770 struct pipe_list *list;
6771 for (list = pipe_list; list; list = list->next) {
6772 if (list->fptr == fptr) break;
6774 if (!list) pipe_add_fptr(fptr);
6776 else {
6777 pipe_del_fptr(fptr);
6779 #endif
6782 void
6783 rb_io_synchronized(rb_io_t *fptr)
6785 rb_io_check_initialized(fptr);
6786 fptr->mode |= FMODE_SYNC;
6789 void
6790 rb_io_unbuffered(rb_io_t *fptr)
6792 rb_io_synchronized(fptr);
6796 rb_pipe(int *pipes)
6798 int ret;
6799 ret = rb_cloexec_pipe(pipes);
6800 if (ret < 0) {
6801 if (rb_gc_for_fd(errno)) {
6802 ret = rb_cloexec_pipe(pipes);
6805 if (ret == 0) {
6806 rb_update_max_fd(pipes[0]);
6807 rb_update_max_fd(pipes[1]);
6809 return ret;
6812 #ifdef _WIN32
6813 #define HAVE_SPAWNV 1
6814 #define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
6815 #define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
6816 #endif
6818 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
6819 struct popen_arg {
6820 VALUE execarg_obj;
6821 struct rb_execarg *eargp;
6822 int modef;
6823 int pair[2];
6824 int write_pair[2];
6826 #endif
6828 #ifdef HAVE_WORKING_FORK
6829 # ifndef __EMSCRIPTEN__
6830 static void
6831 popen_redirect(struct popen_arg *p)
6833 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
6834 close(p->write_pair[1]);
6835 if (p->write_pair[0] != 0) {
6836 dup2(p->write_pair[0], 0);
6837 close(p->write_pair[0]);
6839 close(p->pair[0]);
6840 if (p->pair[1] != 1) {
6841 dup2(p->pair[1], 1);
6842 close(p->pair[1]);
6845 else if (p->modef & FMODE_READABLE) {
6846 close(p->pair[0]);
6847 if (p->pair[1] != 1) {
6848 dup2(p->pair[1], 1);
6849 close(p->pair[1]);
6852 else {
6853 close(p->pair[1]);
6854 if (p->pair[0] != 0) {
6855 dup2(p->pair[0], 0);
6856 close(p->pair[0]);
6860 # endif
6862 #if defined(__linux__)
6863 /* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
6864 * Since /proc may not be available, linux_get_maxfd is just a hint.
6865 * This function, linux_get_maxfd, must be async-signal-safe.
6866 * I.e. opendir() is not usable.
6868 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
6869 * However they are easy to re-implement in async-signal-safe manner.
6870 * (Also note that there is missing/memcmp.c.)
6872 static int
6873 linux_get_maxfd(void)
6875 int fd;
6876 char buf[4096], *p, *np, *e;
6877 ssize_t ss;
6878 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
6879 if (fd < 0) return fd;
6880 ss = read(fd, buf, sizeof(buf));
6881 if (ss < 0) goto err;
6882 p = buf;
6883 e = buf + ss;
6884 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
6885 (np = memchr(p, '\n', e-p)) != NULL) {
6886 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
6887 int fdsize;
6888 p += sizeof("FDSize:")-1;
6889 *np = '\0';
6890 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
6891 close(fd);
6892 return fdsize;
6894 p = np+1;
6896 /* fall through */
6898 err:
6899 close(fd);
6900 return (int)ss;
6902 #endif
6904 /* This function should be async-signal-safe. */
6905 void
6906 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
6908 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
6909 int fd, ret;
6910 int max = (int)max_file_descriptor;
6911 # ifdef F_MAXFD
6912 /* F_MAXFD is available since NetBSD 2.0. */
6913 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
6914 if (ret != -1)
6915 maxhint = max = ret;
6916 # elif defined(__linux__)
6917 ret = linux_get_maxfd();
6918 if (maxhint < ret)
6919 maxhint = ret;
6920 /* maxhint = max = ret; if (ret == -1) abort(); // test */
6921 # endif
6922 if (max < maxhint)
6923 max = maxhint;
6924 for (fd = lowfd; fd <= max; fd++) {
6925 if (!NIL_P(noclose_fds) &&
6926 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
6927 continue;
6928 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
6929 if (ret != -1 && !(ret & FD_CLOEXEC)) {
6930 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
6932 # define CONTIGUOUS_CLOSED_FDS 20
6933 if (ret != -1) {
6934 if (max < fd + CONTIGUOUS_CLOSED_FDS)
6935 max = fd + CONTIGUOUS_CLOSED_FDS;
6938 #endif
6941 # ifndef __EMSCRIPTEN__
6942 static int
6943 popen_exec(void *pp, char *errmsg, size_t errmsg_len)
6945 struct popen_arg *p = (struct popen_arg*)pp;
6947 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
6949 # endif
6950 #endif
6952 #if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
6953 static VALUE
6954 rb_execarg_fixup_v(VALUE execarg_obj)
6956 rb_execarg_parent_start(execarg_obj);
6957 return Qnil;
6959 #else
6960 char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
6961 #endif
6963 #ifndef __EMSCRIPTEN__
6964 static VALUE
6965 pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
6966 const convconfig_t *convconfig)
6968 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
6969 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
6970 rb_pid_t pid = 0;
6971 rb_io_t *fptr;
6972 VALUE port;
6973 rb_io_t *write_fptr;
6974 VALUE write_port;
6975 #if defined(HAVE_WORKING_FORK)
6976 int status;
6977 char errmsg[80] = { '\0' };
6978 #endif
6979 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
6980 int state;
6981 struct popen_arg arg;
6982 #endif
6983 int e = 0;
6984 #if defined(HAVE_SPAWNV)
6985 # if defined(HAVE_SPAWNVE)
6986 # define DO_SPAWN(cmd, args, envp) ((args) ? \
6987 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
6988 spawne(P_NOWAIT, (cmd), (envp)))
6989 # else
6990 # define DO_SPAWN(cmd, args, envp) ((args) ? \
6991 spawnv(P_NOWAIT, (cmd), (args)) : \
6992 spawn(P_NOWAIT, (cmd)))
6993 # endif
6994 # if !defined(HAVE_WORKING_FORK)
6995 char **args = NULL;
6996 # if defined(HAVE_SPAWNVE)
6997 char **envp = NULL;
6998 # endif
6999 # endif
7000 #endif
7001 #if !defined(HAVE_WORKING_FORK)
7002 struct rb_execarg sarg, *sargp = &sarg;
7003 #endif
7004 FILE *fp = 0;
7005 int fd = -1;
7006 int write_fd = -1;
7007 #if !defined(HAVE_WORKING_FORK)
7008 const char *cmd = 0;
7010 if (prog)
7011 cmd = StringValueCStr(prog);
7012 #endif
7014 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7015 arg.execarg_obj = execarg_obj;
7016 arg.eargp = eargp;
7017 arg.modef = fmode;
7018 arg.pair[0] = arg.pair[1] = -1;
7019 arg.write_pair[0] = arg.write_pair[1] = -1;
7020 # if !defined(HAVE_WORKING_FORK)
7021 if (eargp && !eargp->use_shell) {
7022 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7024 # endif
7025 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7026 case FMODE_READABLE|FMODE_WRITABLE:
7027 if (rb_pipe(arg.write_pair) < 0)
7028 rb_sys_fail_str(prog);
7029 if (rb_pipe(arg.pair) < 0) {
7030 e = errno;
7031 close(arg.write_pair[0]);
7032 close(arg.write_pair[1]);
7033 rb_syserr_fail_str(e, prog);
7035 if (eargp) {
7036 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7037 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7039 break;
7040 case FMODE_READABLE:
7041 if (rb_pipe(arg.pair) < 0)
7042 rb_sys_fail_str(prog);
7043 if (eargp)
7044 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7045 break;
7046 case FMODE_WRITABLE:
7047 if (rb_pipe(arg.pair) < 0)
7048 rb_sys_fail_str(prog);
7049 if (eargp)
7050 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7051 break;
7052 default:
7053 rb_sys_fail_str(prog);
7055 if (!NIL_P(execarg_obj)) {
7056 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7057 if (state) {
7058 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7059 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7060 if (0 <= arg.pair[0]) close(arg.pair[0]);
7061 if (0 <= arg.pair[1]) close(arg.pair[1]);
7062 rb_execarg_parent_end(execarg_obj);
7063 rb_jump_tag(state);
7066 # if defined(HAVE_WORKING_FORK)
7067 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7068 # else
7069 rb_execarg_run_options(eargp, sargp, NULL, 0);
7070 # if defined(HAVE_SPAWNVE)
7071 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7072 # endif
7073 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7074 /* exec failed */
7075 switch (e = errno) {
7076 case EAGAIN:
7077 # if EWOULDBLOCK != EAGAIN
7078 case EWOULDBLOCK:
7079 # endif
7080 rb_thread_sleep(1);
7081 continue;
7083 break;
7085 if (eargp)
7086 rb_execarg_run_options(sargp, NULL, NULL, 0);
7087 # endif
7088 rb_execarg_parent_end(execarg_obj);
7090 else {
7091 # if defined(HAVE_WORKING_FORK)
7092 pid = rb_call_proc__fork();
7093 if (pid == 0) { /* child */
7094 popen_redirect(&arg);
7095 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7096 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7097 return Qnil;
7099 # else
7100 rb_notimplement();
7101 # endif
7104 /* parent */
7105 if (pid < 0) {
7106 # if defined(HAVE_WORKING_FORK)
7107 e = errno;
7108 # endif
7109 close(arg.pair[0]);
7110 close(arg.pair[1]);
7111 if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) {
7112 close(arg.write_pair[0]);
7113 close(arg.write_pair[1]);
7115 # if defined(HAVE_WORKING_FORK)
7116 if (errmsg[0])
7117 rb_syserr_fail(e, errmsg);
7118 # endif
7119 rb_syserr_fail_str(e, prog);
7121 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7122 close(arg.pair[1]);
7123 fd = arg.pair[0];
7124 close(arg.write_pair[0]);
7125 write_fd = arg.write_pair[1];
7127 else if (fmode & FMODE_READABLE) {
7128 close(arg.pair[1]);
7129 fd = arg.pair[0];
7131 else {
7132 close(arg.pair[0]);
7133 fd = arg.pair[1];
7135 #else
7136 cmd = rb_execarg_commandline(eargp, &prog);
7137 if (!NIL_P(execarg_obj)) {
7138 rb_execarg_parent_start(execarg_obj);
7139 rb_execarg_run_options(eargp, sargp, NULL, 0);
7141 fp = popen(cmd, modestr);
7142 e = errno;
7143 if (eargp) {
7144 rb_execarg_parent_end(execarg_obj);
7145 rb_execarg_run_options(sargp, NULL, NULL, 0);
7147 if (!fp) rb_syserr_fail_path(e, prog);
7148 fd = fileno(fp);
7149 #endif
7151 port = io_alloc(rb_cIO);
7152 MakeOpenFile(port, fptr);
7153 fptr->fd = fd;
7154 fptr->stdio_file = fp;
7155 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7156 if (convconfig) {
7157 fptr->encs = *convconfig;
7158 #if RUBY_CRLF_ENVIRONMENT
7159 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
7160 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7162 #endif
7164 else {
7165 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7166 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7168 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7169 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7170 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7172 #endif
7174 fptr->pid = pid;
7176 if (0 <= write_fd) {
7177 write_port = io_alloc(rb_cIO);
7178 MakeOpenFile(write_port, write_fptr);
7179 write_fptr->fd = write_fd;
7180 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7181 fptr->mode &= ~FMODE_WRITABLE;
7182 fptr->tied_io_for_writing = write_port;
7183 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7186 #if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7187 fptr->finalize = pipe_finalize;
7188 pipe_add_fptr(fptr);
7189 #endif
7190 return port;
7192 #else
7193 static VALUE
7194 pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7195 const convconfig_t *convconfig)
7197 rb_raise(rb_eNotImpError, "popen() is not available");
7199 #endif
7201 static int
7202 is_popen_fork(VALUE prog)
7204 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7205 #if !defined(HAVE_WORKING_FORK)
7206 rb_raise(rb_eNotImpError,
7207 "fork() function is unimplemented on this machine");
7208 #else
7209 return TRUE;
7210 #endif
7212 return FALSE;
7215 static VALUE
7216 pipe_open_s(VALUE prog, const char *modestr, int fmode,
7217 const convconfig_t *convconfig)
7219 int argc = 1;
7220 VALUE *argv = &prog;
7221 VALUE execarg_obj = Qnil;
7223 if (!is_popen_fork(prog))
7224 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7225 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7228 static VALUE
7229 pipe_close(VALUE io)
7231 rb_io_t *fptr = io_close_fptr(io);
7232 if (fptr) {
7233 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7235 return Qnil;
7238 static VALUE popen_finish(VALUE port, VALUE klass);
7241 * call-seq:
7242 * IO.popen([env,] cmd, mode="r" [, opt]) -> io
7243 * IO.popen([env,] cmd, mode="r" [, opt]) {|io| block } -> obj
7245 * Runs the specified command as a subprocess; the subprocess's
7246 * standard input and output will be connected to the returned
7247 * IO object.
7249 * The PID of the started process can be obtained by IO#pid method.
7251 * _cmd_ is a string or an array as follows.
7253 * cmd:
7254 * "-" : fork
7255 * commandline : command line string which is passed to a shell
7256 * [env, cmdname, arg1, ..., opts] : command name and zero or more arguments (no shell)
7257 * [env, [cmdname, argv0], arg1, ..., opts] : command name, argv[0] and zero or more arguments (no shell)
7258 * (env and opts are optional.)
7260 * If _cmd_ is a +String+ ``<code>-</code>'',
7261 * then a new instance of Ruby is started as the subprocess.
7263 * If <i>cmd</i> is an +Array+ of +String+,
7264 * then it will be used as the subprocess's +argv+ bypassing a shell.
7265 * The array can contain a hash at first for environments and
7266 * a hash at last for options similar to #spawn.
7268 * The default mode for the new file object is ``r'',
7269 * but <i>mode</i> may be set to any of the modes listed in the description for class IO.
7270 * The last argument <i>opt</i> qualifies <i>mode</i>.
7272 * # set IO encoding
7273 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7274 * euc_jp_string = nkf_io.read
7277 * # merge standard output and standard error using
7278 * # spawn option. See the document of Kernel.spawn.
7279 * IO.popen(["ls", "/", :err=>[:child, :out]]) {|ls_io|
7280 * ls_result_with_error = ls_io.read
7283 * # spawn options can be mixed with IO options
7284 * IO.popen(["ls", "/"], :err=>[:child, :out]) {|ls_io|
7285 * ls_result_with_error = ls_io.read
7288 * Raises exceptions which IO.pipe and Kernel.spawn raise.
7290 * If a block is given, Ruby will run the command as a child connected
7291 * to Ruby with a pipe. Ruby's end of the pipe will be passed as a
7292 * parameter to the block.
7293 * At the end of block, Ruby closes the pipe and sets <code>$?</code>.
7294 * In this case IO.popen returns the value of the block.
7296 * If a block is given with a _cmd_ of ``<code>-</code>'',
7297 * the block will be run in two separate processes: once in the parent,
7298 * and once in a child. The parent process will be passed the pipe
7299 * object as a parameter to the block, the child version of the block
7300 * will be passed +nil+, and the child's standard in and
7301 * standard out will be connected to the parent through the pipe. Not
7302 * available on all platforms.
7304 * f = IO.popen("uname")
7305 * p f.readlines
7306 * f.close
7307 * puts "Parent is #{Process.pid}"
7308 * IO.popen("date") {|f| puts f.gets }
7309 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7310 * p $?
7311 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7312 * f.puts "bar"; f.close_write; puts f.gets
7315 * <em>produces:</em>
7317 * ["Linux\n"]
7318 * Parent is 21346
7319 * Thu Jan 15 22:41:19 JST 2009
7320 * 21346 is here, f is #<IO:fd 3>
7321 * 21352 is here, f is nil
7322 * #<Process::Status: pid 21352 exit 0>
7323 * <foo>bar;zot;
7326 static VALUE
7327 rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7329 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7331 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7332 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7333 switch (argc) {
7334 case 2:
7335 pmode = argv[1];
7336 case 1:
7337 pname = argv[0];
7338 break;
7339 default:
7341 int ex = !NIL_P(opt);
7342 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7345 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7348 VALUE
7349 rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7351 const char *modestr;
7352 VALUE tmp, execarg_obj = Qnil;
7353 int oflags, fmode;
7354 convconfig_t convconfig;
7356 tmp = rb_check_array_type(pname);
7357 if (!NIL_P(tmp)) {
7358 long len = RARRAY_LEN(tmp);
7359 #if SIZEOF_LONG > SIZEOF_INT
7360 if (len > INT_MAX) {
7361 rb_raise(rb_eArgError, "too many arguments");
7363 #endif
7364 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7365 RB_GC_GUARD(tmp);
7367 else {
7368 SafeStringValue(pname);
7369 execarg_obj = Qnil;
7370 if (!is_popen_fork(pname))
7371 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7373 if (!NIL_P(execarg_obj)) {
7374 if (!NIL_P(opt))
7375 opt = rb_execarg_extract_options(execarg_obj, opt);
7376 if (!NIL_P(env))
7377 rb_execarg_setenv(execarg_obj, env);
7379 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
7380 modestr = rb_io_oflags_modestr(oflags);
7382 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7385 static VALUE
7386 popen_finish(VALUE port, VALUE klass)
7388 if (NIL_P(port)) {
7389 /* child */
7390 if (rb_block_given_p()) {
7391 rb_yield(Qnil);
7392 rb_io_flush(rb_ractor_stdout());
7393 rb_io_flush(rb_ractor_stderr());
7394 _exit(0);
7396 return Qnil;
7398 RBASIC_SET_CLASS(port, klass);
7399 if (rb_block_given_p()) {
7400 return rb_ensure(rb_yield, port, pipe_close, port);
7402 return port;
7405 static void
7406 rb_scan_open_args(int argc, const VALUE *argv,
7407 VALUE *fname_p, int *oflags_p, int *fmode_p,
7408 convconfig_t *convconfig_p, mode_t *perm_p)
7410 VALUE opt, fname, vmode, vperm;
7411 int oflags, fmode;
7412 mode_t perm;
7414 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
7415 FilePathValue(fname);
7417 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
7419 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
7421 *fname_p = fname;
7422 *oflags_p = oflags;
7423 *fmode_p = fmode;
7424 *perm_p = perm;
7427 static VALUE
7428 rb_open_file(int argc, const VALUE *argv, VALUE io)
7430 VALUE fname;
7431 int oflags, fmode;
7432 convconfig_t convconfig;
7433 mode_t perm;
7435 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
7436 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
7438 return io;
7443 * Document-method: File::open
7445 * call-seq:
7446 * File.open(filename, mode="r" [, opt]) -> file
7447 * File.open(filename [, mode [, perm]] [, opt]) -> file
7448 * File.open(filename, mode="r" [, opt]) {|file| block } -> obj
7449 * File.open(filename [, mode [, perm]] [, opt]) {|file| block } -> obj
7451 * With no associated block, File.open is a synonym for
7452 * File.new. If the optional code block is given, it will
7453 * be passed the opened +file+ as an argument and the File object will
7454 * automatically be closed when the block terminates. The value of the block
7455 * will be returned from File.open.
7457 * If a file is being created, its initial permissions may be set using the
7458 * +perm+ parameter. See File.new for further discussion.
7460 * See IO.new for a description of the +mode+ and +opt+ parameters.
7464 * Document-method: IO::open
7466 * call-seq:
7467 * IO.open(fd, mode="r" [, opt]) -> io
7468 * IO.open(fd, mode="r" [, opt]) {|io| block } -> obj
7470 * With no associated block, IO.open is a synonym for IO.new. If
7471 * the optional code block is given, it will be passed +io+ as an argument,
7472 * and the IO object will automatically be closed when the block terminates.
7473 * In this instance, IO.open returns the value of the block.
7475 * See IO.new for a description of the +fd+, +mode+ and +opt+ parameters.
7478 static VALUE
7479 rb_io_s_open(int argc, VALUE *argv, VALUE klass)
7481 VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
7483 if (rb_block_given_p()) {
7484 return rb_ensure(rb_yield, io, io_close, io);
7487 return io;
7491 * call-seq:
7492 * IO.sysopen(path, [mode, [perm]]) -> integer
7494 * Opens the given path, returning the underlying file descriptor as a
7495 * Integer.
7497 * IO.sysopen("testfile") #=> 3
7500 static VALUE
7501 rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
7503 VALUE fname, vmode, vperm;
7504 VALUE intmode;
7505 int oflags, fd;
7506 mode_t perm;
7508 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
7509 FilePathValue(fname);
7511 if (NIL_P(vmode))
7512 oflags = O_RDONLY;
7513 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
7514 oflags = NUM2INT(intmode);
7515 else {
7516 SafeStringValue(vmode);
7517 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
7519 if (NIL_P(vperm)) perm = 0666;
7520 else perm = NUM2MODET(vperm);
7522 RB_GC_GUARD(fname) = rb_str_new4(fname);
7523 fd = rb_sysopen(fname, oflags, perm);
7524 return INT2NUM(fd);
7527 static VALUE
7528 check_pipe_command(VALUE filename_or_command)
7530 char *s = RSTRING_PTR(filename_or_command);
7531 long l = RSTRING_LEN(filename_or_command);
7532 char *e = s + l;
7533 int chlen;
7535 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
7536 VALUE cmd = rb_str_new(s+chlen, l-chlen);
7537 return cmd;
7539 return Qnil;
7543 * call-seq:
7544 * open(path [, mode [, perm]] [, opt]) -> io or nil
7545 * open(path [, mode [, perm]] [, opt]) {|io| block } -> obj
7547 * Creates an IO object connected to the given stream, file, or subprocess.
7549 * If +path+ does not start with a pipe character (<code>|</code>), treat it
7550 * as the name of a file to open using the specified mode (defaulting to
7551 * "r").
7553 * The +mode+ is either a string or an integer. If it is an integer, it
7554 * must be bitwise-or of open(2) flags, such as File::RDWR or File::EXCL. If
7555 * it is a string, it is either "fmode", "fmode:ext_enc", or
7556 * "fmode:ext_enc:int_enc".
7558 * See the documentation of IO.new for full documentation of the +mode+ string
7559 * directives.
7561 * If a file is being created, its initial permissions may be set using the
7562 * +perm+ parameter. See File.new and the open(2) and chmod(2) man pages for
7563 * a description of permissions.
7565 * If a block is specified, it will be invoked with the IO object as a
7566 * parameter, and the IO will be automatically closed when the block
7567 * terminates. The call returns the value of the block.
7569 * If +path+ starts with a pipe character (<code>"|"</code>), a subprocess is
7570 * created, connected to the caller by a pair of pipes. The returned IO
7571 * object may be used to write to the standard input and read from the
7572 * standard output of this subprocess.
7574 * If the command following the pipe is a single minus sign
7575 * (<code>"|-"</code>), Ruby forks, and this subprocess is connected to the
7576 * parent. If the command is not <code>"-"</code>, the subprocess runs the
7577 * command. Note that the command may be processed by shell if it contains
7578 * shell metacharacters.
7580 * When the subprocess is Ruby (opened via <code>"|-"</code>), the +open+
7581 * call returns +nil+. If a block is associated with the open call, that
7582 * block will run twice --- once in the parent and once in the child.
7584 * The block parameter will be an IO object in the parent and +nil+ in the
7585 * child. The parent's +IO+ object will be connected to the child's $stdin
7586 * and $stdout. The subprocess will be terminated at the end of the block.
7588 * === Examples
7590 * Reading from "testfile":
7592 * open("testfile") do |f|
7593 * print f.gets
7594 * end
7596 * Produces:
7598 * This is line one
7600 * Open a subprocess and read its output:
7602 * cmd = open("|date")
7603 * print cmd.gets
7604 * cmd.close
7606 * Produces:
7608 * Wed Apr 9 08:56:31 CDT 2003
7610 * Open a subprocess running the same Ruby program:
7612 * f = open("|-", "w+")
7613 * if f.nil?
7614 * puts "in Child"
7615 * exit
7616 * else
7617 * puts "Got: #{f.gets}"
7618 * end
7620 * Produces:
7622 * Got: in Child
7624 * Open a subprocess using a block to receive the IO object:
7626 * open "|-" do |f|
7627 * if f then
7628 * # parent process
7629 * puts "Got: #{f.gets}"
7630 * else
7631 * # child process
7632 * puts "in Child"
7633 * end
7634 * end
7636 * Produces:
7638 * Got: in Child
7641 static VALUE
7642 rb_f_open(int argc, VALUE *argv, VALUE _)
7644 ID to_open = 0;
7645 int redirect = FALSE;
7647 if (argc >= 1) {
7648 CONST_ID(to_open, "to_open");
7649 if (rb_respond_to(argv[0], to_open)) {
7650 redirect = TRUE;
7652 else {
7653 VALUE tmp = argv[0];
7654 FilePathValue(tmp);
7655 if (NIL_P(tmp)) {
7656 redirect = TRUE;
7658 else {
7659 VALUE cmd = check_pipe_command(tmp);
7660 if (!NIL_P(cmd)) {
7661 argv[0] = cmd;
7662 return rb_io_s_popen(argc, argv, rb_cIO);
7667 if (redirect) {
7668 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
7670 if (rb_block_given_p()) {
7671 return rb_ensure(rb_yield, io, io_close, io);
7673 return io;
7675 return rb_io_s_open(argc, argv, rb_cFile);
7678 static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const convconfig_t *, mode_t);
7680 static VALUE
7681 rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
7683 int oflags, fmode;
7684 convconfig_t convconfig;
7685 mode_t perm;
7687 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
7688 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
7689 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
7692 static VALUE
7693 rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
7694 const convconfig_t *convconfig, mode_t perm)
7696 VALUE cmd;
7697 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
7698 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
7700 else {
7701 return rb_file_open_generic(io_alloc(klass), filename,
7702 oflags, fmode, convconfig, perm);
7706 static VALUE
7707 io_reopen(VALUE io, VALUE nfile)
7709 rb_io_t *fptr, *orig;
7710 int fd, fd2;
7711 off_t pos = 0;
7713 nfile = rb_io_get_io(nfile);
7714 GetOpenFile(io, fptr);
7715 GetOpenFile(nfile, orig);
7717 if (fptr == orig) return io;
7718 if (IS_PREP_STDIO(fptr)) {
7719 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
7720 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
7721 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
7722 rb_raise(rb_eArgError,
7723 "%s can't change access mode from \"%s\" to \"%s\"",
7724 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
7725 rb_io_fmode_modestr(orig->mode));
7728 if (fptr->mode & FMODE_WRITABLE) {
7729 if (io_fflush(fptr) < 0)
7730 rb_sys_fail_on_write(fptr);
7732 else {
7733 flush_before_seek(fptr);
7735 if (orig->mode & FMODE_READABLE) {
7736 pos = io_tell(orig);
7738 if (orig->mode & FMODE_WRITABLE) {
7739 if (io_fflush(orig) < 0)
7740 rb_sys_fail_on_write(fptr);
7743 /* copy rb_io_t structure */
7744 fptr->mode = orig->mode | (fptr->mode & FMODE_PREP);
7745 fptr->pid = orig->pid;
7746 fptr->lineno = orig->lineno;
7747 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
7748 else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
7749 fptr_copy_finalizer(fptr, orig);
7751 fd = fptr->fd;
7752 fd2 = orig->fd;
7753 if (fd != fd2) {
7754 if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->stdio_file) {
7755 /* need to keep FILE objects of stdin, stdout and stderr */
7756 if (rb_cloexec_dup2(fd2, fd) < 0)
7757 rb_sys_fail_path(orig->pathv);
7758 rb_update_max_fd(fd);
7760 else {
7761 fclose(fptr->stdio_file);
7762 fptr->stdio_file = 0;
7763 fptr->fd = -1;
7764 if (rb_cloexec_dup2(fd2, fd) < 0)
7765 rb_sys_fail_path(orig->pathv);
7766 rb_update_max_fd(fd);
7767 fptr->fd = fd;
7769 rb_thread_fd_close(fd);
7770 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
7771 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
7772 rb_sys_fail_path(fptr->pathv);
7774 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
7775 rb_sys_fail_path(orig->pathv);
7780 if (fptr->mode & FMODE_BINMODE) {
7781 rb_io_binmode(io);
7784 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
7785 return io;
7788 #ifdef _WIN32
7789 int rb_freopen(VALUE fname, const char *mode, FILE *fp);
7790 #else
7791 static int
7792 rb_freopen(VALUE fname, const char *mode, FILE *fp)
7794 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
7795 RB_GC_GUARD(fname);
7796 return errno;
7798 return 0;
7800 #endif
7803 * call-seq:
7804 * ios.reopen(other_IO) -> ios
7805 * ios.reopen(path, mode [, opt]) -> ios
7807 * Reassociates <em>ios</em> with the I/O stream given in
7808 * <i>other_IO</i> or to a new stream opened on <i>path</i>. This may
7809 * dynamically change the actual class of this stream.
7810 * The +mode+ and +opt+ parameters accept the same values as IO.open.
7812 * f1 = File.new("testfile")
7813 * f2 = File.new("testfile")
7814 * f2.readlines[0] #=> "This is line one\n"
7815 * f2.reopen(f1) #=> #<File:testfile>
7816 * f2.readlines[0] #=> "This is line one\n"
7819 static VALUE
7820 rb_io_reopen(int argc, VALUE *argv, VALUE file)
7822 VALUE fname, nmode, opt;
7823 int oflags;
7824 rb_io_t *fptr;
7826 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
7827 VALUE tmp = rb_io_check_io(fname);
7828 if (!NIL_P(tmp)) {
7829 return io_reopen(file, tmp);
7833 FilePathValue(fname);
7834 rb_io_taint_check(file);
7835 fptr = RFILE(file)->fptr;
7836 if (!fptr) {
7837 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
7840 if (!NIL_P(nmode) || !NIL_P(opt)) {
7841 int fmode;
7842 convconfig_t convconfig;
7844 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
7845 if (IS_PREP_STDIO(fptr) &&
7846 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
7847 (fptr->mode & FMODE_READWRITE)) {
7848 rb_raise(rb_eArgError,
7849 "%s can't change access mode from \"%s\" to \"%s\"",
7850 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
7851 rb_io_fmode_modestr(fmode));
7853 fptr->mode = fmode;
7854 fptr->encs = convconfig;
7856 else {
7857 oflags = rb_io_fmode_oflags(fptr->mode);
7860 fptr->pathv = fname;
7861 if (fptr->fd < 0) {
7862 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
7863 fptr->stdio_file = 0;
7864 return file;
7867 if (fptr->mode & FMODE_WRITABLE) {
7868 if (io_fflush(fptr) < 0)
7869 rb_sys_fail_on_write(fptr);
7871 fptr->rbuf.off = fptr->rbuf.len = 0;
7873 if (fptr->stdio_file) {
7874 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
7875 rb_io_oflags_modestr(oflags),
7876 fptr->stdio_file);
7877 if (e) rb_syserr_fail_path(e, fptr->pathv);
7878 fptr->fd = fileno(fptr->stdio_file);
7879 rb_fd_fix_cloexec(fptr->fd);
7880 #ifdef USE_SETVBUF
7881 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
7882 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
7883 #endif
7884 if (fptr->stdio_file == stderr) {
7885 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
7886 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
7888 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
7889 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
7890 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
7893 else {
7894 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
7895 int err = 0;
7896 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
7897 err = errno;
7898 (void)close(tmpfd);
7899 if (err) {
7900 rb_syserr_fail_path(err, fptr->pathv);
7904 return file;
7907 /* :nodoc: */
7908 static VALUE
7909 rb_io_init_copy(VALUE dest, VALUE io)
7911 rb_io_t *fptr, *orig;
7912 int fd;
7913 VALUE write_io;
7914 off_t pos;
7916 io = rb_io_get_io(io);
7917 if (!OBJ_INIT_COPY(dest, io)) return dest;
7918 GetOpenFile(io, orig);
7919 MakeOpenFile(dest, fptr);
7921 rb_io_flush(io);
7923 /* copy rb_io_t structure */
7924 fptr->mode = orig->mode & ~FMODE_PREP;
7925 fptr->encs = orig->encs;
7926 fptr->pid = orig->pid;
7927 fptr->lineno = orig->lineno;
7928 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
7929 fptr_copy_finalizer(fptr, orig);
7931 fd = ruby_dup(orig->fd);
7932 fptr->fd = fd;
7933 pos = io_tell(orig);
7934 if (0 <= pos)
7935 io_seek(fptr, pos, SEEK_SET);
7936 if (fptr->mode & FMODE_BINMODE) {
7937 rb_io_binmode(dest);
7940 write_io = GetWriteIO(io);
7941 if (io != write_io) {
7942 write_io = rb_obj_dup(write_io);
7943 fptr->tied_io_for_writing = write_io;
7944 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
7947 return dest;
7951 * call-seq:
7952 * ios.printf(format_string [, obj, ...]) -> nil
7954 * Formats and writes to <em>ios</em>, converting parameters under
7955 * control of the format string. See Kernel#sprintf for details.
7958 VALUE
7959 rb_io_printf(int argc, const VALUE *argv, VALUE out)
7961 rb_io_write(out, rb_f_sprintf(argc, argv));
7962 return Qnil;
7966 * call-seq:
7967 * printf(io, string [, obj ... ]) -> nil
7968 * printf(string [, obj ... ]) -> nil
7970 * Equivalent to:
7971 * io.write(sprintf(string, obj, ...))
7972 * or
7973 * $stdout.write(sprintf(string, obj, ...))
7976 static VALUE
7977 rb_f_printf(int argc, VALUE *argv, VALUE _)
7979 VALUE out;
7981 if (argc == 0) return Qnil;
7982 if (RB_TYPE_P(argv[0], T_STRING)) {
7983 out = rb_ractor_stdout();
7985 else {
7986 out = argv[0];
7987 argv++;
7988 argc--;
7990 rb_io_write(out, rb_f_sprintf(argc, argv));
7992 return Qnil;
7995 static void
7996 deprecated_str_setter(VALUE val, ID id, VALUE *var)
7998 rb_str_setter(val, id, &val);
7999 if (!NIL_P(val)) {
8000 rb_warn_deprecated("`%s'", NULL, rb_id2name(id));
8002 *var = val;
8006 * call-seq:
8007 * ios.print -> nil
8008 * ios.print(obj, ...) -> nil
8010 * Writes the given object(s) to <em>ios</em>. Returns +nil+.
8012 * The stream must be opened for writing.
8013 * Each given object that isn't a string will be converted by calling
8014 * its <code>to_s</code> method.
8015 * When called without arguments, prints the contents of <code>$_</code>.
8017 * If the output field separator (<code>$,</code>) is not +nil+,
8018 * it is inserted between objects.
8019 * If the output record separator (<code>$\\</code>) is not +nil+,
8020 * it is appended to the output.
8022 * $stdout.print("This is ", 100, " percent.\n")
8024 * <em>produces:</em>
8026 * This is 100 percent.
8029 VALUE
8030 rb_io_print(int argc, const VALUE *argv, VALUE out)
8032 int i;
8033 VALUE line;
8035 /* if no argument given, print `$_' */
8036 if (argc == 0) {
8037 argc = 1;
8038 line = rb_lastline_get();
8039 argv = &line;
8041 if (argc > 1 && !NIL_P(rb_output_fs)) {
8042 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8044 for (i=0; i<argc; i++) {
8045 if (!NIL_P(rb_output_fs) && i>0) {
8046 rb_io_write(out, rb_output_fs);
8048 rb_io_write(out, argv[i]);
8050 if (argc > 0 && !NIL_P(rb_output_rs)) {
8051 rb_io_write(out, rb_output_rs);
8054 return Qnil;
8058 * call-seq:
8059 * print(obj, ...) -> nil
8061 * Prints each object in turn to <code>$stdout</code>. If the output
8062 * field separator (<code>$,</code>) is not +nil+, its
8063 * contents will appear between each field. If the output record
8064 * separator (<code>$\\</code>) is not +nil+, it will be
8065 * appended to the output. If no arguments are given, prints
8066 * <code>$_</code>. Objects that aren't strings will be converted by
8067 * calling their <code>to_s</code> method.
8069 * print "cat", [1,2,3], 99, "\n"
8070 * $, = ", "
8071 * $\ = "\n"
8072 * print "cat", [1,2,3], 99
8074 * <em>produces:</em>
8076 * cat12399
8077 * cat, 1, 2, 3, 99
8080 static VALUE
8081 rb_f_print(int argc, const VALUE *argv, VALUE _)
8083 rb_io_print(argc, argv, rb_ractor_stdout());
8084 return Qnil;
8088 * call-seq:
8089 * ios.putc(obj) -> obj
8091 * If <i>obj</i> is Numeric, write the character whose code is the
8092 * least-significant byte of <i>obj</i>. If <i>obj</i> is String,
8093 * write the first character of <i>obj</i> to <em>ios</em>. Otherwise,
8094 * raise TypeError.
8096 * $stdout.putc "A"
8097 * $stdout.putc 65
8099 * <em>produces:</em>
8101 * AA
8104 static VALUE
8105 rb_io_putc(VALUE io, VALUE ch)
8107 VALUE str;
8108 if (RB_TYPE_P(ch, T_STRING)) {
8109 str = rb_str_substr(ch, 0, 1);
8111 else {
8112 char c = NUM2CHR(ch);
8113 str = rb_str_new(&c, 1);
8115 rb_io_write(io, str);
8116 return ch;
8119 #define forward(obj, id, argc, argv) \
8120 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8121 #define forward_public(obj, id, argc, argv) \
8122 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8123 #define forward_current(id, argc, argv) \
8124 forward_public(ARGF.current_file, id, argc, argv)
8127 * call-seq:
8128 * putc(int) -> int
8130 * Equivalent to:
8132 * $stdout.putc(int)
8134 * Refer to the documentation for IO#putc for important information regarding
8135 * multi-byte characters.
8138 static VALUE
8139 rb_f_putc(VALUE recv, VALUE ch)
8141 VALUE r_stdout = rb_ractor_stdout();
8142 if (recv == r_stdout) {
8143 return rb_io_putc(recv, ch);
8145 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8150 rb_str_end_with_asciichar(VALUE str, int c)
8152 long len = RSTRING_LEN(str);
8153 const char *ptr = RSTRING_PTR(str);
8154 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8155 int n;
8157 if (len == 0) return 0;
8158 if ((n = rb_enc_mbminlen(enc)) == 1) {
8159 return ptr[len - 1] == c;
8161 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8164 static VALUE
8165 io_puts_ary(VALUE ary, VALUE out, int recur)
8167 VALUE tmp;
8168 long i;
8170 if (recur) {
8171 tmp = rb_str_new2("[...]");
8172 rb_io_puts(1, &tmp, out);
8173 return Qtrue;
8175 ary = rb_check_array_type(ary);
8176 if (NIL_P(ary)) return Qfalse;
8177 for (i=0; i<RARRAY_LEN(ary); i++) {
8178 tmp = RARRAY_AREF(ary, i);
8179 rb_io_puts(1, &tmp, out);
8181 return Qtrue;
8185 * call-seq:
8186 * ios.puts(obj, ...) -> nil
8188 * Writes the given object(s) to <em>ios</em>.
8189 * Writes a newline after any that do not already end
8190 * with a newline sequence. Returns +nil+.
8192 * The stream must be opened for writing.
8193 * If called with an array argument, writes each element on a new line.
8194 * Each given object that isn't a string or array will be converted
8195 * by calling its +to_s+ method.
8196 * If called without arguments, outputs a single newline.
8198 * $stdout.puts("this", "is", ["a", "test"])
8200 * <em>produces:</em>
8202 * this
8203 * is
8205 * test
8207 * Note that +puts+ always uses newlines and is not affected
8208 * by the output record separator (<code>$\\</code>).
8211 VALUE
8212 rb_io_puts(int argc, const VALUE *argv, VALUE out)
8214 int i, n;
8215 VALUE line, args[2];
8217 /* if no argument given, print newline. */
8218 if (argc == 0) {
8219 rb_io_write(out, rb_default_rs);
8220 return Qnil;
8222 for (i=0; i<argc; i++) {
8223 if (RB_TYPE_P(argv[i], T_STRING)) {
8224 line = argv[i];
8225 goto string;
8227 if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8228 continue;
8230 line = rb_obj_as_string(argv[i]);
8231 string:
8232 n = 0;
8233 args[n++] = line;
8234 if (RSTRING_LEN(line) == 0 ||
8235 !rb_str_end_with_asciichar(line, '\n')) {
8236 args[n++] = rb_default_rs;
8238 rb_io_writev(out, n, args);
8241 return Qnil;
8245 * call-seq:
8246 * puts(obj, ...) -> nil
8248 * Equivalent to
8250 * $stdout.puts(obj, ...)
8253 static VALUE
8254 rb_f_puts(int argc, VALUE *argv, VALUE recv)
8256 VALUE r_stdout = rb_ractor_stdout();
8257 if (recv == r_stdout) {
8258 return rb_io_puts(argc, argv, recv);
8260 return forward(r_stdout, rb_intern("puts"), argc, argv);
8263 static VALUE
8264 rb_p_write(VALUE str)
8266 VALUE args[2];
8267 args[0] = str;
8268 args[1] = rb_default_rs;
8269 VALUE r_stdout = rb_ractor_stdout();
8270 if (RB_TYPE_P(r_stdout, T_FILE) &&
8271 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
8272 io_writev(2, args, r_stdout);
8274 else {
8275 rb_io_writev(r_stdout, 2, args);
8277 return Qnil;
8280 void
8281 rb_p(VALUE obj) /* for debug print within C code */
8283 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
8286 static VALUE
8287 rb_p_result(int argc, const VALUE *argv)
8289 VALUE ret = Qnil;
8291 if (argc == 1) {
8292 ret = argv[0];
8294 else if (argc > 1) {
8295 ret = rb_ary_new4(argc, argv);
8297 VALUE r_stdout = rb_ractor_stdout();
8298 if (RB_TYPE_P(r_stdout, T_FILE)) {
8299 rb_io_flush(r_stdout);
8301 return ret;
8305 * call-seq:
8306 * p(obj) -> obj
8307 * p(obj1, obj2, ...) -> [obj, ...]
8308 * p() -> nil
8310 * For each object, directly writes _obj_.+inspect+ followed by a
8311 * newline to the program's standard output.
8313 * S = Struct.new(:name, :state)
8314 * s = S['dave', 'TX']
8315 * p s
8317 * <em>produces:</em>
8319 * #<S name="dave", state="TX">
8322 static VALUE
8323 rb_f_p(int argc, VALUE *argv, VALUE self)
8325 int i;
8326 for (i=0; i<argc; i++) {
8327 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
8328 rb_uninterruptible(rb_p_write, inspected);
8330 return rb_p_result(argc, argv);
8334 * call-seq:
8335 * obj.display(port=$>) -> nil
8337 * Prints <i>obj</i> on the given port (default <code>$></code>).
8338 * Equivalent to:
8340 * def display(port=$>)
8341 * port.write self
8342 * nil
8343 * end
8345 * For example:
8347 * 1.display
8348 * "cat".display
8349 * [ 4, 5, 6 ].display
8350 * puts
8352 * <em>produces:</em>
8354 * 1cat[4, 5, 6]
8357 static VALUE
8358 rb_obj_display(int argc, VALUE *argv, VALUE self)
8360 VALUE out;
8362 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
8363 rb_io_write(out, self);
8365 return Qnil;
8368 static int
8369 rb_stderr_to_original_p(VALUE err)
8371 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
8374 void
8375 rb_write_error2(const char *mesg, long len)
8377 VALUE out = rb_ractor_stderr();
8378 if (rb_stderr_to_original_p(out)) {
8379 #ifdef _WIN32
8380 if (isatty(fileno(stderr))) {
8381 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
8383 #endif
8384 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
8385 /* failed to write to stderr, what can we do? */
8386 return;
8389 else {
8390 rb_io_write(out, rb_str_new(mesg, len));
8394 void
8395 rb_write_error(const char *mesg)
8397 rb_write_error2(mesg, strlen(mesg));
8400 void
8401 rb_write_error_str(VALUE mesg)
8403 VALUE out = rb_ractor_stderr();
8404 /* a stopgap measure for the time being */
8405 if (rb_stderr_to_original_p(out)) {
8406 size_t len = (size_t)RSTRING_LEN(mesg);
8407 #ifdef _WIN32
8408 if (isatty(fileno(stderr))) {
8409 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
8411 #endif
8412 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
8413 RB_GC_GUARD(mesg);
8414 return;
8417 else {
8418 /* may unlock GVL, and */
8419 rb_io_write(out, mesg);
8424 rb_stderr_tty_p(void)
8426 if (rb_stderr_to_original_p(rb_ractor_stderr()))
8427 return isatty(fileno(stderr));
8428 return 0;
8431 static void
8432 must_respond_to(ID mid, VALUE val, ID id)
8434 if (!rb_respond_to(val, mid)) {
8435 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
8436 rb_id2str(id), rb_id2str(mid),
8437 rb_obj_class(val));
8441 static void
8442 stdin_setter(VALUE val, ID id, VALUE *ptr)
8444 rb_ractor_stdin_set(val);
8447 static VALUE
8448 stdin_getter(ID id, VALUE *ptr)
8450 return rb_ractor_stdin();
8453 static void
8454 stdout_setter(VALUE val, ID id, VALUE *ptr)
8456 must_respond_to(id_write, val, id);
8457 rb_ractor_stdout_set(val);
8460 static VALUE
8461 stdout_getter(ID id, VALUE *ptr)
8463 return rb_ractor_stdout();
8466 static void
8467 stderr_setter(VALUE val, ID id, VALUE *ptr)
8469 must_respond_to(id_write, val, id);
8470 rb_ractor_stderr_set(val);
8473 static VALUE
8474 stderr_getter(ID id, VALUE *ptr)
8476 return rb_ractor_stderr();
8479 static VALUE
8480 prep_io(int fd, int fmode, VALUE klass, const char *path)
8482 rb_io_t *fp;
8483 VALUE io = io_alloc(klass);
8485 MakeOpenFile(io, fp);
8486 fp->self = io;
8487 fp->fd = fd;
8488 fp->mode = fmode;
8489 if (!io_check_tty(fp)) {
8490 #ifdef __CYGWIN__
8491 fp->mode |= FMODE_BINMODE;
8492 setmode(fd, O_BINARY);
8493 #endif
8495 if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
8496 rb_update_max_fd(fd);
8498 return io;
8501 VALUE
8502 rb_io_fdopen(int fd, int oflags, const char *path)
8504 VALUE klass = rb_cIO;
8506 if (path && strcmp(path, "-")) klass = rb_cFile;
8507 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
8510 static VALUE
8511 prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
8513 rb_io_t *fptr;
8514 VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
8516 GetOpenFile(io, fptr);
8517 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
8518 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
8519 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
8520 if (fmode & FMODE_READABLE) {
8521 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
8523 #endif
8524 fptr->stdio_file = f;
8526 return io;
8529 VALUE
8530 rb_io_prep_stdin(void)
8532 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
8535 VALUE
8536 rb_io_prep_stdout(void)
8538 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
8541 VALUE
8542 rb_io_prep_stderr(void)
8544 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
8547 FILE *
8548 rb_io_stdio_file(rb_io_t *fptr)
8550 if (!fptr->stdio_file) {
8551 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
8552 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
8554 return fptr->stdio_file;
8557 static inline void
8558 rb_io_buffer_init(rb_io_buffer_t *buf)
8560 buf->ptr = NULL;
8561 buf->off = 0;
8562 buf->len = 0;
8563 buf->capa = 0;
8566 static inline rb_io_t *
8567 rb_io_fptr_new(void)
8569 rb_io_t *fp = ALLOC(rb_io_t);
8570 fp->self = Qnil;
8571 fp->fd = -1;
8572 fp->stdio_file = NULL;
8573 fp->mode = 0;
8574 fp->pid = 0;
8575 fp->lineno = 0;
8576 fp->pathv = Qnil;
8577 fp->finalize = 0;
8578 rb_io_buffer_init(&fp->wbuf);
8579 rb_io_buffer_init(&fp->rbuf);
8580 rb_io_buffer_init(&fp->cbuf);
8581 fp->readconv = NULL;
8582 fp->writeconv = NULL;
8583 fp->writeconv_asciicompat = Qnil;
8584 fp->writeconv_pre_ecflags = 0;
8585 fp->writeconv_pre_ecopts = Qnil;
8586 fp->writeconv_initialized = 0;
8587 fp->tied_io_for_writing = 0;
8588 fp->encs.enc = NULL;
8589 fp->encs.enc2 = NULL;
8590 fp->encs.ecflags = 0;
8591 fp->encs.ecopts = Qnil;
8592 fp->write_lock = 0;
8593 return fp;
8596 rb_io_t *
8597 rb_io_make_open_file(VALUE obj)
8599 rb_io_t *fp = 0;
8601 Check_Type(obj, T_FILE);
8602 if (RFILE(obj)->fptr) {
8603 rb_io_close(obj);
8604 rb_io_fptr_finalize(RFILE(obj)->fptr);
8605 RFILE(obj)->fptr = 0;
8607 fp = rb_io_fptr_new();
8608 fp->self = obj;
8609 RFILE(obj)->fptr = fp;
8610 return fp;
8614 * call-seq:
8615 * IO.new(fd [, mode] [, opt]) -> io
8617 * Returns a new IO object (a stream) for the given integer file descriptor
8618 * +fd+ and +mode+ string. +opt+ may be used to specify parts of +mode+ in a
8619 * more readable fashion. See also IO.sysopen and IO.for_fd.
8621 * IO.new is called by various File and IO opening methods such as IO::open,
8622 * Kernel#open, and File::open.
8624 * === Open Mode
8626 * When +mode+ is an integer it must be combination of the modes defined in
8627 * File::Constants (+File::RDONLY+, <code>File::WRONLY|File::CREAT</code>).
8628 * See the open(2) man page for more information.
8630 * When +mode+ is a string it must be in one of the following forms:
8632 * fmode
8633 * fmode ":" ext_enc
8634 * fmode ":" ext_enc ":" int_enc
8635 * fmode ":" "BOM|UTF-*"
8637 * +fmode+ is an IO open mode string, +ext_enc+ is the external encoding for
8638 * the IO and +int_enc+ is the internal encoding.
8640 * ==== IO Open Mode
8642 * Ruby allows the following open modes:
8644 * "r" Read-only, starts at beginning of file (default mode).
8646 * "r+" Read-write, starts at beginning of file.
8648 * "w" Write-only, truncates existing file
8649 * to zero length or creates a new file for writing.
8651 * "w+" Read-write, truncates existing file to zero length
8652 * or creates a new file for reading and writing.
8654 * "a" Write-only, each write call appends data at end of file.
8655 * Creates a new file for writing if file does not exist.
8657 * "a+" Read-write, each write call appends data at end of file.
8658 * Creates a new file for reading and writing if file does
8659 * not exist.
8661 * The following modes must be used separately, and along with one or more of
8662 * the modes seen above.
8664 * "b" Binary file mode
8665 * Suppresses EOL <-> CRLF conversion on Windows. And
8666 * sets external encoding to ASCII-8BIT unless explicitly
8667 * specified.
8669 * "t" Text file mode
8671 * The exclusive access mode ("x") can be used together with "w" to ensure
8672 * the file is created. Errno::EEXIST is raised when it already exists.
8673 * It may not be supported with all kinds of streams (e.g. pipes).
8675 * When the open mode of original IO is read only, the mode cannot be
8676 * changed to be writable. Similarly, the open mode cannot be changed from
8677 * write only to readable.
8679 * When such a change is attempted the error is raised in different locations
8680 * according to the platform.
8682 * === IO Encoding
8684 * When +ext_enc+ is specified, strings read will be tagged by the encoding
8685 * when reading, and strings output will be converted to the specified
8686 * encoding when writing.
8688 * When +ext_enc+ and +int_enc+ are specified read strings will be converted
8689 * from +ext_enc+ to +int_enc+ upon input, and written strings will be
8690 * converted from +int_enc+ to +ext_enc+ upon output. See Encoding for
8691 * further details of transcoding on input and output.
8693 * If "BOM|UTF-8", "BOM|UTF-16LE" or "BOM|UTF16-BE" are used, Ruby checks for
8694 * a Unicode BOM in the input document to help determine the encoding. For
8695 * UTF-16 encodings the file open mode must be binary. When present, the BOM
8696 * is stripped and the external encoding from the BOM is used. When the BOM
8697 * is missing the given Unicode encoding is used as +ext_enc+. (The BOM-set
8698 * encoding option is case insensitive, so "bom|utf-8" is also valid.)
8700 * === Options
8702 * +opt+ can be used instead of +mode+ for improved readability. The
8703 * following keys are supported:
8705 * :mode ::
8706 * Same as +mode+ parameter
8708 * :flags ::
8709 * Specifies file open flags as integer.
8710 * If +mode+ parameter is given, this parameter will be bitwise-ORed.
8712 * :\external_encoding ::
8713 * External encoding for the IO.
8715 * :\internal_encoding ::
8716 * Internal encoding for the IO. "-" is a synonym for the default internal
8717 * encoding.
8719 * If the value is +nil+ no conversion occurs.
8721 * :encoding ::
8722 * Specifies external and internal encodings as "extern:intern".
8724 * :textmode ::
8725 * If the value is truth value, same as "t" in argument +mode+.
8727 * :binmode ::
8728 * If the value is truth value, same as "b" in argument +mode+.
8730 * :autoclose ::
8731 * If the value is +false+, the +fd+ will be kept open after this IO
8732 * instance gets finalized.
8734 * Also, +opt+ can have same keys in String#encode for controlling conversion
8735 * between the external encoding and the internal encoding.
8737 * === Example 1
8739 * fd = IO.sysopen("/dev/tty", "w")
8740 * a = IO.new(fd,"w")
8741 * $stderr.puts "Hello"
8742 * a.puts "World"
8744 * Produces:
8746 * Hello
8747 * World
8749 * === Example 2
8751 * require 'fcntl'
8753 * fd = STDERR.fcntl(Fcntl::F_DUPFD)
8754 * io = IO.new(fd, mode: 'w:UTF-16LE', cr_newline: true)
8755 * io.puts "Hello, World!"
8757 * fd = STDERR.fcntl(Fcntl::F_DUPFD)
8758 * io = IO.new(fd, mode: 'w', cr_newline: true,
8759 * external_encoding: Encoding::UTF_16LE)
8760 * io.puts "Hello, World!"
8762 * Both of above print "Hello, World!" in UTF-16LE to standard error output
8763 * with converting EOL generated by #puts to CR.
8766 static VALUE
8767 rb_io_initialize(int argc, VALUE *argv, VALUE io)
8769 VALUE fnum, vmode;
8770 rb_io_t *fp;
8771 int fd, fmode, oflags = O_RDONLY;
8772 convconfig_t convconfig;
8773 VALUE opt;
8774 #if defined(HAVE_FCNTL) && defined(F_GETFL)
8775 int ofmode;
8776 #else
8777 struct stat st;
8778 #endif
8781 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
8782 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
8784 fd = NUM2INT(fnum);
8785 if (rb_reserved_fd_p(fd)) {
8786 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
8788 #if defined(HAVE_FCNTL) && defined(F_GETFL)
8789 oflags = fcntl(fd, F_GETFL);
8790 if (oflags == -1) rb_sys_fail(0);
8791 #else
8792 if (fstat(fd, &st) < 0) rb_sys_fail(0);
8793 #endif
8794 rb_update_max_fd(fd);
8795 #if defined(HAVE_FCNTL) && defined(F_GETFL)
8796 ofmode = rb_io_oflags_fmode(oflags);
8797 if (NIL_P(vmode)) {
8798 fmode = ofmode;
8800 else if ((~ofmode & fmode) & FMODE_READWRITE) {
8801 VALUE error = INT2FIX(EINVAL);
8802 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
8804 #endif
8805 if (!NIL_P(opt) && rb_hash_aref(opt, sym_autoclose) == Qfalse) {
8806 fmode |= FMODE_PREP;
8808 MakeOpenFile(io, fp);
8809 fp->self = io;
8810 fp->fd = fd;
8811 fp->mode = fmode;
8812 fp->encs = convconfig;
8813 clear_codeconv(fp);
8814 io_check_tty(fp);
8815 if (fileno(stdin) == fd)
8816 fp->stdio_file = stdin;
8817 else if (fileno(stdout) == fd)
8818 fp->stdio_file = stdout;
8819 else if (fileno(stderr) == fd)
8820 fp->stdio_file = stderr;
8822 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
8823 return io;
8827 * call-seq:
8828 * ios.set_encoding_by_bom -> encoding or nil
8830 * Checks if +ios+ starts with a BOM, and then consumes it and sets
8831 * the external encoding. Returns the result encoding if found, or
8832 * nil. If +ios+ is not binmode or its encoding has been set
8833 * already, an exception will be raised.
8835 * File.write("bom.txt", "\u{FEFF}abc")
8836 * ios = File.open("bom.txt", "rb")
8837 * ios.set_encoding_by_bom #=> #<Encoding:UTF-8>
8839 * File.write("nobom.txt", "abc")
8840 * ios = File.open("nobom.txt", "rb")
8841 * ios.set_encoding_by_bom #=> nil
8844 static VALUE
8845 rb_io_set_encoding_by_bom(VALUE io)
8847 rb_io_t *fptr;
8849 GetOpenFile(io, fptr);
8850 if (!(fptr->mode & FMODE_BINMODE)) {
8851 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
8853 if (fptr->encs.enc2) {
8854 rb_raise(rb_eArgError, "encoding conversion is set");
8856 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
8857 rb_raise(rb_eArgError, "encoding is set to %s already",
8858 rb_enc_name(fptr->encs.enc));
8860 if (!io_set_encoding_by_bom(io)) return Qnil;
8861 return rb_enc_from_encoding(fptr->encs.enc);
8865 * call-seq:
8866 * File.new(filename, mode="r" [, opt]) -> file
8867 * File.new(filename [, mode [, perm]] [, opt]) -> file
8869 * Opens the file named by +filename+ according to the given +mode+ and
8870 * returns a new File object.
8872 * See IO.new for a description of +mode+ and +opt+.
8874 * If a file is being created, permission bits may be given in +perm+. These
8875 * mode and permission bits are platform dependent; on Unix systems, see
8876 * open(2) and chmod(2) man pages for details.
8878 * The new File object is buffered mode (or non-sync mode), unless
8879 * +filename+ is a tty.
8880 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync= about sync mode.
8882 * === Examples
8884 * f = File.new("testfile", "r")
8885 * f = File.new("newfile", "w+")
8886 * f = File.new("newfile", File::CREAT|File::TRUNC|File::RDWR, 0644)
8889 static VALUE
8890 rb_file_initialize(int argc, VALUE *argv, VALUE io)
8892 if (RFILE(io)->fptr) {
8893 rb_raise(rb_eRuntimeError, "reinitializing File");
8895 if (0 < argc && argc < 3) {
8896 VALUE fd = rb_check_to_int(argv[0]);
8898 if (!NIL_P(fd)) {
8899 argv[0] = fd;
8900 return rb_io_initialize(argc, argv, io);
8903 rb_open_file(argc, argv, io);
8905 return io;
8908 /* :nodoc: */
8909 static VALUE
8910 rb_io_s_new(int argc, VALUE *argv, VALUE klass)
8912 if (rb_block_given_p()) {
8913 VALUE cname = rb_obj_as_string(klass);
8915 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
8916 cname, cname);
8918 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
8923 * call-seq:
8924 * IO.for_fd(fd, mode [, opt]) -> io
8926 * Synonym for IO.new.
8930 static VALUE
8931 rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
8933 VALUE io = rb_obj_alloc(klass);
8934 rb_io_initialize(argc, argv, io);
8935 return io;
8939 * call-seq:
8940 * ios.autoclose? -> true or false
8942 * Returns +true+ if the underlying file descriptor of _ios_ will be
8943 * closed automatically at its finalization, otherwise +false+.
8946 static VALUE
8947 rb_io_autoclose_p(VALUE io)
8949 rb_io_t *fptr = RFILE(io)->fptr;
8950 rb_io_check_closed(fptr);
8951 return (fptr->mode & FMODE_PREP) ? Qfalse : Qtrue;
8955 * call-seq:
8956 * io.autoclose = bool -> true or false
8958 * Sets auto-close flag.
8960 * f = open("/dev/null")
8961 * IO.for_fd(f.fileno)
8962 * # ...
8963 * f.gets # may cause Errno::EBADF
8965 * f = open("/dev/null")
8966 * IO.for_fd(f.fileno).autoclose = false
8967 * # ...
8968 * f.gets # won't cause Errno::EBADF
8971 static VALUE
8972 rb_io_set_autoclose(VALUE io, VALUE autoclose)
8974 rb_io_t *fptr;
8975 GetOpenFile(io, fptr);
8976 if (!RTEST(autoclose))
8977 fptr->mode |= FMODE_PREP;
8978 else
8979 fptr->mode &= ~FMODE_PREP;
8980 return autoclose;
8983 static void
8984 argf_mark(void *ptr)
8986 struct argf *p = ptr;
8987 rb_gc_mark(p->filename);
8988 rb_gc_mark(p->current_file);
8989 rb_gc_mark(p->argv);
8990 rb_gc_mark(p->inplace);
8991 rb_gc_mark(p->encs.ecopts);
8994 static size_t
8995 argf_memsize(const void *ptr)
8997 const struct argf *p = ptr;
8998 size_t size = sizeof(*p);
8999 return size;
9002 static const rb_data_type_t argf_type = {
9003 "ARGF",
9004 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9005 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9008 static inline void
9009 argf_init(struct argf *p, VALUE v)
9011 p->filename = Qnil;
9012 p->current_file = Qnil;
9013 p->lineno = 0;
9014 p->argv = v;
9017 static VALUE
9018 argf_alloc(VALUE klass)
9020 struct argf *p;
9021 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9023 argf_init(p, Qnil);
9024 return argf;
9027 #undef rb_argv
9029 /* :nodoc: */
9030 static VALUE
9031 argf_initialize(VALUE argf, VALUE argv)
9033 memset(&ARGF, 0, sizeof(ARGF));
9034 argf_init(&ARGF, argv);
9036 return argf;
9039 /* :nodoc: */
9040 static VALUE
9041 argf_initialize_copy(VALUE argf, VALUE orig)
9043 if (!OBJ_INIT_COPY(argf, orig)) return argf;
9044 ARGF = argf_of(orig);
9045 ARGF.argv = rb_obj_dup(ARGF.argv);
9046 return argf;
9050 * call-seq:
9051 * ARGF.lineno = integer -> integer
9053 * Sets the line number of +ARGF+ as a whole to the given +Integer+.
9055 * +ARGF+ sets the line number automatically as you read data, so normally
9056 * you will not need to set it explicitly. To access the current line number
9057 * use +ARGF.lineno+.
9059 * For example:
9061 * ARGF.lineno #=> 0
9062 * ARGF.readline #=> "This is line 1\n"
9063 * ARGF.lineno #=> 1
9064 * ARGF.lineno = 0 #=> 0
9065 * ARGF.lineno #=> 0
9067 static VALUE
9068 argf_set_lineno(VALUE argf, VALUE val)
9070 ARGF.lineno = NUM2INT(val);
9071 ARGF.last_lineno = ARGF.lineno;
9072 return Qnil;
9076 * call-seq:
9077 * ARGF.lineno -> integer
9079 * Returns the current line number of ARGF as a whole. This value
9080 * can be set manually with +ARGF.lineno=+.
9082 * For example:
9084 * ARGF.lineno #=> 0
9085 * ARGF.readline #=> "This is line 1\n"
9086 * ARGF.lineno #=> 1
9088 static VALUE
9089 argf_lineno(VALUE argf)
9091 return INT2FIX(ARGF.lineno);
9094 static VALUE
9095 argf_forward(int argc, VALUE *argv, VALUE argf)
9097 return forward_current(rb_frame_this_func(), argc, argv);
9100 #define next_argv() argf_next_argv(argf)
9101 #define ARGF_GENERIC_INPUT_P() \
9102 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
9103 #define ARGF_FORWARD(argc, argv) do {\
9104 if (ARGF_GENERIC_INPUT_P())\
9105 return argf_forward((argc), (argv), argf);\
9106 } while (0)
9107 #define NEXT_ARGF_FORWARD(argc, argv) do {\
9108 if (!next_argv()) return Qnil;\
9109 ARGF_FORWARD((argc), (argv));\
9110 } while (0)
9112 static void
9113 argf_close(VALUE argf)
9115 VALUE file = ARGF.current_file;
9116 if (file == rb_stdin) return;
9117 if (RB_TYPE_P(file, T_FILE)) {
9118 rb_io_set_write_io(file, Qnil);
9120 io_close(file);
9121 ARGF.init_p = -1;
9124 static int
9125 argf_next_argv(VALUE argf)
9127 char *fn;
9128 rb_io_t *fptr;
9129 int stdout_binmode = 0;
9130 int fmode;
9132 VALUE r_stdout = rb_ractor_stdout();
9134 if (RB_TYPE_P(r_stdout, T_FILE)) {
9135 GetOpenFile(r_stdout, fptr);
9136 if (fptr->mode & FMODE_BINMODE)
9137 stdout_binmode = 1;
9140 if (ARGF.init_p == 0) {
9141 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
9142 ARGF.next_p = 1;
9144 else {
9145 ARGF.next_p = -1;
9147 ARGF.init_p = 1;
9149 else {
9150 if (NIL_P(ARGF.argv)) {
9151 ARGF.next_p = -1;
9153 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
9154 ARGF.next_p = 1;
9158 if (ARGF.next_p == 1) {
9159 if (ARGF.init_p == 1) argf_close(argf);
9160 retry:
9161 if (RARRAY_LEN(ARGF.argv) > 0) {
9162 VALUE filename = rb_ary_shift(ARGF.argv);
9163 FilePathValue(filename);
9164 ARGF.filename = filename;
9165 filename = rb_str_encode_ospath(filename);
9166 fn = StringValueCStr(filename);
9167 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
9168 ARGF.current_file = rb_stdin;
9169 if (ARGF.inplace) {
9170 rb_warn("Can't do inplace edit for stdio; skipping");
9171 goto retry;
9174 else {
9175 VALUE write_io = Qnil;
9176 int fr = rb_sysopen(filename, O_RDONLY, 0);
9178 if (ARGF.inplace) {
9179 struct stat st;
9180 #ifndef NO_SAFE_RENAME
9181 struct stat st2;
9182 #endif
9183 VALUE str;
9184 int fw;
9186 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
9187 rb_io_close(r_stdout);
9189 fstat(fr, &st);
9190 str = filename;
9191 if (!NIL_P(ARGF.inplace)) {
9192 VALUE suffix = ARGF.inplace;
9193 str = rb_str_dup(str);
9194 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
9195 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
9196 rb_enc_get(suffix), 0, Qnil))) {
9197 rb_str_append(str, suffix);
9199 #ifdef NO_SAFE_RENAME
9200 (void)close(fr);
9201 (void)unlink(RSTRING_PTR(str));
9202 if (rename(fn, RSTRING_PTR(str)) < 0) {
9203 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
9204 filename, str, strerror(errno));
9205 goto retry;
9207 fr = rb_sysopen(str, O_RDONLY, 0);
9208 #else
9209 if (rename(fn, RSTRING_PTR(str)) < 0) {
9210 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
9211 filename, str, strerror(errno));
9212 close(fr);
9213 goto retry;
9215 #endif
9217 else {
9218 #ifdef NO_SAFE_RENAME
9219 rb_fatal("Can't do inplace edit without backup");
9220 #else
9221 if (unlink(fn) < 0) {
9222 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
9223 filename, strerror(errno));
9224 close(fr);
9225 goto retry;
9227 #endif
9229 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
9230 #ifndef NO_SAFE_RENAME
9231 fstat(fw, &st2);
9232 #ifdef HAVE_FCHMOD
9233 fchmod(fw, st.st_mode);
9234 #else
9235 chmod(fn, st.st_mode);
9236 #endif
9237 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
9238 int err;
9239 #ifdef HAVE_FCHOWN
9240 err = fchown(fw, st.st_uid, st.st_gid);
9241 #else
9242 err = chown(fn, st.st_uid, st.st_gid);
9243 #endif
9244 if (err && getuid() == 0 && st2.st_uid == 0) {
9245 const char *wkfn = RSTRING_PTR(filename);
9246 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
9247 filename, str, strerror(errno));
9248 (void)close(fr);
9249 (void)close(fw);
9250 (void)unlink(wkfn);
9251 goto retry;
9254 #endif
9255 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
9256 rb_ractor_stdout_set(write_io);
9257 if (stdout_binmode) rb_io_binmode(rb_stdout);
9259 fmode = FMODE_READABLE;
9260 if (!ARGF.binmode) {
9261 fmode |= DEFAULT_TEXTMODE;
9263 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
9264 if (!NIL_P(write_io)) {
9265 rb_io_set_write_io(ARGF.current_file, write_io);
9267 RB_GC_GUARD(filename);
9269 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
9270 GetOpenFile(ARGF.current_file, fptr);
9271 if (ARGF.encs.enc) {
9272 fptr->encs = ARGF.encs;
9273 clear_codeconv(fptr);
9275 else {
9276 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
9277 if (!ARGF.binmode) {
9278 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
9279 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9280 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9281 #endif
9284 ARGF.next_p = 0;
9286 else {
9287 ARGF.next_p = 1;
9288 return FALSE;
9291 else if (ARGF.next_p == -1) {
9292 ARGF.current_file = rb_stdin;
9293 ARGF.filename = rb_str_new2("-");
9294 if (ARGF.inplace) {
9295 rb_warn("Can't do inplace edit for stdio");
9296 rb_ractor_stdout_set(orig_stdout);
9299 if (ARGF.init_p == -1) ARGF.init_p = 1;
9300 return TRUE;
9303 static VALUE
9304 argf_getline(int argc, VALUE *argv, VALUE argf)
9306 VALUE line;
9307 long lineno = ARGF.lineno;
9309 retry:
9310 if (!next_argv()) return Qnil;
9311 if (ARGF_GENERIC_INPUT_P()) {
9312 line = forward_current(idGets, argc, argv);
9314 else {
9315 if (argc == 0 && rb_rs == rb_default_rs) {
9316 line = rb_io_gets(ARGF.current_file);
9318 else {
9319 line = rb_io_getline(argc, argv, ARGF.current_file);
9321 if (NIL_P(line) && ARGF.next_p != -1) {
9322 argf_close(argf);
9323 ARGF.next_p = 1;
9324 goto retry;
9327 if (!NIL_P(line)) {
9328 ARGF.lineno = ++lineno;
9329 ARGF.last_lineno = ARGF.lineno;
9331 return line;
9334 static VALUE
9335 argf_lineno_getter(ID id, VALUE *var)
9337 VALUE argf = *var;
9338 return INT2FIX(ARGF.last_lineno);
9341 static void
9342 argf_lineno_setter(VALUE val, ID id, VALUE *var)
9344 VALUE argf = *var;
9345 int n = NUM2INT(val);
9346 ARGF.last_lineno = ARGF.lineno = n;
9349 static VALUE argf_gets(int, VALUE *, VALUE);
9352 * call-seq:
9353 * gets(sep=$/ [, getline_args]) -> string or nil
9354 * gets(limit [, getline_args]) -> string or nil
9355 * gets(sep, limit [, getline_args]) -> string or nil
9357 * Returns (and assigns to <code>$_</code>) the next line from the list
9358 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
9359 * no files are present on the command line. Returns +nil+ at end of
9360 * file. The optional argument specifies the record separator. The
9361 * separator is included with the contents of each record. A separator
9362 * of +nil+ reads the entire contents, and a zero-length separator
9363 * reads the input one paragraph at a time, where paragraphs are
9364 * divided by two consecutive newlines. If the first argument is an
9365 * integer, or optional second argument is given, the returning string
9366 * would not be longer than the given value in bytes. If multiple
9367 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
9368 * the contents one file at a time.
9370 * ARGV << "testfile"
9371 * print while gets
9373 * <em>produces:</em>
9375 * This is line one
9376 * This is line two
9377 * This is line three
9378 * And so on...
9380 * The style of programming using <code>$_</code> as an implicit
9381 * parameter is gradually losing favor in the Ruby community.
9384 static VALUE
9385 rb_f_gets(int argc, VALUE *argv, VALUE recv)
9387 if (recv == argf) {
9388 return argf_gets(argc, argv, argf);
9390 return forward(argf, idGets, argc, argv);
9394 * call-seq:
9395 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
9396 * ARGF.gets(limit [, getline_args]) -> string or nil
9397 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
9399 * Returns the next line from the current file in +ARGF+.
9401 * By default lines are assumed to be separated by <code>$/</code>;
9402 * to use a different character as a separator, supply it as a +String+
9403 * for the _sep_ argument.
9405 * The optional _limit_ argument specifies how many characters of each line
9406 * to return. By default all characters are returned.
9408 * See IO.readlines for details about getline_args.
9411 static VALUE
9412 argf_gets(int argc, VALUE *argv, VALUE argf)
9414 VALUE line;
9416 line = argf_getline(argc, argv, argf);
9417 rb_lastline_set(line);
9419 return line;
9422 VALUE
9423 rb_gets(void)
9425 VALUE line;
9427 if (rb_rs != rb_default_rs) {
9428 return rb_f_gets(0, 0, argf);
9431 retry:
9432 if (!next_argv()) return Qnil;
9433 line = rb_io_gets(ARGF.current_file);
9434 if (NIL_P(line) && ARGF.next_p != -1) {
9435 rb_io_close(ARGF.current_file);
9436 ARGF.next_p = 1;
9437 goto retry;
9439 rb_lastline_set(line);
9440 if (!NIL_P(line)) {
9441 ARGF.lineno++;
9442 ARGF.last_lineno = ARGF.lineno;
9445 return line;
9448 static VALUE argf_readline(int, VALUE *, VALUE);
9451 * call-seq:
9452 * readline(sep=$/) -> string
9453 * readline(limit) -> string
9454 * readline(sep, limit) -> string
9456 * Equivalent to Kernel::gets, except
9457 * +readline+ raises +EOFError+ at end of file.
9460 static VALUE
9461 rb_f_readline(int argc, VALUE *argv, VALUE recv)
9463 if (recv == argf) {
9464 return argf_readline(argc, argv, argf);
9466 return forward(argf, rb_intern("readline"), argc, argv);
9471 * call-seq:
9472 * ARGF.readline(sep=$/) -> string
9473 * ARGF.readline(limit) -> string
9474 * ARGF.readline(sep, limit) -> string
9476 * Returns the next line from the current file in +ARGF+.
9478 * By default lines are assumed to be separated by <code>$/</code>;
9479 * to use a different character as a separator, supply it as a +String+
9480 * for the _sep_ argument.
9482 * The optional _limit_ argument specifies how many characters of each line
9483 * to return. By default all characters are returned.
9485 * An +EOFError+ is raised at the end of the file.
9487 static VALUE
9488 argf_readline(int argc, VALUE *argv, VALUE argf)
9490 VALUE line;
9492 if (!next_argv()) rb_eof_error();
9493 ARGF_FORWARD(argc, argv);
9494 line = argf_gets(argc, argv, argf);
9495 if (NIL_P(line)) {
9496 rb_eof_error();
9499 return line;
9502 static VALUE argf_readlines(int, VALUE *, VALUE);
9505 * call-seq:
9506 * readlines(sep=$/) -> array
9507 * readlines(limit) -> array
9508 * readlines(sep, limit) -> array
9510 * Returns an array containing the lines returned by calling
9511 * <code>Kernel.gets(<i>sep</i>)</code> until the end of file.
9514 static VALUE
9515 rb_f_readlines(int argc, VALUE *argv, VALUE recv)
9517 if (recv == argf) {
9518 return argf_readlines(argc, argv, argf);
9520 return forward(argf, rb_intern("readlines"), argc, argv);
9524 * call-seq:
9525 * ARGF.readlines(sep=$/) -> array
9526 * ARGF.readlines(limit) -> array
9527 * ARGF.readlines(sep, limit) -> array
9529 * ARGF.to_a(sep=$/) -> array
9530 * ARGF.to_a(limit) -> array
9531 * ARGF.to_a(sep, limit) -> array
9533 * Reads +ARGF+'s current file in its entirety, returning an +Array+ of its
9534 * lines, one line per element. Lines are assumed to be separated by _sep_.
9536 * lines = ARGF.readlines
9537 * lines[0] #=> "This is line one\n"
9539 static VALUE
9540 argf_readlines(int argc, VALUE *argv, VALUE argf)
9542 long lineno = ARGF.lineno;
9543 VALUE lines, ary;
9545 ary = rb_ary_new();
9546 while (next_argv()) {
9547 if (ARGF_GENERIC_INPUT_P()) {
9548 lines = forward_current(rb_intern("readlines"), argc, argv);
9550 else {
9551 lines = rb_io_readlines(argc, argv, ARGF.current_file);
9552 argf_close(argf);
9554 ARGF.next_p = 1;
9555 rb_ary_concat(ary, lines);
9556 ARGF.lineno = lineno + RARRAY_LEN(ary);
9557 ARGF.last_lineno = ARGF.lineno;
9559 ARGF.init_p = 0;
9560 return ary;
9564 * call-seq:
9565 * `cmd` -> string
9567 * Returns the standard output of running _cmd_ in a subshell.
9568 * The built-in syntax <code>%x{...}</code> uses
9569 * this method. Sets <code>$?</code> to the process status.
9571 * `date` #=> "Wed Apr 9 08:56:30 CDT 2003\n"
9572 * `ls testdir`.split[1] #=> "main.rb"
9573 * `echo oops && exit 99` #=> "oops\n"
9574 * $?.exitstatus #=> 99
9577 static VALUE
9578 rb_f_backquote(VALUE obj, VALUE str)
9580 VALUE port;
9581 VALUE result;
9582 rb_io_t *fptr;
9584 SafeStringValue(str);
9585 rb_last_status_clear();
9586 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
9587 if (NIL_P(port)) return rb_str_new(0,0);
9589 GetOpenFile(port, fptr);
9590 result = read_all(fptr, remain_size(fptr), Qnil);
9591 rb_io_close(port);
9592 RFILE(port)->fptr = NULL;
9593 rb_io_fptr_finalize(fptr);
9594 RB_GC_GUARD(port);
9596 return result;
9599 #ifdef HAVE_SYS_SELECT_H
9600 #include <sys/select.h>
9601 #endif
9603 static VALUE
9604 select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
9606 VALUE res, list;
9607 rb_fdset_t *rp, *wp, *ep;
9608 rb_io_t *fptr;
9609 long i;
9610 int max = 0, n;
9611 int pending = 0;
9612 struct timeval timerec;
9614 if (!NIL_P(read)) {
9615 Check_Type(read, T_ARRAY);
9616 for (i=0; i<RARRAY_LEN(read); i++) {
9617 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
9618 rb_fd_set(fptr->fd, &fds[0]);
9619 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
9620 pending++;
9621 rb_fd_set(fptr->fd, &fds[3]);
9623 if (max < fptr->fd) max = fptr->fd;
9625 if (pending) { /* no blocking if there's buffered data */
9626 timerec.tv_sec = timerec.tv_usec = 0;
9627 tp = &timerec;
9629 rp = &fds[0];
9631 else
9632 rp = 0;
9634 if (!NIL_P(write)) {
9635 Check_Type(write, T_ARRAY);
9636 for (i=0; i<RARRAY_LEN(write); i++) {
9637 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
9638 GetOpenFile(write_io, fptr);
9639 rb_fd_set(fptr->fd, &fds[1]);
9640 if (max < fptr->fd) max = fptr->fd;
9642 wp = &fds[1];
9644 else
9645 wp = 0;
9647 if (!NIL_P(except)) {
9648 Check_Type(except, T_ARRAY);
9649 for (i=0; i<RARRAY_LEN(except); i++) {
9650 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
9651 VALUE write_io = GetWriteIO(io);
9652 GetOpenFile(io, fptr);
9653 rb_fd_set(fptr->fd, &fds[2]);
9654 if (max < fptr->fd) max = fptr->fd;
9655 if (io != write_io) {
9656 GetOpenFile(write_io, fptr);
9657 rb_fd_set(fptr->fd, &fds[2]);
9658 if (max < fptr->fd) max = fptr->fd;
9661 ep = &fds[2];
9663 else {
9664 ep = 0;
9667 max++;
9669 n = rb_thread_fd_select(max, rp, wp, ep, tp);
9670 if (n < 0) {
9671 rb_sys_fail(0);
9673 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
9675 res = rb_ary_new2(3);
9676 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
9677 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
9678 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
9680 if (rp) {
9681 list = RARRAY_AREF(res, 0);
9682 for (i=0; i< RARRAY_LEN(read); i++) {
9683 VALUE obj = rb_ary_entry(read, i);
9684 VALUE io = rb_io_get_io(obj);
9685 GetOpenFile(io, fptr);
9686 if (rb_fd_isset(fptr->fd, &fds[0]) ||
9687 rb_fd_isset(fptr->fd, &fds[3])) {
9688 rb_ary_push(list, obj);
9693 if (wp) {
9694 list = RARRAY_AREF(res, 1);
9695 for (i=0; i< RARRAY_LEN(write); i++) {
9696 VALUE obj = rb_ary_entry(write, i);
9697 VALUE io = rb_io_get_io(obj);
9698 VALUE write_io = GetWriteIO(io);
9699 GetOpenFile(write_io, fptr);
9700 if (rb_fd_isset(fptr->fd, &fds[1])) {
9701 rb_ary_push(list, obj);
9706 if (ep) {
9707 list = RARRAY_AREF(res, 2);
9708 for (i=0; i< RARRAY_LEN(except); i++) {
9709 VALUE obj = rb_ary_entry(except, i);
9710 VALUE io = rb_io_get_io(obj);
9711 VALUE write_io = GetWriteIO(io);
9712 GetOpenFile(io, fptr);
9713 if (rb_fd_isset(fptr->fd, &fds[2])) {
9714 rb_ary_push(list, obj);
9716 else if (io != write_io) {
9717 GetOpenFile(write_io, fptr);
9718 if (rb_fd_isset(fptr->fd, &fds[2])) {
9719 rb_ary_push(list, obj);
9725 return res; /* returns an empty array on interrupt */
9728 struct select_args {
9729 VALUE read, write, except;
9730 struct timeval *timeout;
9731 rb_fdset_t fdsets[4];
9734 static VALUE
9735 select_call(VALUE arg)
9737 struct select_args *p = (struct select_args *)arg;
9739 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
9742 static VALUE
9743 select_end(VALUE arg)
9745 struct select_args *p = (struct select_args *)arg;
9746 int i;
9748 for (i = 0; i < numberof(p->fdsets); ++i)
9749 rb_fd_term(&p->fdsets[i]);
9750 return Qnil;
9753 static VALUE sym_normal, sym_sequential, sym_random,
9754 sym_willneed, sym_dontneed, sym_noreuse;
9756 #ifdef HAVE_POSIX_FADVISE
9757 struct io_advise_struct {
9758 int fd;
9759 int advice;
9760 off_t offset;
9761 off_t len;
9764 static VALUE
9765 io_advise_internal(void *arg)
9767 struct io_advise_struct *ptr = arg;
9768 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
9771 static VALUE
9772 io_advise_sym_to_const(VALUE sym)
9774 #ifdef POSIX_FADV_NORMAL
9775 if (sym == sym_normal)
9776 return INT2NUM(POSIX_FADV_NORMAL);
9777 #endif
9779 #ifdef POSIX_FADV_RANDOM
9780 if (sym == sym_random)
9781 return INT2NUM(POSIX_FADV_RANDOM);
9782 #endif
9784 #ifdef POSIX_FADV_SEQUENTIAL
9785 if (sym == sym_sequential)
9786 return INT2NUM(POSIX_FADV_SEQUENTIAL);
9787 #endif
9789 #ifdef POSIX_FADV_WILLNEED
9790 if (sym == sym_willneed)
9791 return INT2NUM(POSIX_FADV_WILLNEED);
9792 #endif
9794 #ifdef POSIX_FADV_DONTNEED
9795 if (sym == sym_dontneed)
9796 return INT2NUM(POSIX_FADV_DONTNEED);
9797 #endif
9799 #ifdef POSIX_FADV_NOREUSE
9800 if (sym == sym_noreuse)
9801 return INT2NUM(POSIX_FADV_NOREUSE);
9802 #endif
9804 return Qnil;
9807 static VALUE
9808 do_io_advise(rb_io_t *fptr, VALUE advice, off_t offset, off_t len)
9810 int rv;
9811 struct io_advise_struct ias;
9812 VALUE num_adv;
9814 num_adv = io_advise_sym_to_const(advice);
9817 * The platform doesn't support this hint. We don't raise exception, instead
9818 * silently ignore it. Because IO::advise is only hint.
9820 if (NIL_P(num_adv))
9821 return Qnil;
9823 ias.fd = fptr->fd;
9824 ias.advice = NUM2INT(num_adv);
9825 ias.offset = offset;
9826 ias.len = len;
9828 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
9829 if (rv && rv != ENOSYS) {
9830 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
9831 it returns the error code. */
9832 VALUE message = rb_sprintf("%"PRIsVALUE" "
9833 "(%"PRI_OFFT_PREFIX"d, "
9834 "%"PRI_OFFT_PREFIX"d, "
9835 "%"PRIsVALUE")",
9836 fptr->pathv, offset, len, advice);
9837 rb_syserr_fail_str(rv, message);
9840 return Qnil;
9843 #endif /* HAVE_POSIX_FADVISE */
9845 static void
9846 advice_arg_check(VALUE advice)
9848 if (!SYMBOL_P(advice))
9849 rb_raise(rb_eTypeError, "advice must be a Symbol");
9851 if (advice != sym_normal &&
9852 advice != sym_sequential &&
9853 advice != sym_random &&
9854 advice != sym_willneed &&
9855 advice != sym_dontneed &&
9856 advice != sym_noreuse) {
9857 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
9862 * call-seq:
9863 * ios.advise(advice, offset=0, len=0) -> nil
9865 * Announce an intention to access data from the current file in a
9866 * specific pattern. On platforms that do not support the
9867 * <em>posix_fadvise(2)</em> system call, this method is a no-op.
9869 * _advice_ is one of the following symbols:
9871 * :normal:: No advice to give; the default assumption for an open file.
9872 * :sequential:: The data will be accessed sequentially
9873 * with lower offsets read before higher ones.
9874 * :random:: The data will be accessed in random order.
9875 * :willneed:: The data will be accessed in the near future.
9876 * :dontneed:: The data will not be accessed in the near future.
9877 * :noreuse:: The data will only be accessed once.
9879 * The semantics of a piece of advice are platform-dependent. See
9880 * <em>man 2 posix_fadvise</em> for details.
9882 * "data" means the region of the current file that begins at
9883 * _offset_ and extends for _len_ bytes. If _len_ is 0, the region
9884 * ends at the last byte of the file. By default, both _offset_ and
9885 * _len_ are 0, meaning that the advice applies to the entire file.
9887 * If an error occurs, one of the following exceptions will be raised:
9889 * IOError:: The IO stream is closed.
9890 * Errno::EBADF::
9891 * The file descriptor of the current file is invalid.
9892 * Errno::EINVAL:: An invalid value for _advice_ was given.
9893 * Errno::ESPIPE::
9894 * The file descriptor of the current file refers to a FIFO or
9895 * pipe. (Linux raises Errno::EINVAL in this case).
9896 * TypeError::
9897 * Either _advice_ was not a Symbol, or one of the
9898 * other arguments was not an Integer.
9899 * RangeError:: One of the arguments given was too big/small.
9901 * This list is not exhaustive; other Errno:: exceptions are also possible.
9903 static VALUE
9904 rb_io_advise(int argc, VALUE *argv, VALUE io)
9906 VALUE advice, offset, len;
9907 off_t off, l;
9908 rb_io_t *fptr;
9910 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
9911 advice_arg_check(advice);
9913 io = GetWriteIO(io);
9914 GetOpenFile(io, fptr);
9916 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
9917 l = NIL_P(len) ? 0 : NUM2OFFT(len);
9919 #ifdef HAVE_POSIX_FADVISE
9920 return do_io_advise(fptr, advice, off, l);
9921 #else
9922 ((void)off, (void)l); /* Ignore all hint */
9923 return Qnil;
9924 #endif
9928 * call-seq:
9929 * IO.select(read_array [, write_array [, error_array [, timeout]]]) -> array or nil
9931 * Calls select(2) system call.
9932 * It monitors given arrays of IO objects, waits until one or more of
9933 * IO objects are ready for reading, are ready for writing, and have
9934 * pending exceptions respectively, and returns an array that contains
9935 * arrays of those IO objects. It will return +nil+ if optional
9936 * <i>timeout</i> value is given and no IO object is ready in
9937 * <i>timeout</i> seconds.
9939 * IO.select peeks the buffer of IO objects for testing readability.
9940 * If the IO buffer is not empty, IO.select immediately notifies
9941 * readability. This "peek" only happens for IO objects. It does not
9942 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
9944 * The best way to use IO.select is invoking it after nonblocking
9945 * methods such as #read_nonblock, #write_nonblock, etc. The methods
9946 * raise an exception which is extended by IO::WaitReadable or
9947 * IO::WaitWritable. The modules notify how the caller should wait
9948 * with IO.select. If IO::WaitReadable is raised, the caller should
9949 * wait for reading. If IO::WaitWritable is raised, the caller should
9950 * wait for writing.
9952 * So, blocking read (#readpartial) can be emulated using
9953 * #read_nonblock and IO.select as follows:
9955 * begin
9956 * result = io_like.read_nonblock(maxlen)
9957 * rescue IO::WaitReadable
9958 * IO.select([io_like])
9959 * retry
9960 * rescue IO::WaitWritable
9961 * IO.select(nil, [io_like])
9962 * retry
9963 * end
9965 * Especially, the combination of nonblocking methods and IO.select is
9966 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
9967 * has #to_io method to return underlying IO object. IO.select calls
9968 * #to_io to obtain the file descriptor to wait.
9970 * This means that readability notified by IO.select doesn't mean
9971 * readability from OpenSSL::SSL::SSLSocket object.
9973 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
9974 * some data. IO.select doesn't see the buffer. So IO.select can
9975 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
9977 * However, several more complicated situations exist.
9979 * SSL is a protocol which is sequence of records.
9980 * The record consists of multiple bytes.
9981 * So, the remote side of SSL sends a partial record, IO.select
9982 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
9983 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
9985 * Also, the remote side can request SSL renegotiation which forces
9986 * the local SSL engine to write some data.
9987 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
9988 * system call and it can block.
9989 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
9990 * IO::WaitWritable instead of blocking.
9991 * So, the caller should wait for ready for writability as above
9992 * example.
9994 * The combination of nonblocking methods and IO.select is also useful
9995 * for streams such as tty, pipe socket socket when multiple processes
9996 * read from a stream.
9998 * Finally, Linux kernel developers don't guarantee that
9999 * readability of select(2) means readability of following read(2) even
10000 * for a single process.
10001 * See select(2) manual on GNU/Linux system.
10003 * Invoking IO.select before IO#readpartial works well as usual.
10004 * However it is not the best way to use IO.select.
10006 * The writability notified by select(2) doesn't show
10007 * how many bytes are writable.
10008 * IO#write method blocks until given whole string is written.
10009 * So, <code>IO#write(two or more bytes)</code> can block after
10010 * writability is notified by IO.select. IO#write_nonblock is required
10011 * to avoid the blocking.
10013 * Blocking write (#write) can be emulated using #write_nonblock and
10014 * IO.select as follows: IO::WaitReadable should also be rescued for
10015 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
10017 * while 0 < string.bytesize
10018 * begin
10019 * written = io_like.write_nonblock(string)
10020 * rescue IO::WaitReadable
10021 * IO.select([io_like])
10022 * retry
10023 * rescue IO::WaitWritable
10024 * IO.select(nil, [io_like])
10025 * retry
10026 * end
10027 * string = string.byteslice(written..-1)
10028 * end
10030 * === Parameters
10031 * read_array:: an array of IO objects that wait until ready for read
10032 * write_array:: an array of IO objects that wait until ready for write
10033 * error_array:: an array of IO objects that wait for exceptions
10034 * timeout:: a numeric value in second
10036 * === Example
10038 * rp, wp = IO.pipe
10039 * mesg = "ping "
10040 * 100.times {
10041 * # IO.select follows IO#read. Not the best way to use IO.select.
10042 * rs, ws, = IO.select([rp], [wp])
10043 * if r = rs[0]
10044 * ret = r.read(5)
10045 * print ret
10046 * case ret
10047 * when /ping/
10048 * mesg = "pong\n"
10049 * when /pong/
10050 * mesg = "ping "
10051 * end
10052 * end
10053 * if w = ws[0]
10054 * w.write(mesg)
10055 * end
10058 * <em>produces:</em>
10060 * ping pong
10061 * ping pong
10062 * ping pong
10063 * (snipped)
10064 * ping
10067 static VALUE
10068 rb_f_select(int argc, VALUE *argv, VALUE obj)
10070 VALUE timeout;
10071 struct select_args args;
10072 struct timeval timerec;
10073 int i;
10075 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
10076 if (NIL_P(timeout)) {
10077 args.timeout = 0;
10079 else {
10080 timerec = rb_time_interval(timeout);
10081 args.timeout = &timerec;
10084 for (i = 0; i < numberof(args.fdsets); ++i)
10085 rb_fd_init(&args.fdsets[i]);
10087 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
10090 #ifdef IOCTL_REQ_TYPE
10091 typedef IOCTL_REQ_TYPE ioctl_req_t;
10092 #else
10093 typedef int ioctl_req_t;
10094 # define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
10095 #endif
10097 #ifdef HAVE_IOCTL
10098 struct ioctl_arg {
10099 int fd;
10100 ioctl_req_t cmd;
10101 long narg;
10104 static VALUE
10105 nogvl_ioctl(void *ptr)
10107 struct ioctl_arg *arg = ptr;
10109 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
10112 static int
10113 do_ioctl(int fd, ioctl_req_t cmd, long narg)
10115 int retval;
10116 struct ioctl_arg arg;
10118 arg.fd = fd;
10119 arg.cmd = cmd;
10120 arg.narg = narg;
10122 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
10124 return retval;
10126 #endif
10128 #define DEFAULT_IOCTL_NARG_LEN (256)
10130 #if defined(__linux__) && defined(_IOC_SIZE)
10131 static long
10132 linux_iocparm_len(ioctl_req_t cmd)
10134 long len;
10136 if ((cmd & 0xFFFF0000) == 0) {
10137 /* legacy and unstructured ioctl number. */
10138 return DEFAULT_IOCTL_NARG_LEN;
10141 len = _IOC_SIZE(cmd);
10143 /* paranoia check for silly drivers which don't keep ioctl convention */
10144 if (len < DEFAULT_IOCTL_NARG_LEN)
10145 len = DEFAULT_IOCTL_NARG_LEN;
10147 return len;
10149 #endif
10151 #ifdef HAVE_IOCTL
10152 static long
10153 ioctl_narg_len(ioctl_req_t cmd)
10155 long len;
10157 #ifdef IOCPARM_MASK
10158 #ifndef IOCPARM_LEN
10159 #define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
10160 #endif
10161 #endif
10162 #ifdef IOCPARM_LEN
10163 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
10164 #elif defined(__linux__) && defined(_IOC_SIZE)
10165 len = linux_iocparm_len(cmd);
10166 #else
10167 /* otherwise guess at what's safe */
10168 len = DEFAULT_IOCTL_NARG_LEN;
10169 #endif
10171 return len;
10173 #endif
10175 #ifdef HAVE_FCNTL
10176 #ifdef __linux__
10177 typedef long fcntl_arg_t;
10178 #else
10179 /* posix */
10180 typedef int fcntl_arg_t;
10181 #endif
10183 static long
10184 fcntl_narg_len(ioctl_req_t cmd)
10186 long len;
10188 switch (cmd) {
10189 #ifdef F_DUPFD
10190 case F_DUPFD:
10191 len = sizeof(fcntl_arg_t);
10192 break;
10193 #endif
10194 #ifdef F_DUP2FD /* bsd specific */
10195 case F_DUP2FD:
10196 len = sizeof(int);
10197 break;
10198 #endif
10199 #ifdef F_DUPFD_CLOEXEC /* linux specific */
10200 case F_DUPFD_CLOEXEC:
10201 len = sizeof(fcntl_arg_t);
10202 break;
10203 #endif
10204 #ifdef F_GETFD
10205 case F_GETFD:
10206 len = 1;
10207 break;
10208 #endif
10209 #ifdef F_SETFD
10210 case F_SETFD:
10211 len = sizeof(fcntl_arg_t);
10212 break;
10213 #endif
10214 #ifdef F_GETFL
10215 case F_GETFL:
10216 len = 1;
10217 break;
10218 #endif
10219 #ifdef F_SETFL
10220 case F_SETFL:
10221 len = sizeof(fcntl_arg_t);
10222 break;
10223 #endif
10224 #ifdef F_GETOWN
10225 case F_GETOWN:
10226 len = 1;
10227 break;
10228 #endif
10229 #ifdef F_SETOWN
10230 case F_SETOWN:
10231 len = sizeof(fcntl_arg_t);
10232 break;
10233 #endif
10234 #ifdef F_GETOWN_EX /* linux specific */
10235 case F_GETOWN_EX:
10236 len = sizeof(struct f_owner_ex);
10237 break;
10238 #endif
10239 #ifdef F_SETOWN_EX /* linux specific */
10240 case F_SETOWN_EX:
10241 len = sizeof(struct f_owner_ex);
10242 break;
10243 #endif
10244 #ifdef F_GETLK
10245 case F_GETLK:
10246 len = sizeof(struct flock);
10247 break;
10248 #endif
10249 #ifdef F_SETLK
10250 case F_SETLK:
10251 len = sizeof(struct flock);
10252 break;
10253 #endif
10254 #ifdef F_SETLKW
10255 case F_SETLKW:
10256 len = sizeof(struct flock);
10257 break;
10258 #endif
10259 #ifdef F_READAHEAD /* bsd specific */
10260 case F_READAHEAD:
10261 len = sizeof(int);
10262 break;
10263 #endif
10264 #ifdef F_RDAHEAD /* Darwin specific */
10265 case F_RDAHEAD:
10266 len = sizeof(int);
10267 break;
10268 #endif
10269 #ifdef F_GETSIG /* linux specific */
10270 case F_GETSIG:
10271 len = 1;
10272 break;
10273 #endif
10274 #ifdef F_SETSIG /* linux specific */
10275 case F_SETSIG:
10276 len = sizeof(fcntl_arg_t);
10277 break;
10278 #endif
10279 #ifdef F_GETLEASE /* linux specific */
10280 case F_GETLEASE:
10281 len = 1;
10282 break;
10283 #endif
10284 #ifdef F_SETLEASE /* linux specific */
10285 case F_SETLEASE:
10286 len = sizeof(fcntl_arg_t);
10287 break;
10288 #endif
10289 #ifdef F_NOTIFY /* linux specific */
10290 case F_NOTIFY:
10291 len = sizeof(fcntl_arg_t);
10292 break;
10293 #endif
10295 default:
10296 len = 256;
10297 break;
10300 return len;
10302 #else /* HAVE_FCNTL */
10303 static long
10304 fcntl_narg_len(ioctl_req_t cmd)
10306 return 0;
10308 #endif /* HAVE_FCNTL */
10310 #define NARG_SENTINEL 17
10312 static long
10313 setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
10315 long narg = 0;
10316 VALUE arg = *argp;
10318 if (!RTEST(arg)) {
10319 narg = 0;
10321 else if (FIXNUM_P(arg)) {
10322 narg = FIX2LONG(arg);
10324 else if (arg == Qtrue) {
10325 narg = 1;
10327 else {
10328 VALUE tmp = rb_check_string_type(arg);
10330 if (NIL_P(tmp)) {
10331 narg = NUM2LONG(arg);
10333 else {
10334 char *ptr;
10335 long len, slen;
10337 *argp = arg = tmp;
10338 len = narg_len(cmd);
10339 rb_str_modify(arg);
10341 slen = RSTRING_LEN(arg);
10342 /* expand for data + sentinel. */
10343 if (slen < len+1) {
10344 rb_str_resize(arg, len+1);
10345 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
10346 slen = len+1;
10348 /* a little sanity check here */
10349 ptr = RSTRING_PTR(arg);
10350 ptr[slen - 1] = NARG_SENTINEL;
10351 narg = (long)(SIGNED_VALUE)ptr;
10355 return narg;
10358 static VALUE
10359 finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
10361 if (retval < 0) rb_sys_fail_path(fptr->pathv);
10362 if (RB_TYPE_P(arg, T_STRING)) {
10363 char *ptr;
10364 long slen;
10365 RSTRING_GETMEM(arg, ptr, slen);
10366 if (ptr[slen-1] != NARG_SENTINEL)
10367 rb_raise(rb_eArgError, "return value overflowed string");
10368 ptr[slen-1] = '\0';
10371 return INT2NUM(retval);
10374 #ifdef HAVE_IOCTL
10375 static VALUE
10376 rb_ioctl(VALUE io, VALUE req, VALUE arg)
10378 ioctl_req_t cmd = NUM2IOCTLREQ(req);
10379 rb_io_t *fptr;
10380 long narg;
10381 int retval;
10383 narg = setup_narg(cmd, &arg, ioctl_narg_len);
10384 GetOpenFile(io, fptr);
10385 retval = do_ioctl(fptr->fd, cmd, narg);
10386 return finish_narg(retval, arg, fptr);
10390 * call-seq:
10391 * ios.ioctl(integer_cmd, arg) -> integer
10393 * Provides a mechanism for issuing low-level commands to control or
10394 * query I/O devices. Arguments and results are platform dependent. If
10395 * <i>arg</i> is a number, its value is passed directly. If it is a
10396 * string, it is interpreted as a binary sequence of bytes. On Unix
10397 * platforms, see <code>ioctl(2)</code> for details. Not implemented on
10398 * all platforms.
10401 static VALUE
10402 rb_io_ioctl(int argc, VALUE *argv, VALUE io)
10404 VALUE req, arg;
10406 rb_scan_args(argc, argv, "11", &req, &arg);
10407 return rb_ioctl(io, req, arg);
10409 #else
10410 #define rb_io_ioctl rb_f_notimplement
10411 #endif
10413 #ifdef HAVE_FCNTL
10414 struct fcntl_arg {
10415 int fd;
10416 int cmd;
10417 long narg;
10420 static VALUE
10421 nogvl_fcntl(void *ptr)
10423 struct fcntl_arg *arg = ptr;
10425 #if defined(F_DUPFD)
10426 if (arg->cmd == F_DUPFD)
10427 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
10428 #endif
10429 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
10432 static int
10433 do_fcntl(int fd, int cmd, long narg)
10435 int retval;
10436 struct fcntl_arg arg;
10438 arg.fd = fd;
10439 arg.cmd = cmd;
10440 arg.narg = narg;
10442 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
10443 if (retval != -1) {
10444 switch (cmd) {
10445 #if defined(F_DUPFD)
10446 case F_DUPFD:
10447 #endif
10448 #if defined(F_DUPFD_CLOEXEC)
10449 case F_DUPFD_CLOEXEC:
10450 #endif
10451 rb_update_max_fd(retval);
10455 return retval;
10458 static VALUE
10459 rb_fcntl(VALUE io, VALUE req, VALUE arg)
10461 int cmd = NUM2INT(req);
10462 rb_io_t *fptr;
10463 long narg;
10464 int retval;
10466 narg = setup_narg(cmd, &arg, fcntl_narg_len);
10467 GetOpenFile(io, fptr);
10468 retval = do_fcntl(fptr->fd, cmd, narg);
10469 return finish_narg(retval, arg, fptr);
10473 * call-seq:
10474 * ios.fcntl(integer_cmd, arg) -> integer
10476 * Provides a mechanism for issuing low-level commands to control or
10477 * query file-oriented I/O streams. Arguments and results are platform
10478 * dependent. If <i>arg</i> is a number, its value is passed
10479 * directly. If it is a string, it is interpreted as a binary sequence
10480 * of bytes (Array#pack might be a useful way to build this string). On
10481 * Unix platforms, see <code>fcntl(2)</code> for details. Not
10482 * implemented on all platforms.
10485 static VALUE
10486 rb_io_fcntl(int argc, VALUE *argv, VALUE io)
10488 VALUE req, arg;
10490 rb_scan_args(argc, argv, "11", &req, &arg);
10491 return rb_fcntl(io, req, arg);
10493 #else
10494 #define rb_io_fcntl rb_f_notimplement
10495 #endif
10497 #if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
10499 * call-seq:
10500 * syscall(num [, args...]) -> integer
10502 * Calls the operating system function identified by _num_ and
10503 * returns the result of the function or raises SystemCallError if
10504 * it failed.
10506 * Arguments for the function can follow _num_. They must be either
10507 * +String+ objects or +Integer+ objects. A +String+ object is passed
10508 * as a pointer to the byte sequence. An +Integer+ object is passed
10509 * as an integer whose bit size is the same as a pointer.
10510 * Up to nine parameters may be passed.
10512 * The function identified by _num_ is system
10513 * dependent. On some Unix systems, the numbers may be obtained from a
10514 * header file called <code>syscall.h</code>.
10516 * syscall 4, 1, "hello\n", 6 # '4' is write(2) on our box
10518 * <em>produces:</em>
10520 * hello
10522 * Calling +syscall+ on a platform which does not have any way to
10523 * an arbitrary system function just fails with NotImplementedError.
10525 * *Note:*
10526 * +syscall+ is essentially unsafe and unportable.
10527 * Feel free to shoot your foot.
10528 * The DL (Fiddle) library is preferred for safer and a bit
10529 * more portable programming.
10532 static VALUE
10533 rb_f_syscall(int argc, VALUE *argv, VALUE _)
10535 VALUE arg[8];
10536 #if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
10537 # define SYSCALL __syscall
10538 # define NUM2SYSCALLID(x) NUM2LONG(x)
10539 # define RETVAL2NUM(x) LONG2NUM(x)
10540 # if SIZEOF_LONG == 8
10541 long num, retval = -1;
10542 # elif SIZEOF_LONG_LONG == 8
10543 long long num, retval = -1;
10544 # else
10545 # error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
10546 # endif
10547 #elif defined(__linux__)
10548 # define SYSCALL syscall
10549 # define NUM2SYSCALLID(x) NUM2LONG(x)
10550 # define RETVAL2NUM(x) LONG2NUM(x)
10552 * Linux man page says, syscall(2) function prototype is below.
10554 * int syscall(int number, ...);
10556 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
10558 long num, retval = -1;
10559 #else
10560 # define SYSCALL syscall
10561 # define NUM2SYSCALLID(x) NUM2INT(x)
10562 # define RETVAL2NUM(x) INT2NUM(x)
10563 int num, retval = -1;
10564 #endif
10565 int i;
10567 if (RTEST(ruby_verbose)) {
10568 rb_category_warning(RB_WARN_CATEGORY_DEPRECATED,
10569 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
10572 if (argc == 0)
10573 rb_raise(rb_eArgError, "too few arguments for syscall");
10574 if (argc > numberof(arg))
10575 rb_raise(rb_eArgError, "too many arguments for syscall");
10576 num = NUM2SYSCALLID(argv[0]); ++argv;
10577 for (i = argc - 1; i--; ) {
10578 VALUE v = rb_check_string_type(argv[i]);
10580 if (!NIL_P(v)) {
10581 SafeStringValue(v);
10582 rb_str_modify(v);
10583 arg[i] = (VALUE)StringValueCStr(v);
10585 else {
10586 arg[i] = (VALUE)NUM2LONG(argv[i]);
10590 switch (argc) {
10591 case 1:
10592 retval = SYSCALL(num);
10593 break;
10594 case 2:
10595 retval = SYSCALL(num, arg[0]);
10596 break;
10597 case 3:
10598 retval = SYSCALL(num, arg[0],arg[1]);
10599 break;
10600 case 4:
10601 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
10602 break;
10603 case 5:
10604 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
10605 break;
10606 case 6:
10607 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
10608 break;
10609 case 7:
10610 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
10611 break;
10612 case 8:
10613 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
10614 break;
10617 if (retval == -1)
10618 rb_sys_fail(0);
10619 return RETVAL2NUM(retval);
10620 #undef SYSCALL
10621 #undef NUM2SYSCALLID
10622 #undef RETVAL2NUM
10624 #else
10625 #define rb_f_syscall rb_f_notimplement
10626 #endif
10628 static VALUE
10629 io_new_instance(VALUE args)
10631 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
10634 static rb_encoding *
10635 find_encoding(VALUE v)
10637 rb_encoding *enc = rb_find_encoding(v);
10638 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
10639 return enc;
10642 static void
10643 io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
10645 rb_encoding *enc, *enc2;
10646 int ecflags = fptr->encs.ecflags;
10647 VALUE ecopts, tmp;
10649 if (!NIL_P(v2)) {
10650 enc2 = find_encoding(v1);
10651 tmp = rb_check_string_type(v2);
10652 if (!NIL_P(tmp)) {
10653 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
10654 /* Special case - "-" => no transcoding */
10655 enc = enc2;
10656 enc2 = NULL;
10658 else
10659 enc = find_encoding(v2);
10660 if (enc == enc2) {
10661 /* Special case - "-" => no transcoding */
10662 enc2 = NULL;
10665 else {
10666 enc = find_encoding(v2);
10667 if (enc == enc2) {
10668 /* Special case - "-" => no transcoding */
10669 enc2 = NULL;
10672 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10673 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
10675 else {
10676 if (NIL_P(v1)) {
10677 /* Set to default encodings */
10678 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
10679 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10680 ecopts = Qnil;
10682 else {
10683 tmp = rb_check_string_type(v1);
10684 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
10685 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
10686 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10687 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
10689 else {
10690 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
10691 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10692 ecopts = Qnil;
10696 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
10697 fptr->encs.enc = enc;
10698 fptr->encs.enc2 = enc2;
10699 fptr->encs.ecflags = ecflags;
10700 fptr->encs.ecopts = ecopts;
10701 clear_codeconv(fptr);
10705 struct io_encoding_set_args {
10706 rb_io_t *fptr;
10707 VALUE v1;
10708 VALUE v2;
10709 VALUE opt;
10712 static VALUE
10713 io_encoding_set_v(VALUE v)
10715 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
10716 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
10717 return Qnil;
10720 static VALUE
10721 pipe_pair_close(VALUE rw)
10723 VALUE *rwp = (VALUE *)rw;
10724 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
10728 * call-seq:
10729 * IO.pipe -> [read_io, write_io]
10730 * IO.pipe(ext_enc) -> [read_io, write_io]
10731 * IO.pipe("ext_enc:int_enc" [, opt]) -> [read_io, write_io]
10732 * IO.pipe(ext_enc, int_enc [, opt]) -> [read_io, write_io]
10734 * IO.pipe(...) {|read_io, write_io| ... }
10736 * Creates a pair of pipe endpoints (connected to each other) and
10737 * returns them as a two-element array of IO objects:
10738 * <code>[</code> <i>read_io</i>, <i>write_io</i> <code>]</code>.
10740 * If a block is given, the block is called and
10741 * returns the value of the block.
10742 * <i>read_io</i> and <i>write_io</i> are sent to the block as arguments.
10743 * If read_io and write_io are not closed when the block exits, they are closed.
10744 * i.e. closing read_io and/or write_io doesn't cause an error.
10746 * Not available on all platforms.
10748 * If an encoding (encoding name or encoding object) is specified as an optional argument,
10749 * read string from pipe is tagged with the encoding specified.
10750 * If the argument is a colon separated two encoding names "A:B",
10751 * the read string is converted from encoding A (external encoding)
10752 * to encoding B (internal encoding), then tagged with B.
10753 * If two optional arguments are specified, those must be
10754 * encoding objects or encoding names,
10755 * and the first one is the external encoding,
10756 * and the second one is the internal encoding.
10757 * If the external encoding and the internal encoding is specified,
10758 * optional hash argument specify the conversion option.
10760 * In the example below, the two processes close the ends of the pipe
10761 * that they are not using. This is not just a cosmetic nicety. The
10762 * read end of a pipe will not generate an end of file condition if
10763 * there are any writers with the pipe still open. In the case of the
10764 * parent process, the <code>rd.read</code> will never return if it
10765 * does not first issue a <code>wr.close</code>.
10767 * rd, wr = IO.pipe
10769 * if fork
10770 * wr.close
10771 * puts "Parent got: <#{rd.read}>"
10772 * rd.close
10773 * Process.wait
10774 * else
10775 * rd.close
10776 * puts "Sending message to parent"
10777 * wr.write "Hi Dad"
10778 * wr.close
10779 * end
10781 * <em>produces:</em>
10783 * Sending message to parent
10784 * Parent got: <Hi Dad>
10787 static VALUE
10788 rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
10790 int pipes[2], state;
10791 VALUE r, w, args[3], v1, v2;
10792 VALUE opt;
10793 rb_io_t *fptr, *fptr2;
10794 struct io_encoding_set_args ies_args;
10795 int fmode = 0;
10796 VALUE ret;
10798 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
10799 if (rb_pipe(pipes) < 0)
10800 rb_sys_fail(0);
10802 args[0] = klass;
10803 args[1] = INT2NUM(pipes[0]);
10804 args[2] = INT2FIX(O_RDONLY);
10805 r = rb_protect(io_new_instance, (VALUE)args, &state);
10806 if (state) {
10807 close(pipes[0]);
10808 close(pipes[1]);
10809 rb_jump_tag(state);
10811 GetOpenFile(r, fptr);
10813 ies_args.fptr = fptr;
10814 ies_args.v1 = v1;
10815 ies_args.v2 = v2;
10816 ies_args.opt = opt;
10817 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
10818 if (state) {
10819 close(pipes[1]);
10820 io_close(r);
10821 rb_jump_tag(state);
10824 args[1] = INT2NUM(pipes[1]);
10825 args[2] = INT2FIX(O_WRONLY);
10826 w = rb_protect(io_new_instance, (VALUE)args, &state);
10827 if (state) {
10828 close(pipes[1]);
10829 if (!NIL_P(r)) rb_io_close(r);
10830 rb_jump_tag(state);
10832 GetOpenFile(w, fptr2);
10833 rb_io_synchronized(fptr2);
10835 extract_binmode(opt, &fmode);
10837 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
10838 rb_io_ascii8bit_binmode(r);
10839 rb_io_ascii8bit_binmode(w);
10842 #if DEFAULT_TEXTMODE
10843 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
10844 fptr->mode &= ~FMODE_TEXTMODE;
10845 setmode(fptr->fd, O_BINARY);
10847 #if RUBY_CRLF_ENVIRONMENT
10848 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
10849 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
10851 #endif
10852 #endif
10853 fptr->mode |= fmode;
10854 #if DEFAULT_TEXTMODE
10855 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
10856 fptr2->mode &= ~FMODE_TEXTMODE;
10857 setmode(fptr2->fd, O_BINARY);
10859 #endif
10860 fptr2->mode |= fmode;
10862 ret = rb_assoc_new(r, w);
10863 if (rb_block_given_p()) {
10864 VALUE rw[2];
10865 rw[0] = r;
10866 rw[1] = w;
10867 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
10869 return ret;
10872 struct foreach_arg {
10873 int argc;
10874 VALUE *argv;
10875 VALUE io;
10878 static void
10879 open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
10881 VALUE path, v;
10882 VALUE vmode = Qnil, vperm = Qnil;
10884 path = *argv++;
10885 argc--;
10886 FilePathValue(path);
10887 arg->io = 0;
10888 arg->argc = argc;
10889 arg->argv = argv;
10890 if (NIL_P(opt)) {
10891 vmode = INT2NUM(O_RDONLY);
10892 vperm = INT2FIX(0666);
10894 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
10895 int n;
10897 v = rb_to_array_type(v);
10898 n = RARRAY_LENINT(v);
10899 rb_check_arity(n, 0, 3); /* rb_io_open */
10900 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
10902 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
10905 static VALUE
10906 io_s_foreach(VALUE v)
10908 struct getline_arg *arg = (void *)v;
10909 VALUE str;
10911 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
10912 rb_lastline_set(str);
10913 rb_yield(str);
10915 rb_lastline_set(Qnil);
10916 return Qnil;
10920 * call-seq:
10921 * IO.foreach(name, sep=$/ [, getline_args, open_args]) {|line| block } -> nil
10922 * IO.foreach(name, limit [, getline_args, open_args]) {|line| block } -> nil
10923 * IO.foreach(name, sep, limit [, getline_args, open_args]) {|line| block } -> nil
10924 * IO.foreach(...) -> an_enumerator
10925 * File.foreach(name, sep=$/ [, getline_args, open_args]) {|line| block } -> nil
10926 * File.foreach(name, limit [, getline_args, open_args]) {|line| block } -> nil
10927 * File.foreach(name, sep, limit [, getline_args, open_args]) {|line| block } -> nil
10928 * File.foreach(...) -> an_enumerator
10930 * Executes the block for every line in the named I/O port, where lines
10931 * are separated by <em>sep</em>.
10933 * If no block is given, an enumerator is returned instead.
10935 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
10936 * is the IO class, a subprocess is created in the same way as Kernel#open,
10937 * and its output is returned.
10938 * Consider to use File.foreach to disable the behavior of subprocess invocation.
10940 * File.foreach("testfile") {|x| print "GOT ", x }
10941 * IO.foreach("| cat testfile") {|x| print "GOT ", x }
10943 * <em>produces:</em>
10945 * GOT This is line one
10946 * GOT This is line two
10947 * GOT This is line three
10948 * GOT And so on...
10950 * If the last argument is a hash, it's the keyword argument to open.
10951 * See IO.readlines for details about getline_args.
10952 * And see also IO.read for details about open_args.
10956 static VALUE
10957 rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
10959 VALUE opt;
10960 int orig_argc = argc;
10961 struct foreach_arg arg;
10962 struct getline_arg garg;
10964 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
10965 RETURN_ENUMERATOR(self, orig_argc, argv);
10966 extract_getline_args(argc-1, argv+1, &garg);
10967 open_key_args(self, argc, argv, opt, &arg);
10968 if (NIL_P(arg.io)) return Qnil;
10969 extract_getline_opts(opt, &garg);
10970 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
10971 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
10974 static VALUE
10975 io_s_readlines(VALUE v)
10977 struct getline_arg *arg = (void *)v;
10978 return io_readlines(arg, arg->io);
10982 * call-seq:
10983 * IO.readlines(name, sep=$/ [, getline_args, open_args]) -> array
10984 * IO.readlines(name, limit [, getline_args, open_args]) -> array
10985 * IO.readlines(name, sep, limit [, getline_args, open_args]) -> array
10986 * File.readlines(name, sep=$/ [, getline_args, open_args]) -> array
10987 * File.readlines(name, limit [, getline_args, open_args]) -> array
10988 * File.readlines(name, sep, limit [, getline_args, open_args]) -> array
10990 * Reads the entire file specified by <i>name</i> as individual
10991 * lines, and returns those lines in an array. Lines are separated by
10992 * <i>sep</i>.
10994 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
10995 * is the IO class, a subprocess is created in the same way as Kernel#open,
10996 * and its output is returned.
10997 * Consider to use File.readlines to disable the behavior of subprocess invocation.
10999 * a = File.readlines("testfile")
11000 * a[0] #=> "This is line one\n"
11002 * b = File.readlines("testfile", chomp: true)
11003 * b[0] #=> "This is line one"
11005 * IO.readlines("|ls -a") #=> [".\n", "..\n", ...]
11007 * If the last argument is a hash, it's the keyword argument to open.
11009 * === Options for getline
11011 * The options hash accepts the following keys:
11013 * :chomp::
11014 * When the optional +chomp+ keyword argument has a true value,
11015 * <code>\n</code>, <code>\r</code>, and <code>\r\n</code>
11016 * will be removed from the end of each line.
11018 * See also IO.read for details about +name+ and open_args.
11021 static VALUE
11022 rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
11024 VALUE opt;
11025 struct foreach_arg arg;
11026 struct getline_arg garg;
11028 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
11029 extract_getline_args(argc-1, argv+1, &garg);
11030 open_key_args(io, argc, argv, opt, &arg);
11031 if (NIL_P(arg.io)) return Qnil;
11032 extract_getline_opts(opt, &garg);
11033 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
11034 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
11037 static VALUE
11038 io_s_read(VALUE v)
11040 struct foreach_arg *arg = (void *)v;
11041 return io_read(arg->argc, arg->argv, arg->io);
11044 struct seek_arg {
11045 VALUE io;
11046 VALUE offset;
11047 int mode;
11050 static VALUE
11051 seek_before_access(VALUE argp)
11053 struct seek_arg *arg = (struct seek_arg *)argp;
11054 rb_io_binmode(arg->io);
11055 return rb_io_seek(arg->io, arg->offset, arg->mode);
11059 * call-seq:
11060 * IO.read(name, [length [, offset]] [, opt]) -> string
11061 * File.read(name, [length [, offset]] [, opt]) -> string
11063 * Opens the file, optionally seeks to the given +offset+, then returns
11064 * +length+ bytes (defaulting to the rest of the file). #read ensures
11065 * the file is closed before returning.
11067 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11068 * is the IO class, a subprocess is created in the same way as Kernel#open,
11069 * and its output is returned.
11070 * Consider to use File.read to disable the behavior of subprocess invocation.
11072 * === Options
11074 * The options hash accepts the following keys:
11076 * :encoding::
11077 * string or encoding
11079 * Specifies the encoding of the read string. +:encoding+ will be ignored
11080 * if +length+ is specified. See Encoding.aliases for possible encodings.
11082 * :mode::
11083 * string or integer
11085 * Specifies the <i>mode</i> argument for open(). It must start
11086 * with an "r", otherwise it will cause an error.
11087 * See IO.new for the list of possible modes.
11089 * :open_args::
11090 * array
11092 * Specifies arguments for open() as an array. This key can not be used
11093 * in combination with either +:encoding+ or +:mode+.
11095 * Examples:
11097 * File.read("testfile") #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
11098 * File.read("testfile", 20) #=> "This is line one\nThi"
11099 * File.read("testfile", 20, 10) #=> "ne one\nThis is line "
11100 * File.read("binfile", mode: "rb") #=> "\xF7\x00\x00\x0E\x12"
11101 * IO.read("|ls -a") #=> ".\n..\n"...
11104 static VALUE
11105 rb_io_s_read(int argc, VALUE *argv, VALUE io)
11107 VALUE opt, offset;
11108 struct foreach_arg arg;
11110 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
11111 open_key_args(io, argc, argv, opt, &arg);
11112 if (NIL_P(arg.io)) return Qnil;
11113 if (!NIL_P(offset)) {
11114 struct seek_arg sarg;
11115 int state = 0;
11116 sarg.io = arg.io;
11117 sarg.offset = offset;
11118 sarg.mode = SEEK_SET;
11119 rb_protect(seek_before_access, (VALUE)&sarg, &state);
11120 if (state) {
11121 rb_io_close(arg.io);
11122 rb_jump_tag(state);
11124 if (arg.argc == 2) arg.argc = 1;
11126 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
11130 * call-seq:
11131 * IO.binread(name, [length [, offset]]) -> string
11132 * File.binread(name, [length [, offset]]) -> string
11134 * Opens the file, optionally seeks to the given <i>offset</i>, then
11135 * returns <i>length</i> bytes (defaulting to the rest of the file).
11136 * #binread ensures the file is closed before returning. The open mode
11137 * would be <code>"rb:ASCII-8BIT"</code>.
11139 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11140 * is the IO class, a subprocess is created in the same way as Kernel#open,
11141 * and its output is returned.
11142 * Consider to use File.binread to disable the behavior of subprocess invocation.
11144 * File.binread("testfile") #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
11145 * File.binread("testfile", 20) #=> "This is line one\nThi"
11146 * File.binread("testfile", 20, 10) #=> "ne one\nThis is line "
11147 * IO.binread("| cat testfile") #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
11149 * See also IO.read for details about +name+ and open_args.
11152 static VALUE
11153 rb_io_s_binread(int argc, VALUE *argv, VALUE io)
11155 VALUE offset;
11156 struct foreach_arg arg;
11157 enum {
11158 fmode = FMODE_READABLE|FMODE_BINMODE,
11159 oflags = O_RDONLY
11160 #ifdef O_BINARY
11161 |O_BINARY
11162 #endif
11164 convconfig_t convconfig = {NULL, NULL, 0, Qnil};
11166 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
11167 FilePathValue(argv[0]);
11168 convconfig.enc = rb_ascii8bit_encoding();
11169 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
11170 if (NIL_P(arg.io)) return Qnil;
11171 arg.argv = argv+1;
11172 arg.argc = (argc > 1) ? 1 : 0;
11173 if (!NIL_P(offset)) {
11174 struct seek_arg sarg;
11175 int state = 0;
11176 sarg.io = arg.io;
11177 sarg.offset = offset;
11178 sarg.mode = SEEK_SET;
11179 rb_protect(seek_before_access, (VALUE)&sarg, &state);
11180 if (state) {
11181 rb_io_close(arg.io);
11182 rb_jump_tag(state);
11185 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
11188 static VALUE
11189 io_s_write0(VALUE v)
11191 struct write_arg *arg = (void *)v;
11192 return io_write(arg->io,arg->str,arg->nosync);
11195 static VALUE
11196 io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
11198 VALUE string, offset, opt;
11199 struct foreach_arg arg;
11200 struct write_arg warg;
11202 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
11204 if (NIL_P(opt)) opt = rb_hash_new();
11205 else opt = rb_hash_dup(opt);
11208 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
11209 int mode = O_WRONLY|O_CREAT;
11210 #ifdef O_BINARY
11211 if (binary) mode |= O_BINARY;
11212 #endif
11213 if (NIL_P(offset)) mode |= O_TRUNC;
11214 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
11216 open_key_args(klass, argc, argv, opt, &arg);
11218 #ifndef O_BINARY
11219 if (binary) rb_io_binmode_m(arg.io);
11220 #endif
11222 if (NIL_P(arg.io)) return Qnil;
11223 if (!NIL_P(offset)) {
11224 struct seek_arg sarg;
11225 int state = 0;
11226 sarg.io = arg.io;
11227 sarg.offset = offset;
11228 sarg.mode = SEEK_SET;
11229 rb_protect(seek_before_access, (VALUE)&sarg, &state);
11230 if (state) {
11231 rb_io_close(arg.io);
11232 rb_jump_tag(state);
11236 warg.io = arg.io;
11237 warg.str = string;
11238 warg.nosync = 0;
11240 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
11244 * call-seq:
11245 * IO.write(name, string [, offset]) -> integer
11246 * IO.write(name, string [, offset] [, opt]) -> integer
11247 * File.write(name, string [, offset]) -> integer
11248 * File.write(name, string [, offset] [, opt]) -> integer
11250 * Opens the file, optionally seeks to the given <i>offset</i>, writes
11251 * <i>string</i>, then returns the length written. #write ensures the
11252 * file is closed before returning. If <i>offset</i> is not given in
11253 * write mode, the file is truncated. Otherwise, it is not truncated.
11255 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11256 * is the IO class, a subprocess is created in the same way as Kernel#open,
11257 * and its output is returned.
11258 * Consider to use File.write to disable the behavior of subprocess invocation.
11260 * File.write("testfile", "0123456789", 20) #=> 10
11261 * # File could contain: "This is line one\nThi0123456789two\nThis is line three\nAnd so on...\n"
11262 * File.write("testfile", "0123456789") #=> 10
11263 * # File would now read: "0123456789"
11264 * IO.write("|tr a-z A-Z", "abc") #=> 3
11265 * # Prints "ABC" to the standard output
11267 * If the last argument is a hash, it specifies options for the internal
11268 * open(). It accepts the following keys:
11270 * :encoding::
11271 * string or encoding
11273 * Specifies the encoding of the read string.
11274 * See Encoding.aliases for possible encodings.
11276 * :mode::
11277 * string or integer
11279 * Specifies the <i>mode</i> argument for open(). It must start
11280 * with "w", "a", or "r+", otherwise it will cause an error.
11281 * See IO.new for the list of possible modes.
11283 * :perm::
11284 * integer
11286 * Specifies the <i>perm</i> argument for open().
11288 * :open_args::
11289 * array
11291 * Specifies arguments for open() as an array.
11292 * This key can not be used in combination with other keys.
11294 * See also IO.read for details about +name+ and open_args.
11297 static VALUE
11298 rb_io_s_write(int argc, VALUE *argv, VALUE io)
11300 return io_s_write(argc, argv, io, 0);
11304 * call-seq:
11305 * IO.binwrite(name, string, [offset]) -> integer
11306 * IO.binwrite(name, string, [offset], open_args) -> integer
11307 * File.binwrite(name, string, [offset]) -> integer
11308 * File.binwrite(name, string, [offset], open_args) -> integer
11310 * Same as IO.write except opening the file in binary mode and
11311 * ASCII-8BIT encoding (<code>"wb:ASCII-8BIT"</code>).
11313 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11314 * is the IO class, a subprocess is created in the same way as Kernel#open,
11315 * and its output is returned.
11316 * Consider to use File.binwrite to disable the behavior of subprocess invocation.
11318 * See also IO.read for details about +name+ and open_args.
11321 static VALUE
11322 rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
11324 return io_s_write(argc, argv, io, 1);
11327 struct copy_stream_struct {
11328 VALUE src;
11329 VALUE dst;
11330 off_t copy_length; /* (off_t)-1 if not specified */
11331 off_t src_offset; /* (off_t)-1 if not specified */
11333 rb_io_t *src_fptr;
11334 rb_io_t *dst_fptr;
11335 unsigned close_src : 1;
11336 unsigned close_dst : 1;
11337 int error_no;
11338 off_t total;
11339 const char *syserr;
11340 const char *notimp;
11341 VALUE th;
11342 struct stat src_stat;
11343 struct stat dst_stat;
11344 #ifdef HAVE_FCOPYFILE
11345 copyfile_state_t copyfile_state;
11346 #endif
11349 static void *
11350 exec_interrupts(void *arg)
11352 VALUE th = (VALUE)arg;
11353 rb_thread_execute_interrupts(th);
11354 return NULL;
11358 * returns TRUE if the preceding system call was interrupted
11359 * so we can continue. If the thread was interrupted, we
11360 * reacquire the GVL to execute interrupts before continuing.
11362 static int
11363 maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
11365 switch (errno) {
11366 case EINTR:
11367 #if defined(ERESTART)
11368 case ERESTART:
11369 #endif
11370 if (rb_thread_interrupted(stp->th)) {
11371 if (has_gvl)
11372 rb_thread_execute_interrupts(stp->th);
11373 else
11374 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
11376 return TRUE;
11378 return FALSE;
11381 struct wait_for_single_fd {
11382 VALUE scheduler;
11384 rb_io_t *fptr;
11385 short events;
11387 VALUE result;
11390 static void *
11391 rb_thread_fiber_scheduler_wait_for(void * _args)
11393 struct wait_for_single_fd *args = (struct wait_for_single_fd *)_args;
11395 args->result = rb_fiber_scheduler_io_wait(args->scheduler, args->fptr->self, INT2NUM(args->events), Qnil);
11397 return NULL;
11400 #if USE_POLL
11401 # define IOWAIT_SYSCALL "poll"
11402 STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
11403 STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
11404 static int
11405 nogvl_wait_for(VALUE th, rb_io_t *fptr, short events)
11407 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
11408 if (scheduler != Qnil) {
11409 struct wait_for_single_fd args = {.scheduler = scheduler, .fptr = fptr, .events = events};
11410 rb_thread_call_with_gvl(rb_thread_fiber_scheduler_wait_for, &args);
11411 return RTEST(args.result);
11414 int fd = fptr->fd;
11415 if (fd == -1) return 0;
11417 struct pollfd fds;
11419 fds.fd = fd;
11420 fds.events = events;
11422 return poll(&fds, 1, -1);
11424 #else /* !USE_POLL */
11425 # define IOWAIT_SYSCALL "select"
11426 static int
11427 nogvl_wait_for(VALUE th, rb_io_t *fptr, short events)
11429 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
11430 if (scheduler != Qnil) {
11431 struct wait_for_single_fd args = {.scheduler = scheduler, .fptr = fptr, .events = events};
11432 rb_thread_call_with_gvl(rb_thread_fiber_scheduler_wait_for, &args);
11433 return RTEST(args.result);
11436 int fd = fptr->fd;
11437 if (fd == -1) return 0;
11439 rb_fdset_t fds;
11440 int ret;
11442 rb_fd_init(&fds);
11443 rb_fd_set(fd, &fds);
11445 switch (events) {
11446 case RB_WAITFD_IN:
11447 ret = rb_fd_select(fd + 1, &fds, 0, 0, 0);
11448 break;
11449 case RB_WAITFD_OUT:
11450 ret = rb_fd_select(fd + 1, 0, &fds, 0, 0);
11451 break;
11452 default:
11453 VM_UNREACHABLE(nogvl_wait_for);
11456 rb_fd_term(&fds);
11457 return ret;
11459 #endif /* !USE_POLL */
11461 static int
11462 maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
11464 int ret;
11466 do {
11467 if (has_gvl) {
11468 ret = RB_NUM2INT(rb_io_wait(stp->src, RB_INT2NUM(RUBY_IO_READABLE), Qnil));
11470 else {
11471 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN);
11473 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
11475 if (ret < 0) {
11476 stp->syserr = IOWAIT_SYSCALL;
11477 stp->error_no = errno;
11478 return ret;
11480 return 0;
11483 static int
11484 nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
11486 int ret;
11488 do {
11489 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT);
11490 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
11492 if (ret < 0) {
11493 stp->syserr = IOWAIT_SYSCALL;
11494 stp->error_no = errno;
11495 return ret;
11497 return 0;
11500 #ifdef USE_COPY_FILE_RANGE
11502 static ssize_t
11503 simple_copy_file_range(int in_fd, off_t *in_offset, int out_fd, off_t *out_offset, size_t count, unsigned int flags)
11505 #ifdef HAVE_COPY_FILE_RANGE
11506 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
11507 #else
11508 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
11509 #endif
11512 static int
11513 nogvl_copy_file_range(struct copy_stream_struct *stp)
11515 ssize_t ss;
11516 off_t src_size;
11517 off_t copy_length, src_offset, *src_offset_ptr;
11519 if (!S_ISREG(stp->src_stat.st_mode))
11520 return 0;
11522 src_size = stp->src_stat.st_size;
11523 src_offset = stp->src_offset;
11524 if (src_offset >= (off_t)0) {
11525 src_offset_ptr = &src_offset;
11527 else {
11528 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
11531 copy_length = stp->copy_length;
11532 if (copy_length < (off_t)0) {
11533 if (src_offset < (off_t)0) {
11534 off_t current_offset;
11535 errno = 0;
11536 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
11537 if (current_offset < (off_t)0 && errno) {
11538 stp->syserr = "lseek";
11539 stp->error_no = errno;
11540 return (int)current_offset;
11542 copy_length = src_size - current_offset;
11544 else {
11545 copy_length = src_size - src_offset;
11549 retry_copy_file_range:
11550 # if SIZEOF_OFF_T > SIZEOF_SIZE_T
11551 /* we are limited by the 32-bit ssize_t return value on 32-bit */
11552 ss = (copy_length > (off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
11553 # else
11554 ss = (ssize_t)copy_length;
11555 # endif
11556 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
11557 if (0 < ss) {
11558 stp->total += ss;
11559 copy_length -= ss;
11560 if (0 < copy_length) {
11561 goto retry_copy_file_range;
11564 if (ss < 0) {
11565 if (maygvl_copy_stream_continue_p(0, stp)) {
11566 goto retry_copy_file_range;
11568 switch (errno) {
11569 case EINVAL:
11570 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
11571 docker container) */
11572 #ifdef ENOSYS
11573 case ENOSYS:
11574 #endif
11575 #ifdef EXDEV
11576 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
11577 #endif
11578 return 0;
11579 case EAGAIN:
11580 #if EWOULDBLOCK != EAGAIN
11581 case EWOULDBLOCK:
11582 #endif
11584 int ret = nogvl_copy_stream_wait_write(stp);
11585 if (ret < 0) return ret;
11587 goto retry_copy_file_range;
11588 case EBADF:
11590 int e = errno;
11591 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
11593 if (flags != -1 && flags & O_APPEND) {
11594 return 0;
11596 errno = e;
11599 stp->syserr = "copy_file_range";
11600 stp->error_no = errno;
11601 return (int)ss;
11603 return 1;
11605 #endif
11607 #ifdef HAVE_FCOPYFILE
11608 static int
11609 nogvl_fcopyfile(struct copy_stream_struct *stp)
11611 off_t cur, ss = 0;
11612 const off_t src_offset = stp->src_offset;
11613 int ret;
11615 if (stp->copy_length >= (off_t)0) {
11616 /* copy_length can't be specified in fcopyfile(3) */
11617 return 0;
11620 if (!S_ISREG(stp->src_stat.st_mode))
11621 return 0;
11623 if (!S_ISREG(stp->dst_stat.st_mode))
11624 return 0;
11625 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (off_t)0) /* if dst IO was already written */
11626 return 0;
11627 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
11628 /* fcopyfile(3) appends src IO to dst IO and then truncates
11629 * dst IO to src IO's original size. */
11630 off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
11631 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
11632 if (end > (off_t)0) return 0;
11635 if (src_offset > (off_t)0) {
11636 off_t r;
11638 /* get current offset */
11639 errno = 0;
11640 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
11641 if (cur < (off_t)0 && errno) {
11642 stp->error_no = errno;
11643 return 1;
11646 errno = 0;
11647 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
11648 if (r < (off_t)0 && errno) {
11649 stp->error_no = errno;
11650 return 1;
11654 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
11655 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
11656 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
11658 if (ret == 0) { /* success */
11659 stp->total = ss;
11660 if (src_offset > (off_t)0) {
11661 off_t r;
11662 errno = 0;
11663 /* reset offset */
11664 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
11665 if (r < (off_t)0 && errno) {
11666 stp->error_no = errno;
11667 return 1;
11671 else {
11672 switch (errno) {
11673 case ENOTSUP:
11674 case EPERM:
11675 case EINVAL:
11676 return 0;
11678 stp->syserr = "fcopyfile";
11679 stp->error_no = errno;
11680 return (int)ret;
11682 return 1;
11684 #endif
11686 #ifdef HAVE_SENDFILE
11688 # ifdef __linux__
11689 # define USE_SENDFILE
11691 # ifdef HAVE_SYS_SENDFILE_H
11692 # include <sys/sendfile.h>
11693 # endif
11695 static ssize_t
11696 simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count)
11698 return sendfile(out_fd, in_fd, offset, (size_t)count);
11701 # elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
11702 /* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
11703 * without cpuset -l 0.
11705 # define USE_SENDFILE
11707 static ssize_t
11708 simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count)
11710 int r;
11711 off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
11712 off_t sbytes;
11713 # ifdef __APPLE__
11714 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
11715 sbytes = count;
11716 # else
11717 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
11718 # endif
11719 if (r != 0 && sbytes == 0) return r;
11720 if (offset) {
11721 *offset += sbytes;
11723 else {
11724 lseek(in_fd, sbytes, SEEK_CUR);
11726 return (ssize_t)sbytes;
11729 # endif
11731 #endif
11733 #ifdef USE_SENDFILE
11734 static int
11735 nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
11737 ssize_t ss;
11738 off_t src_size;
11739 off_t copy_length;
11740 off_t src_offset;
11741 int use_pread;
11743 if (!S_ISREG(stp->src_stat.st_mode))
11744 return 0;
11746 src_size = stp->src_stat.st_size;
11747 #ifndef __linux__
11748 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
11749 return 0;
11750 #endif
11752 src_offset = stp->src_offset;
11753 use_pread = src_offset >= (off_t)0;
11755 copy_length = stp->copy_length;
11756 if (copy_length < (off_t)0) {
11757 if (use_pread)
11758 copy_length = src_size - src_offset;
11759 else {
11760 off_t cur;
11761 errno = 0;
11762 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
11763 if (cur < (off_t)0 && errno) {
11764 stp->syserr = "lseek";
11765 stp->error_no = errno;
11766 return (int)cur;
11768 copy_length = src_size - cur;
11772 retry_sendfile:
11773 # if SIZEOF_OFF_T > SIZEOF_SIZE_T
11774 /* we are limited by the 32-bit ssize_t return value on 32-bit */
11775 ss = (copy_length > (off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
11776 # else
11777 ss = (ssize_t)copy_length;
11778 # endif
11779 if (use_pread) {
11780 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
11782 else {
11783 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
11785 if (0 < ss) {
11786 stp->total += ss;
11787 copy_length -= ss;
11788 if (0 < copy_length) {
11789 goto retry_sendfile;
11792 if (ss < 0) {
11793 if (maygvl_copy_stream_continue_p(0, stp))
11794 goto retry_sendfile;
11795 switch (errno) {
11796 case EINVAL:
11797 #ifdef ENOSYS
11798 case ENOSYS:
11799 #endif
11800 #ifdef EOPNOTSUP
11801 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
11802 see also: [Feature #16965] */
11803 case EOPNOTSUP:
11804 #endif
11805 return 0;
11806 case EAGAIN:
11807 #if EWOULDBLOCK != EAGAIN
11808 case EWOULDBLOCK:
11809 #endif
11811 int ret;
11812 #ifndef __linux__
11814 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
11815 * select() reports regular files to always be "ready", so
11816 * there is no need to select() on it.
11817 * Other OSes may have the same limitation for sendfile() which
11818 * allow us to bypass maygvl_copy_stream_wait_read()...
11820 ret = maygvl_copy_stream_wait_read(0, stp);
11821 if (ret < 0) return ret;
11822 #endif
11823 ret = nogvl_copy_stream_wait_write(stp);
11824 if (ret < 0) return ret;
11826 goto retry_sendfile;
11828 stp->syserr = "sendfile";
11829 stp->error_no = errno;
11830 return (int)ss;
11832 return 1;
11834 #endif
11836 static ssize_t
11837 maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
11839 if (has_gvl)
11840 return rb_read_internal(fptr, buf, count);
11841 else
11842 return read(fptr->fd, buf, count);
11845 static ssize_t
11846 maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, off_t offset)
11848 ssize_t ss;
11849 retry_read:
11850 if (offset < (off_t)0) {
11851 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
11853 else {
11854 #ifdef HAVE_PREAD
11855 ss = pread(stp->src_fptr->fd, buf, len, offset);
11856 #else
11857 stp->notimp = "pread";
11858 return -1;
11859 #endif
11861 if (ss == 0) {
11862 return 0;
11864 if (ss < 0) {
11865 if (maygvl_copy_stream_continue_p(has_gvl, stp))
11866 goto retry_read;
11867 switch (errno) {
11868 case EAGAIN:
11869 #if EWOULDBLOCK != EAGAIN
11870 case EWOULDBLOCK:
11871 #endif
11873 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
11874 if (ret < 0) return ret;
11876 goto retry_read;
11877 #ifdef ENOSYS
11878 case ENOSYS:
11879 stp->notimp = "pread";
11880 return ss;
11881 #endif
11883 stp->syserr = offset < (off_t)0 ? "read" : "pread";
11884 stp->error_no = errno;
11886 return ss;
11889 static int
11890 nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
11892 ssize_t ss;
11893 int off = 0;
11894 while (len) {
11895 ss = write(stp->dst_fptr->fd, buf+off, len);
11896 if (ss < 0) {
11897 if (maygvl_copy_stream_continue_p(0, stp))
11898 continue;
11899 if (io_again_p(errno)) {
11900 int ret = nogvl_copy_stream_wait_write(stp);
11901 if (ret < 0) return ret;
11902 continue;
11904 stp->syserr = "write";
11905 stp->error_no = errno;
11906 return (int)ss;
11908 off += (int)ss;
11909 len -= (int)ss;
11910 stp->total += ss;
11912 return 0;
11915 static void
11916 nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
11918 char buf[1024*16];
11919 size_t len;
11920 ssize_t ss;
11921 int ret;
11922 off_t copy_length;
11923 int use_eof;
11924 off_t src_offset;
11925 int use_pread;
11927 copy_length = stp->copy_length;
11928 use_eof = copy_length < (off_t)0;
11929 src_offset = stp->src_offset;
11930 use_pread = src_offset >= (off_t)0;
11932 if (use_pread && stp->close_src) {
11933 off_t r;
11934 errno = 0;
11935 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
11936 if (r < (off_t)0 && errno) {
11937 stp->syserr = "lseek";
11938 stp->error_no = errno;
11939 return;
11941 src_offset = (off_t)-1;
11942 use_pread = 0;
11945 while (use_eof || 0 < copy_length) {
11946 if (!use_eof && copy_length < (off_t)sizeof(buf)) {
11947 len = (size_t)copy_length;
11949 else {
11950 len = sizeof(buf);
11952 if (use_pread) {
11953 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
11954 if (0 < ss)
11955 src_offset += ss;
11957 else {
11958 ss = maygvl_copy_stream_read(0, stp, buf, len, (off_t)-1);
11960 if (ss <= 0) /* EOF or error */
11961 return;
11963 ret = nogvl_copy_stream_write(stp, buf, ss);
11964 if (ret < 0)
11965 return;
11967 if (!use_eof)
11968 copy_length -= ss;
11972 static void *
11973 nogvl_copy_stream_func(void *arg)
11975 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
11976 #if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
11977 int ret;
11978 #endif
11980 #ifdef USE_COPY_FILE_RANGE
11981 ret = nogvl_copy_file_range(stp);
11982 if (ret != 0)
11983 goto finish; /* error or success */
11984 #endif
11986 #ifdef HAVE_FCOPYFILE
11987 ret = nogvl_fcopyfile(stp);
11988 if (ret != 0)
11989 goto finish; /* error or success */
11990 #endif
11992 #ifdef USE_SENDFILE
11993 ret = nogvl_copy_stream_sendfile(stp);
11994 if (ret != 0)
11995 goto finish; /* error or success */
11996 #endif
11998 nogvl_copy_stream_read_write(stp);
12000 #if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
12001 finish:
12002 #endif
12003 return 0;
12006 static VALUE
12007 copy_stream_fallback_body(VALUE arg)
12009 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
12010 const int buflen = 16*1024;
12011 VALUE n;
12012 VALUE buf = rb_str_buf_new(buflen);
12013 off_t rest = stp->copy_length;
12014 off_t off = stp->src_offset;
12015 ID read_method = id_readpartial;
12017 if (!stp->src_fptr) {
12018 if (!rb_respond_to(stp->src, read_method)) {
12019 read_method = id_read;
12023 while (1) {
12024 long numwrote;
12025 long l;
12026 if (stp->copy_length < (off_t)0) {
12027 l = buflen;
12029 else {
12030 if (rest == 0) {
12031 rb_str_resize(buf, 0);
12032 break;
12034 l = buflen < rest ? buflen : (long)rest;
12036 if (!stp->src_fptr) {
12037 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
12039 if (read_method == id_read && NIL_P(rc))
12040 break;
12042 else {
12043 ssize_t ss;
12044 rb_str_resize(buf, buflen);
12045 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
12046 rb_str_resize(buf, ss > 0 ? ss : 0);
12047 if (ss < 0)
12048 return Qnil;
12049 if (ss == 0)
12050 rb_eof_error();
12051 if (off >= (off_t)0)
12052 off += ss;
12054 n = rb_io_write(stp->dst, buf);
12055 numwrote = NUM2LONG(n);
12056 stp->total += numwrote;
12057 rest -= numwrote;
12058 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
12059 break;
12063 return Qnil;
12066 static VALUE
12067 copy_stream_fallback(struct copy_stream_struct *stp)
12069 if (!stp->src_fptr && stp->src_offset >= (off_t)0) {
12070 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
12072 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
12073 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
12074 rb_eEOFError, (VALUE)0);
12075 return Qnil;
12078 static VALUE
12079 copy_stream_body(VALUE arg)
12081 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
12082 VALUE src_io = stp->src, dst_io = stp->dst;
12083 const int common_oflags = 0
12084 #ifdef O_NOCTTY
12085 | O_NOCTTY
12086 #endif
12089 stp->th = rb_thread_current();
12091 stp->total = 0;
12093 if (src_io == argf ||
12094 !(RB_TYPE_P(src_io, T_FILE) ||
12095 RB_TYPE_P(src_io, T_STRING) ||
12096 rb_respond_to(src_io, rb_intern("to_path")))) {
12097 stp->src_fptr = NULL;
12099 else {
12100 int stat_ret;
12101 VALUE tmp_io = rb_io_check_io(src_io);
12102 if (!NIL_P(tmp_io)) {
12103 src_io = tmp_io;
12105 else if (!RB_TYPE_P(src_io, T_FILE)) {
12106 VALUE args[2];
12107 FilePathValue(src_io);
12108 args[0] = src_io;
12109 args[1] = INT2NUM(O_RDONLY|common_oflags);
12110 src_io = rb_class_new_instance(2, args, rb_cFile);
12111 stp->src = src_io;
12112 stp->close_src = 1;
12114 RB_IO_POINTER(src_io, stp->src_fptr);
12115 rb_io_check_byte_readable(stp->src_fptr);
12117 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
12118 if (stat_ret < 0) {
12119 stp->syserr = "fstat";
12120 stp->error_no = errno;
12121 return Qnil;
12125 if (dst_io == argf ||
12126 !(RB_TYPE_P(dst_io, T_FILE) ||
12127 RB_TYPE_P(dst_io, T_STRING) ||
12128 rb_respond_to(dst_io, rb_intern("to_path")))) {
12129 stp->dst_fptr = NULL;
12131 else {
12132 int stat_ret;
12133 VALUE tmp_io = rb_io_check_io(dst_io);
12134 if (!NIL_P(tmp_io)) {
12135 dst_io = GetWriteIO(tmp_io);
12137 else if (!RB_TYPE_P(dst_io, T_FILE)) {
12138 VALUE args[3];
12139 FilePathValue(dst_io);
12140 args[0] = dst_io;
12141 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
12142 args[2] = INT2FIX(0666);
12143 dst_io = rb_class_new_instance(3, args, rb_cFile);
12144 stp->dst = dst_io;
12145 stp->close_dst = 1;
12147 else {
12148 dst_io = GetWriteIO(dst_io);
12149 stp->dst = dst_io;
12151 RB_IO_POINTER(dst_io, stp->dst_fptr);
12152 rb_io_check_writable(stp->dst_fptr);
12154 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
12155 if (stat_ret < 0) {
12156 stp->syserr = "fstat";
12157 stp->error_no = errno;
12158 return Qnil;
12162 #ifdef O_BINARY
12163 if (stp->src_fptr)
12164 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
12165 #endif
12166 if (stp->dst_fptr)
12167 io_ascii8bit_binmode(stp->dst_fptr);
12169 if (stp->src_offset < (off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
12170 size_t len = stp->src_fptr->rbuf.len;
12171 VALUE str;
12172 if (stp->copy_length >= (off_t)0 && stp->copy_length < (off_t)len) {
12173 len = (size_t)stp->copy_length;
12175 str = rb_str_buf_new(len);
12176 rb_str_resize(str,len);
12177 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
12178 if (stp->dst_fptr) { /* IO or filename */
12179 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
12180 rb_sys_fail_on_write(stp->dst_fptr);
12182 else /* others such as StringIO */
12183 rb_io_write(dst_io, str);
12184 rb_str_resize(str, 0);
12185 stp->total += len;
12186 if (stp->copy_length >= (off_t)0)
12187 stp->copy_length -= len;
12190 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
12191 rb_raise(rb_eIOError, "flush failed");
12194 if (stp->copy_length == 0)
12195 return Qnil;
12197 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
12198 return copy_stream_fallback(stp);
12201 rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
12202 return Qnil;
12205 static VALUE
12206 copy_stream_finalize(VALUE arg)
12208 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
12210 #ifdef HAVE_FCOPYFILE
12211 if (stp->copyfile_state) {
12212 copyfile_state_free(stp->copyfile_state);
12214 #endif
12216 if (stp->close_src) {
12217 rb_io_close_m(stp->src);
12219 if (stp->close_dst) {
12220 rb_io_close_m(stp->dst);
12222 if (stp->syserr) {
12223 rb_syserr_fail(stp->error_no, stp->syserr);
12225 if (stp->notimp) {
12226 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
12228 return Qnil;
12232 * call-seq:
12233 * IO.copy_stream(src, dst)
12234 * IO.copy_stream(src, dst, copy_length)
12235 * IO.copy_stream(src, dst, copy_length, src_offset)
12237 * IO.copy_stream copies <i>src</i> to <i>dst</i>.
12238 * <i>src</i> and <i>dst</i> is either a filename or an IO-like object.
12239 * IO-like object for <i>src</i> should have #readpartial or #read
12240 * method. IO-like object for <i>dst</i> should have #write method.
12241 * (Specialized mechanisms, such as sendfile system call, may be used
12242 * on appropriate situation.)
12244 * This method returns the number of bytes copied.
12246 * If optional arguments are not given,
12247 * the start position of the copy is
12248 * the beginning of the filename or
12249 * the current file offset of the IO.
12250 * The end position of the copy is the end of file.
12252 * If <i>copy_length</i> is given,
12253 * No more than <i>copy_length</i> bytes are copied.
12255 * If <i>src_offset</i> is given,
12256 * it specifies the start position of the copy.
12258 * When <i>src_offset</i> is specified and
12259 * <i>src</i> is an IO,
12260 * IO.copy_stream doesn't move the current file offset.
12263 static VALUE
12264 rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
12266 VALUE src, dst, length, src_offset;
12267 struct copy_stream_struct st;
12269 MEMZERO(&st, struct copy_stream_struct, 1);
12271 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
12273 st.src = src;
12274 st.dst = dst;
12276 st.src_fptr = NULL;
12277 st.dst_fptr = NULL;
12279 if (NIL_P(length))
12280 st.copy_length = (off_t)-1;
12281 else
12282 st.copy_length = NUM2OFFT(length);
12284 if (NIL_P(src_offset))
12285 st.src_offset = (off_t)-1;
12286 else
12287 st.src_offset = NUM2OFFT(src_offset);
12289 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
12291 return OFFT2NUM(st.total);
12295 * call-seq:
12296 * io.external_encoding -> encoding
12298 * Returns the Encoding object that represents the encoding of the file.
12299 * If _io_ is in write mode and no encoding is specified, returns +nil+.
12302 static VALUE
12303 rb_io_external_encoding(VALUE io)
12305 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
12307 if (fptr->encs.enc2) {
12308 return rb_enc_from_encoding(fptr->encs.enc2);
12310 if (fptr->mode & FMODE_WRITABLE) {
12311 if (fptr->encs.enc)
12312 return rb_enc_from_encoding(fptr->encs.enc);
12313 return Qnil;
12315 return rb_enc_from_encoding(io_read_encoding(fptr));
12319 * call-seq:
12320 * io.internal_encoding -> encoding
12322 * Returns the Encoding of the internal string if conversion is
12323 * specified. Otherwise returns +nil+.
12326 static VALUE
12327 rb_io_internal_encoding(VALUE io)
12329 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
12331 if (!fptr->encs.enc2) return Qnil;
12332 return rb_enc_from_encoding(io_read_encoding(fptr));
12336 * call-seq:
12337 * io.set_encoding(ext_enc) -> io
12338 * io.set_encoding("ext_enc:int_enc") -> io
12339 * io.set_encoding(ext_enc, int_enc) -> io
12340 * io.set_encoding("ext_enc:int_enc", opt) -> io
12341 * io.set_encoding(ext_enc, int_enc, opt) -> io
12343 * If single argument is specified, read string from io is tagged
12344 * with the encoding specified. If encoding is a colon separated two
12345 * encoding names "A:B", the read string is converted from encoding A
12346 * (external encoding) to encoding B (internal encoding), then tagged
12347 * with B. If two arguments are specified, those must be encoding
12348 * objects or encoding names, and the first one is the external encoding, and the
12349 * second one is the internal encoding.
12350 * If the external encoding and the internal encoding is specified,
12351 * optional hash argument specify the conversion option.
12354 static VALUE
12355 rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
12357 rb_io_t *fptr;
12358 VALUE v1, v2, opt;
12360 if (!RB_TYPE_P(io, T_FILE)) {
12361 return forward(io, id_set_encoding, argc, argv);
12364 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
12365 GetOpenFile(io, fptr);
12366 io_encoding_set(fptr, v1, v2, opt);
12367 return io;
12370 void
12371 rb_stdio_set_default_encoding(void)
12373 VALUE val = Qnil;
12375 #ifdef _WIN32
12376 if (isatty(fileno(stdin))) {
12377 rb_encoding *external = rb_locale_encoding();
12378 rb_encoding *internal = rb_default_internal_encoding();
12379 if (!internal) internal = rb_default_external_encoding();
12380 io_encoding_set(RFILE(rb_stdin)->fptr,
12381 rb_enc_from_encoding(external),
12382 rb_enc_from_encoding(internal),
12383 Qnil);
12385 else
12386 #endif
12387 rb_io_set_encoding(1, &val, rb_stdin);
12388 rb_io_set_encoding(1, &val, rb_stdout);
12389 rb_io_set_encoding(1, &val, rb_stderr);
12392 static inline int
12393 global_argf_p(VALUE arg)
12395 return arg == argf;
12399 * call-seq:
12400 * ARGF.external_encoding -> encoding
12402 * Returns the external encoding for files read from +ARGF+ as an +Encoding+
12403 * object. The external encoding is the encoding of the text as stored in a
12404 * file. Contrast with +ARGF.internal_encoding+, which is the encoding used
12405 * to represent this text within Ruby.
12407 * To set the external encoding use +ARGF.set_encoding+.
12409 * For example:
12411 * ARGF.external_encoding #=> #<Encoding:UTF-8>
12414 static VALUE
12415 argf_external_encoding(VALUE argf)
12417 if (!RTEST(ARGF.current_file)) {
12418 return rb_enc_from_encoding(rb_default_external_encoding());
12420 return rb_io_external_encoding(rb_io_check_io(ARGF.current_file));
12424 * call-seq:
12425 * ARGF.internal_encoding -> encoding
12427 * Returns the internal encoding for strings read from +ARGF+ as an
12428 * +Encoding+ object.
12430 * If +ARGF.set_encoding+ has been called with two encoding names, the second
12431 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
12432 * value is returned. Failing that, if a default external encoding was
12433 * specified on the command-line, that value is used. If the encoding is
12434 * unknown, +nil+ is returned.
12436 static VALUE
12437 argf_internal_encoding(VALUE argf)
12439 if (!RTEST(ARGF.current_file)) {
12440 return rb_enc_from_encoding(rb_default_external_encoding());
12442 return rb_io_internal_encoding(rb_io_check_io(ARGF.current_file));
12446 * call-seq:
12447 * ARGF.set_encoding(ext_enc) -> ARGF
12448 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
12449 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
12450 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
12451 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
12453 * If single argument is specified, strings read from ARGF are tagged with
12454 * the encoding specified.
12456 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
12457 * the read string is converted from the first encoding (external encoding)
12458 * to the second encoding (internal encoding), then tagged with the second
12459 * encoding.
12461 * If two arguments are specified, they must be encoding objects or encoding
12462 * names. Again, the first specifies the external encoding; the second
12463 * specifies the internal encoding.
12465 * If the external encoding and the internal encoding are specified, the
12466 * optional +Hash+ argument can be used to adjust the conversion process. The
12467 * structure of this hash is explained in the String#encode documentation.
12469 * For example:
12471 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
12472 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
12473 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
12474 * # to UTF-8.
12476 static VALUE
12477 argf_set_encoding(int argc, VALUE *argv, VALUE argf)
12479 rb_io_t *fptr;
12481 if (!next_argv()) {
12482 rb_raise(rb_eArgError, "no stream to set encoding");
12484 rb_io_set_encoding(argc, argv, ARGF.current_file);
12485 GetOpenFile(ARGF.current_file, fptr);
12486 ARGF.encs = fptr->encs;
12487 return argf;
12491 * call-seq:
12492 * ARGF.tell -> Integer
12493 * ARGF.pos -> Integer
12495 * Returns the current offset (in bytes) of the current file in +ARGF+.
12497 * ARGF.pos #=> 0
12498 * ARGF.gets #=> "This is line one\n"
12499 * ARGF.pos #=> 17
12502 static VALUE
12503 argf_tell(VALUE argf)
12505 if (!next_argv()) {
12506 rb_raise(rb_eArgError, "no stream to tell");
12508 ARGF_FORWARD(0, 0);
12509 return rb_io_tell(ARGF.current_file);
12513 * call-seq:
12514 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
12516 * Seeks to offset _amount_ (an +Integer+) in the +ARGF+ stream according to
12517 * the value of _whence_. See IO#seek for further details.
12519 static VALUE
12520 argf_seek_m(int argc, VALUE *argv, VALUE argf)
12522 if (!next_argv()) {
12523 rb_raise(rb_eArgError, "no stream to seek");
12525 ARGF_FORWARD(argc, argv);
12526 return rb_io_seek_m(argc, argv, ARGF.current_file);
12530 * call-seq:
12531 * ARGF.pos = position -> Integer
12533 * Seeks to the position given by _position_ (in bytes) in +ARGF+.
12535 * For example:
12537 * ARGF.pos = 17
12538 * ARGF.gets #=> "This is line two\n"
12540 static VALUE
12541 argf_set_pos(VALUE argf, VALUE offset)
12543 if (!next_argv()) {
12544 rb_raise(rb_eArgError, "no stream to set position");
12546 ARGF_FORWARD(1, &offset);
12547 return rb_io_set_pos(ARGF.current_file, offset);
12551 * call-seq:
12552 * ARGF.rewind -> 0
12554 * Positions the current file to the beginning of input, resetting
12555 * +ARGF.lineno+ to zero.
12557 * ARGF.readline #=> "This is line one\n"
12558 * ARGF.rewind #=> 0
12559 * ARGF.lineno #=> 0
12560 * ARGF.readline #=> "This is line one\n"
12562 static VALUE
12563 argf_rewind(VALUE argf)
12565 VALUE ret;
12566 int old_lineno;
12568 if (!next_argv()) {
12569 rb_raise(rb_eArgError, "no stream to rewind");
12571 ARGF_FORWARD(0, 0);
12572 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
12573 ret = rb_io_rewind(ARGF.current_file);
12574 if (!global_argf_p(argf)) {
12575 ARGF.last_lineno = ARGF.lineno -= old_lineno;
12577 return ret;
12581 * call-seq:
12582 * ARGF.fileno -> integer
12583 * ARGF.to_i -> integer
12585 * Returns an integer representing the numeric file descriptor for
12586 * the current file. Raises an +ArgumentError+ if there isn't a current file.
12588 * ARGF.fileno #=> 3
12590 static VALUE
12591 argf_fileno(VALUE argf)
12593 if (!next_argv()) {
12594 rb_raise(rb_eArgError, "no stream");
12596 ARGF_FORWARD(0, 0);
12597 return rb_io_fileno(ARGF.current_file);
12601 * call-seq:
12602 * ARGF.to_io -> IO
12604 * Returns an +IO+ object representing the current file. This will be a
12605 * +File+ object unless the current file is a stream such as STDIN.
12607 * For example:
12609 * ARGF.to_io #=> #<File:glark.txt>
12610 * ARGF.to_io #=> #<IO:<STDIN>>
12612 static VALUE
12613 argf_to_io(VALUE argf)
12615 next_argv();
12616 ARGF_FORWARD(0, 0);
12617 return ARGF.current_file;
12621 * call-seq:
12622 * ARGF.eof? -> true or false
12623 * ARGF.eof -> true or false
12625 * Returns true if the current file in +ARGF+ is at end of file, i.e. it has
12626 * no data to read. The stream must be opened for reading or an +IOError+
12627 * will be raised.
12629 * $ echo "eof" | ruby argf.rb
12631 * ARGF.eof? #=> false
12632 * 3.times { ARGF.readchar }
12633 * ARGF.eof? #=> false
12634 * ARGF.readchar #=> "\n"
12635 * ARGF.eof? #=> true
12638 static VALUE
12639 argf_eof(VALUE argf)
12641 next_argv();
12642 if (RTEST(ARGF.current_file)) {
12643 if (ARGF.init_p == 0) return Qtrue;
12644 next_argv();
12645 ARGF_FORWARD(0, 0);
12646 if (rb_io_eof(ARGF.current_file)) {
12647 return Qtrue;
12650 return Qfalse;
12654 * call-seq:
12655 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
12657 * Reads _length_ bytes from ARGF. The files named on the command line
12658 * are concatenated and treated as a single file by this method, so when
12659 * called without arguments the contents of this pseudo file are returned in
12660 * their entirety.
12662 * _length_ must be a non-negative integer or +nil+.
12664 * If _length_ is a positive integer, +read+ tries to read
12665 * _length_ bytes without any conversion (binary mode).
12666 * It returns +nil+ if an EOF is encountered before anything can be read.
12667 * Fewer than _length_ bytes are returned if an EOF is encountered during
12668 * the read.
12669 * In the case of an integer _length_, the resulting string is always
12670 * in ASCII-8BIT encoding.
12672 * If _length_ is omitted or is +nil+, it reads until EOF
12673 * and the encoding conversion is applied, if applicable.
12674 * A string is returned even if EOF is encountered before any data is read.
12676 * If _length_ is zero, it returns an empty string (<code>""</code>).
12678 * If the optional _outbuf_ argument is present,
12679 * it must reference a String, which will receive the data.
12680 * The _outbuf_ will contain only the received data after the method call
12681 * even if it is not empty at the beginning.
12683 * For example:
12685 * $ echo "small" > small.txt
12686 * $ echo "large" > large.txt
12687 * $ ./glark.rb small.txt large.txt
12689 * ARGF.read #=> "small\nlarge"
12690 * ARGF.read(200) #=> "small\nlarge"
12691 * ARGF.read(2) #=> "sm"
12692 * ARGF.read(0) #=> ""
12694 * Note that this method behaves like the fread() function in C.
12695 * This means it retries to invoke read(2) system calls to read data
12696 * with the specified length.
12697 * If you need the behavior like a single read(2) system call,
12698 * consider ARGF#readpartial or ARGF#read_nonblock.
12701 static VALUE
12702 argf_read(int argc, VALUE *argv, VALUE argf)
12704 VALUE tmp, str, length;
12705 long len = 0;
12707 rb_scan_args(argc, argv, "02", &length, &str);
12708 if (!NIL_P(length)) {
12709 len = NUM2LONG(argv[0]);
12711 if (!NIL_P(str)) {
12712 StringValue(str);
12713 rb_str_resize(str,0);
12714 argv[1] = Qnil;
12717 retry:
12718 if (!next_argv()) {
12719 return str;
12721 if (ARGF_GENERIC_INPUT_P()) {
12722 tmp = argf_forward(argc, argv, argf);
12724 else {
12725 tmp = io_read(argc, argv, ARGF.current_file);
12727 if (NIL_P(str)) str = tmp;
12728 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
12729 if (NIL_P(tmp) || NIL_P(length)) {
12730 if (ARGF.next_p != -1) {
12731 argf_close(argf);
12732 ARGF.next_p = 1;
12733 goto retry;
12736 else if (argc >= 1) {
12737 long slen = RSTRING_LEN(str);
12738 if (slen < len) {
12739 argv[0] = LONG2NUM(len - slen);
12740 goto retry;
12743 return str;
12746 struct argf_call_arg {
12747 int argc;
12748 VALUE *argv;
12749 VALUE argf;
12752 static VALUE
12753 argf_forward_call(VALUE arg)
12755 struct argf_call_arg *p = (struct argf_call_arg *)arg;
12756 argf_forward(p->argc, p->argv, p->argf);
12757 return Qnil;
12760 static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
12761 int nonblock);
12764 * call-seq:
12765 * ARGF.readpartial(maxlen) -> string
12766 * ARGF.readpartial(maxlen, outbuf) -> outbuf
12768 * Reads at most _maxlen_ bytes from the ARGF stream.
12770 * If the optional _outbuf_ argument is present,
12771 * it must reference a String, which will receive the data.
12772 * The _outbuf_ will contain only the received data after the method call
12773 * even if it is not empty at the beginning.
12775 * It raises EOFError on end of ARGF stream.
12776 * Since ARGF stream is a concatenation of multiple files,
12777 * internally EOF is occur for each file.
12778 * ARGF.readpartial returns empty strings for EOFs except the last one and
12779 * raises EOFError for the last one.
12783 static VALUE
12784 argf_readpartial(int argc, VALUE *argv, VALUE argf)
12786 return argf_getpartial(argc, argv, argf, Qnil, 0);
12790 * call-seq:
12791 * ARGF.read_nonblock(maxlen[, options]) -> string
12792 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
12794 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
12797 static VALUE
12798 argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
12800 VALUE opts;
12802 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
12804 if (!NIL_P(opts))
12805 argc--;
12807 return argf_getpartial(argc, argv, argf, opts, 1);
12810 static VALUE
12811 argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
12813 VALUE tmp, str, length;
12814 int no_exception;
12816 rb_scan_args(argc, argv, "11", &length, &str);
12817 if (!NIL_P(str)) {
12818 StringValue(str);
12819 argv[1] = str;
12821 no_exception = no_exception_p(opts);
12823 if (!next_argv()) {
12824 if (!NIL_P(str)) {
12825 rb_str_resize(str, 0);
12827 rb_eof_error();
12829 if (ARGF_GENERIC_INPUT_P()) {
12830 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
12831 struct argf_call_arg arg;
12832 arg.argc = argc;
12833 arg.argv = argv;
12834 arg.argf = argf;
12835 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
12836 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
12838 else {
12839 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
12841 if (NIL_P(tmp)) {
12842 if (ARGF.next_p == -1) {
12843 return io_nonblock_eof(no_exception);
12845 argf_close(argf);
12846 ARGF.next_p = 1;
12847 if (RARRAY_LEN(ARGF.argv) == 0) {
12848 return io_nonblock_eof(no_exception);
12850 if (NIL_P(str))
12851 str = rb_str_new(NULL, 0);
12852 return str;
12854 return tmp;
12858 * call-seq:
12859 * ARGF.getc -> String or nil
12861 * Reads the next character from +ARGF+ and returns it as a +String+. Returns
12862 * +nil+ at the end of the stream.
12864 * +ARGF+ treats the files named on the command line as a single file created
12865 * by concatenating their contents. After returning the last character of the
12866 * first file, it returns the first character of the second file, and so on.
12868 * For example:
12870 * $ echo "foo" > file
12871 * $ ruby argf.rb file
12873 * ARGF.getc #=> "f"
12874 * ARGF.getc #=> "o"
12875 * ARGF.getc #=> "o"
12876 * ARGF.getc #=> "\n"
12877 * ARGF.getc #=> nil
12878 * ARGF.getc #=> nil
12880 static VALUE
12881 argf_getc(VALUE argf)
12883 VALUE ch;
12885 retry:
12886 if (!next_argv()) return Qnil;
12887 if (ARGF_GENERIC_INPUT_P()) {
12888 ch = forward_current(rb_intern("getc"), 0, 0);
12890 else {
12891 ch = rb_io_getc(ARGF.current_file);
12893 if (NIL_P(ch) && ARGF.next_p != -1) {
12894 argf_close(argf);
12895 ARGF.next_p = 1;
12896 goto retry;
12899 return ch;
12903 * call-seq:
12904 * ARGF.getbyte -> Integer or nil
12906 * Gets the next 8-bit byte (0..255) from +ARGF+. Returns +nil+ if called at
12907 * the end of the stream.
12909 * For example:
12911 * $ echo "foo" > file
12912 * $ ruby argf.rb file
12914 * ARGF.getbyte #=> 102
12915 * ARGF.getbyte #=> 111
12916 * ARGF.getbyte #=> 111
12917 * ARGF.getbyte #=> 10
12918 * ARGF.getbyte #=> nil
12920 static VALUE
12921 argf_getbyte(VALUE argf)
12923 VALUE ch;
12925 retry:
12926 if (!next_argv()) return Qnil;
12927 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
12928 ch = forward_current(rb_intern("getbyte"), 0, 0);
12930 else {
12931 ch = rb_io_getbyte(ARGF.current_file);
12933 if (NIL_P(ch) && ARGF.next_p != -1) {
12934 argf_close(argf);
12935 ARGF.next_p = 1;
12936 goto retry;
12939 return ch;
12943 * call-seq:
12944 * ARGF.readchar -> String or nil
12946 * Reads the next character from +ARGF+ and returns it as a +String+. Raises
12947 * an +EOFError+ after the last character of the last file has been read.
12949 * For example:
12951 * $ echo "foo" > file
12952 * $ ruby argf.rb file
12954 * ARGF.readchar #=> "f"
12955 * ARGF.readchar #=> "o"
12956 * ARGF.readchar #=> "o"
12957 * ARGF.readchar #=> "\n"
12958 * ARGF.readchar #=> end of file reached (EOFError)
12960 static VALUE
12961 argf_readchar(VALUE argf)
12963 VALUE ch;
12965 retry:
12966 if (!next_argv()) rb_eof_error();
12967 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
12968 ch = forward_current(rb_intern("getc"), 0, 0);
12970 else {
12971 ch = rb_io_getc(ARGF.current_file);
12973 if (NIL_P(ch) && ARGF.next_p != -1) {
12974 argf_close(argf);
12975 ARGF.next_p = 1;
12976 goto retry;
12979 return ch;
12983 * call-seq:
12984 * ARGF.readbyte -> Integer
12986 * Reads the next 8-bit byte from ARGF and returns it as an +Integer+. Raises
12987 * an +EOFError+ after the last byte of the last file has been read.
12989 * For example:
12991 * $ echo "foo" > file
12992 * $ ruby argf.rb file
12994 * ARGF.readbyte #=> 102
12995 * ARGF.readbyte #=> 111
12996 * ARGF.readbyte #=> 111
12997 * ARGF.readbyte #=> 10
12998 * ARGF.readbyte #=> end of file reached (EOFError)
13000 static VALUE
13001 argf_readbyte(VALUE argf)
13003 VALUE c;
13005 NEXT_ARGF_FORWARD(0, 0);
13006 c = argf_getbyte(argf);
13007 if (NIL_P(c)) {
13008 rb_eof_error();
13010 return c;
13013 #define FOREACH_ARGF() while (next_argv())
13015 static VALUE
13016 argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
13018 const VALUE current = ARGF.current_file;
13019 rb_yield_values2(argc, argv);
13020 if (ARGF.init_p == -1 || current != ARGF.current_file) {
13021 rb_iter_break_value(Qundef);
13023 return Qnil;
13026 #define ARGF_block_call(mid, argc, argv, func, argf) \
13027 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
13028 func, argf, rb_keyword_given_p())
13030 static void
13031 argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
13033 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
13034 if (ret != Qundef) ARGF.next_p = 1;
13037 static VALUE
13038 argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
13040 if (!global_argf_p(argf)) {
13041 ARGF.last_lineno = ++ARGF.lineno;
13043 return argf_block_call_i(i, argf, argc, argv, blockarg);
13046 static void
13047 argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
13049 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
13050 if (ret != Qundef) ARGF.next_p = 1;
13054 * call-seq:
13055 * ARGF.each(sep=$/) {|line| block } -> ARGF
13056 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
13057 * ARGF.each(...) -> an_enumerator
13059 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
13060 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
13061 * ARGF.each_line(...) -> an_enumerator
13063 * Returns an enumerator which iterates over each line (separated by _sep_,
13064 * which defaults to your platform's newline character) of each file in
13065 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
13066 * block, otherwise an enumerator is returned.
13067 * The optional _limit_ argument is an +Integer+ specifying the maximum
13068 * length of each line; longer lines will be split according to this limit.
13070 * This method allows you to treat the files supplied on the command line as
13071 * a single file consisting of the concatenation of each named file. After
13072 * the last line of the first file has been returned, the first line of the
13073 * second file is returned. The +ARGF.filename+ and +ARGF.lineno+ methods can
13074 * be used to determine the filename of the current line and line number of
13075 * the whole input, respectively.
13077 * For example, the following code prints out each line of each named file
13078 * prefixed with its line number, displaying the filename once per file:
13080 * ARGF.each_line do |line|
13081 * puts ARGF.filename if ARGF.file.lineno == 1
13082 * puts "#{ARGF.file.lineno}: #{line}"
13083 * end
13085 * While the following code prints only the first file's name at first, and
13086 * the contents with line number counted through all named files.
13088 * ARGF.each_line do |line|
13089 * puts ARGF.filename if ARGF.lineno == 1
13090 * puts "#{ARGF.lineno}: #{line}"
13091 * end
13093 static VALUE
13094 argf_each_line(int argc, VALUE *argv, VALUE argf)
13096 RETURN_ENUMERATOR(argf, argc, argv);
13097 FOREACH_ARGF() {
13098 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
13100 return argf;
13104 * call-seq:
13105 * ARGF.each_byte {|byte| block } -> ARGF
13106 * ARGF.each_byte -> an_enumerator
13108 * Iterates over each byte of each file in +ARGV+.
13109 * A byte is returned as an +Integer+ in the range 0..255.
13111 * This method allows you to treat the files supplied on the command line as
13112 * a single file consisting of the concatenation of each named file. After
13113 * the last byte of the first file has been returned, the first byte of the
13114 * second file is returned. The +ARGF.filename+ method can be used to
13115 * determine the filename of the current byte.
13117 * If no block is given, an enumerator is returned instead.
13119 * For example:
13121 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
13124 static VALUE
13125 argf_each_byte(VALUE argf)
13127 RETURN_ENUMERATOR(argf, 0, 0);
13128 FOREACH_ARGF() {
13129 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
13131 return argf;
13135 * call-seq:
13136 * ARGF.each_char {|char| block } -> ARGF
13137 * ARGF.each_char -> an_enumerator
13139 * Iterates over each character of each file in +ARGF+.
13141 * This method allows you to treat the files supplied on the command line as
13142 * a single file consisting of the concatenation of each named file. After
13143 * the last character of the first file has been returned, the first
13144 * character of the second file is returned. The +ARGF.filename+ method can
13145 * be used to determine the name of the file in which the current character
13146 * appears.
13148 * If no block is given, an enumerator is returned instead.
13150 static VALUE
13151 argf_each_char(VALUE argf)
13153 RETURN_ENUMERATOR(argf, 0, 0);
13154 FOREACH_ARGF() {
13155 argf_block_call(rb_intern("each_char"), 0, 0, argf);
13157 return argf;
13161 * call-seq:
13162 * ARGF.each_codepoint {|codepoint| block } -> ARGF
13163 * ARGF.each_codepoint -> an_enumerator
13165 * Iterates over each codepoint of each file in +ARGF+.
13167 * This method allows you to treat the files supplied on the command line as
13168 * a single file consisting of the concatenation of each named file. After
13169 * the last codepoint of the first file has been returned, the first
13170 * codepoint of the second file is returned. The +ARGF.filename+ method can
13171 * be used to determine the name of the file in which the current codepoint
13172 * appears.
13174 * If no block is given, an enumerator is returned instead.
13176 static VALUE
13177 argf_each_codepoint(VALUE argf)
13179 RETURN_ENUMERATOR(argf, 0, 0);
13180 FOREACH_ARGF() {
13181 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
13183 return argf;
13187 * call-seq:
13188 * ARGF.filename -> String
13189 * ARGF.path -> String
13191 * Returns the current filename. "-" is returned when the current file is
13192 * STDIN.
13194 * For example:
13196 * $ echo "foo" > foo
13197 * $ echo "bar" > bar
13198 * $ echo "glark" > glark
13200 * $ ruby argf.rb foo bar glark
13202 * ARGF.filename #=> "foo"
13203 * ARGF.read(5) #=> "foo\nb"
13204 * ARGF.filename #=> "bar"
13205 * ARGF.skip
13206 * ARGF.filename #=> "glark"
13208 static VALUE
13209 argf_filename(VALUE argf)
13211 next_argv();
13212 return ARGF.filename;
13215 static VALUE
13216 argf_filename_getter(ID id, VALUE *var)
13218 return argf_filename(*var);
13222 * call-seq:
13223 * ARGF.file -> IO or File object
13225 * Returns the current file as an +IO+ or +File+ object.
13226 * <code>$stdin</code> is returned when the current file is STDIN.
13228 * For example:
13230 * $ echo "foo" > foo
13231 * $ echo "bar" > bar
13233 * $ ruby argf.rb foo bar
13235 * ARGF.file #=> #<File:foo>
13236 * ARGF.read(5) #=> "foo\nb"
13237 * ARGF.file #=> #<File:bar>
13239 static VALUE
13240 argf_file(VALUE argf)
13242 next_argv();
13243 return ARGF.current_file;
13247 * call-seq:
13248 * ARGF.binmode -> ARGF
13250 * Puts +ARGF+ into binary mode. Once a stream is in binary mode, it cannot
13251 * be reset to non-binary mode. This option has the following effects:
13253 * * Newline conversion is disabled.
13254 * * Encoding conversion is disabled.
13255 * * Content is treated as ASCII-8BIT.
13257 static VALUE
13258 argf_binmode_m(VALUE argf)
13260 ARGF.binmode = 1;
13261 next_argv();
13262 ARGF_FORWARD(0, 0);
13263 rb_io_ascii8bit_binmode(ARGF.current_file);
13264 return argf;
13268 * call-seq:
13269 * ARGF.binmode? -> true or false
13271 * Returns true if +ARGF+ is being read in binary mode; false otherwise.
13272 * To enable binary mode use +ARGF.binmode+.
13274 * For example:
13276 * ARGF.binmode? #=> false
13277 * ARGF.binmode
13278 * ARGF.binmode? #=> true
13280 static VALUE
13281 argf_binmode_p(VALUE argf)
13283 return RBOOL(ARGF.binmode);
13287 * call-seq:
13288 * ARGF.skip -> ARGF
13290 * Sets the current file to the next file in ARGV. If there aren't any more
13291 * files it has no effect.
13293 * For example:
13295 * $ ruby argf.rb foo bar
13296 * ARGF.filename #=> "foo"
13297 * ARGF.skip
13298 * ARGF.filename #=> "bar"
13300 static VALUE
13301 argf_skip(VALUE argf)
13303 if (ARGF.init_p && ARGF.next_p == 0) {
13304 argf_close(argf);
13305 ARGF.next_p = 1;
13307 return argf;
13311 * call-seq:
13312 * ARGF.close -> ARGF
13314 * Closes the current file and skips to the next file in ARGV. If there are
13315 * no more files to open, just closes the current file. +STDIN+ will not be
13316 * closed.
13318 * For example:
13320 * $ ruby argf.rb foo bar
13322 * ARGF.filename #=> "foo"
13323 * ARGF.close
13324 * ARGF.filename #=> "bar"
13325 * ARGF.close
13327 static VALUE
13328 argf_close_m(VALUE argf)
13330 next_argv();
13331 argf_close(argf);
13332 if (ARGF.next_p != -1) {
13333 ARGF.next_p = 1;
13335 ARGF.lineno = 0;
13336 return argf;
13340 * call-seq:
13341 * ARGF.closed? -> true or false
13343 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
13344 * +ARGF.close+ to actually close the current file.
13346 static VALUE
13347 argf_closed(VALUE argf)
13349 next_argv();
13350 ARGF_FORWARD(0, 0);
13351 return rb_io_closed(ARGF.current_file);
13355 * call-seq:
13356 * ARGF.to_s -> String
13358 * Returns "ARGF".
13360 static VALUE
13361 argf_to_s(VALUE argf)
13363 return rb_str_new2("ARGF");
13367 * call-seq:
13368 * ARGF.inplace_mode -> String
13370 * Returns the file extension appended to the names of modified files under
13371 * in-place edit mode. This value can be set using +ARGF.inplace_mode=+ or
13372 * passing the +-i+ switch to the Ruby binary.
13374 static VALUE
13375 argf_inplace_mode_get(VALUE argf)
13377 if (!ARGF.inplace) return Qnil;
13378 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
13379 return rb_str_dup(ARGF.inplace);
13382 static VALUE
13383 opt_i_get(ID id, VALUE *var)
13385 return argf_inplace_mode_get(*var);
13389 * call-seq:
13390 * ARGF.inplace_mode = ext -> ARGF
13392 * Sets the filename extension for in-place editing mode to the given String.
13393 * Each file being edited has this value appended to its filename. The
13394 * modified file is saved under this new name.
13396 * For example:
13398 * $ ruby argf.rb file.txt
13400 * ARGF.inplace_mode = '.bak'
13401 * ARGF.each_line do |line|
13402 * print line.sub("foo","bar")
13403 * end
13405 * Each line of _file.txt_ has the first occurrence of "foo" replaced with
13406 * "bar", then the new line is written out to _file.txt.bak_.
13408 static VALUE
13409 argf_inplace_mode_set(VALUE argf, VALUE val)
13411 if (!RTEST(val)) {
13412 ARGF.inplace = Qfalse;
13414 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
13415 ARGF.inplace = Qnil;
13417 else {
13418 ARGF.inplace = rb_str_new_frozen(val);
13420 return argf;
13423 static void
13424 opt_i_set(VALUE val, ID id, VALUE *var)
13426 argf_inplace_mode_set(*var, val);
13429 void
13430 ruby_set_inplace_mode(const char *suffix)
13432 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
13436 * call-seq:
13437 * ARGF.argv -> ARGV
13439 * Returns the +ARGV+ array, which contains the arguments passed to your
13440 * script, one per element.
13442 * For example:
13444 * $ ruby argf.rb -v glark.txt
13446 * ARGF.argv #=> ["-v", "glark.txt"]
13449 static VALUE
13450 argf_argv(VALUE argf)
13452 return ARGF.argv;
13455 static VALUE
13456 argf_argv_getter(ID id, VALUE *var)
13458 return argf_argv(*var);
13461 VALUE
13462 rb_get_argv(void)
13464 return ARGF.argv;
13468 * call-seq:
13469 * ARGF.to_write_io -> io
13471 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
13472 * enabled.
13474 static VALUE
13475 argf_write_io(VALUE argf)
13477 if (!RTEST(ARGF.current_file)) {
13478 rb_raise(rb_eIOError, "not opened for writing");
13480 return GetWriteIO(ARGF.current_file);
13484 * call-seq:
13485 * ARGF.write(string) -> integer
13487 * Writes _string_ if inplace mode.
13489 static VALUE
13490 argf_write(VALUE argf, VALUE str)
13492 return rb_io_write(argf_write_io(argf), str);
13495 void
13496 rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
13498 rb_readwrite_syserr_fail(waiting, errno, mesg);
13501 void
13502 rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
13504 VALUE arg, c = Qnil;
13505 arg = mesg ? rb_str_new2(mesg) : Qnil;
13506 switch (waiting) {
13507 case RB_IO_WAIT_WRITABLE:
13508 switch (n) {
13509 case EAGAIN:
13510 c = rb_eEAGAINWaitWritable;
13511 break;
13512 #if EAGAIN != EWOULDBLOCK
13513 case EWOULDBLOCK:
13514 c = rb_eEWOULDBLOCKWaitWritable;
13515 break;
13516 #endif
13517 case EINPROGRESS:
13518 c = rb_eEINPROGRESSWaitWritable;
13519 break;
13520 default:
13521 rb_mod_syserr_fail_str(rb_mWaitWritable, n, arg);
13523 break;
13524 case RB_IO_WAIT_READABLE:
13525 switch (n) {
13526 case EAGAIN:
13527 c = rb_eEAGAINWaitReadable;
13528 break;
13529 #if EAGAIN != EWOULDBLOCK
13530 case EWOULDBLOCK:
13531 c = rb_eEWOULDBLOCKWaitReadable;
13532 break;
13533 #endif
13534 case EINPROGRESS:
13535 c = rb_eEINPROGRESSWaitReadable;
13536 break;
13537 default:
13538 rb_mod_syserr_fail_str(rb_mWaitReadable, n, arg);
13540 break;
13541 default:
13542 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
13544 rb_exc_raise(rb_class_new_instance(1, &arg, c));
13547 static VALUE
13548 get_LAST_READ_LINE(ID _x, VALUE *_y)
13550 return rb_lastline_get();
13553 static void
13554 set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
13556 rb_lastline_set(val);
13560 * Document-class: IOError
13562 * Raised when an IO operation fails.
13564 * File.open("/etc/hosts") {|f| f << "example"}
13565 * #=> IOError: not opened for writing
13567 * File.open("/etc/hosts") {|f| f.close; f.read }
13568 * #=> IOError: closed stream
13570 * Note that some IO failures raise <code>SystemCallError</code>s
13571 * and these are not subclasses of IOError:
13573 * File.open("does/not/exist")
13574 * #=> Errno::ENOENT: No such file or directory - does/not/exist
13578 * Document-class: EOFError
13580 * Raised by some IO operations when reaching the end of file. Many IO
13581 * methods exist in two forms,
13583 * one that returns +nil+ when the end of file is reached, the other
13584 * raises +EOFError+.
13586 * +EOFError+ is a subclass of +IOError+.
13588 * file = File.open("/etc/hosts")
13589 * file.read
13590 * file.gets #=> nil
13591 * file.readline #=> EOFError: end of file reached
13595 * Document-class: ARGF
13597 * +ARGF+ is a stream designed for use in scripts that process files given as
13598 * command-line arguments or passed in via STDIN.
13600 * The arguments passed to your script are stored in the +ARGV+ Array, one
13601 * argument per element. +ARGF+ assumes that any arguments that aren't
13602 * filenames have been removed from +ARGV+. For example:
13604 * $ ruby argf.rb --verbose file1 file2
13606 * ARGV #=> ["--verbose", "file1", "file2"]
13607 * option = ARGV.shift #=> "--verbose"
13608 * ARGV #=> ["file1", "file2"]
13610 * You can now use +ARGF+ to work with a concatenation of each of these named
13611 * files. For instance, +ARGF.read+ will return the contents of _file1_
13612 * followed by the contents of _file2_.
13614 * After a file in +ARGV+ has been read +ARGF+ removes it from the Array.
13615 * Thus, after all files have been read +ARGV+ will be empty.
13617 * You can manipulate +ARGV+ yourself to control what +ARGF+ operates on. If
13618 * you remove a file from +ARGV+, it is ignored by +ARGF+; if you add files to
13619 * +ARGV+, they are treated as if they were named on the command line. For
13620 * example:
13622 * ARGV.replace ["file1"]
13623 * ARGF.readlines # Returns the contents of file1 as an Array
13624 * ARGV #=> []
13625 * ARGV.replace ["file2", "file3"]
13626 * ARGF.read # Returns the contents of file2 and file3
13628 * If +ARGV+ is empty, +ARGF+ acts as if it contained STDIN, i.e. the data
13629 * piped to your script. For example:
13631 * $ echo "glark" | ruby -e 'p ARGF.read'
13632 * "glark\n"
13636 * The IO class is the basis for all input and output in Ruby.
13637 * An I/O stream may be <em>duplexed</em> (that is, bidirectional), and
13638 * so may use more than one native operating system stream.
13640 * Many of the examples in this section use the File class, the only standard
13641 * subclass of IO. The two classes are closely associated. Like the File
13642 * class, the Socket library subclasses from IO (such as TCPSocket or
13643 * UDPSocket).
13645 * The Kernel#open method can create an IO (or File) object for these types
13646 * of arguments:
13648 * * A plain string represents a filename suitable for the underlying
13649 * operating system.
13651 * * A string starting with <code>"|"</code> indicates a subprocess.
13652 * The remainder of the string following the <code>"|"</code> is
13653 * invoked as a process with appropriate input/output channels
13654 * connected to it.
13656 * * A string equal to <code>"|-"</code> will create another Ruby
13657 * instance as a subprocess.
13659 * The IO may be opened with different file modes (read-only, write-only) and
13660 * encodings for proper conversion. See IO.new for these options. See
13661 * Kernel#open for details of the various command formats described above.
13663 * IO.popen, the Open3 library, or Process#spawn may also be used to
13664 * communicate with subprocesses through an IO.
13666 * Ruby will convert pathnames between different operating system
13667 * conventions if possible. For instance, on a Windows system the
13668 * filename <code>"/gumby/ruby/test.rb"</code> will be opened as
13669 * <code>"\gumby\ruby\test.rb"</code>. When specifying a Windows-style
13670 * filename in a Ruby string, remember to escape the backslashes:
13672 * "C:\\gumby\\ruby\\test.rb"
13674 * Our examples here will use the Unix-style forward slashes;
13675 * File::ALT_SEPARATOR can be used to get the platform-specific separator
13676 * character.
13678 * The global constant ARGF (also accessible as <code>$<</code>) provides an
13679 * IO-like stream which allows access to all files mentioned on the
13680 * command line (or STDIN if no files are mentioned). ARGF#path and its alias
13681 * ARGF#filename are provided to access the name of the file currently being
13682 * read.
13684 * == io/console
13686 * The io/console extension provides methods for interacting with the
13687 * console. The console can be accessed from IO.console or the standard
13688 * input/output/error IO objects.
13690 * Requiring io/console adds the following methods:
13692 * * IO::console
13693 * * IO#raw
13694 * * IO#raw!
13695 * * IO#cooked
13696 * * IO#cooked!
13697 * * IO#getch
13698 * * IO#echo=
13699 * * IO#echo?
13700 * * IO#noecho
13701 * * IO#winsize
13702 * * IO#winsize=
13703 * * IO#iflush
13704 * * IO#ioflush
13705 * * IO#oflush
13707 * Example:
13709 * require 'io/console'
13710 * rows, columns = $stdout.winsize
13711 * puts "Your screen is #{columns} wide and #{rows} tall"
13713 * == Example Files
13715 * Many examples here use these filenames and their corresponding files:
13717 * - <tt>t.txt</tt>: A text-only file that is assumed to exist via:
13719 * text = <<~EOT
13720 * This is line one.
13721 * This is the second line.
13722 * This is the third line.
13723 * EOT
13724 * File.write('t.txt', text)
13726 * - <tt>t.dat</tt>: A data file that is assumed to exist via:
13728 * data = "\u9990\u9991\u9992\u9993\u9994"
13729 * f = File.open('t.dat', 'wb:UTF-16')
13730 * f.write(data)
13731 * f.close
13733 * - <tt>t.rus</tt>: A Russian-language text file that is assumed to exist via:
13735 * File.write('t.rus', "\u{442 435 441 442}")
13737 * - <tt>t.tmp</tt>: A file that is assumed _not_ to exist.
13739 * == Modes
13741 * A number of \IO method calls must or may specify a _mode_ for the stream;
13742 * the mode determines how stream is to be accessible, including:
13744 * - Whether the stream is to be read-only, write-only, or read-write.
13745 * - Whether the stream is positioned at its beginning or its end.
13746 * - Whether the stream treats data as text-only or binary.
13747 * - The external and internal encodings.
13749 * === Mode Specified as an \Integer
13751 * When +mode+ is an integer it must be one or more (combined by bitwise OR (<tt>|</tt>)
13752 * of the modes defined in File::Constants:
13754 * - +File::RDONLY+: Open for reading only.
13755 * - +File::WRONLY+: Open for writing only.
13756 * - +File::RDWR+: Open for reading and writing.
13757 * - +File::APPEND+: Open for appending only.
13758 * - +File::CREAT+: Create file if it does not exist.
13759 * - +File::EXCL+: Raise an exception if +File::CREAT+ is given and the file exists.
13761 * Examples:
13763 * File.new('t.txt', File::RDONLY)
13764 * File.new('t.tmp', File::RDWR | File::CREAT | File::EXCL)
13766 * Note: Method IO#set_encoding does not allow the mode to be specified as an integer.
13768 * === Mode Specified As a \String
13770 * When +mode+ is a string it must begin with one of the following:
13772 * - <tt>'r'</tt>: Read-only stream, positioned at the beginning;
13773 * the stream cannot be changed to writable.
13774 * - <tt>'w'</tt>: Write-only stream, positioned at the beginning;
13775 * the stream cannot be changed to readable.
13776 * - <tt>'a'</tt>: Write-only stream, positioned at the end;
13777 * every write appends to the end;
13778 * the stream cannot be changed to readable.
13779 * - <tt>'r+'</tt>: Read-write stream, positioned at the beginning.
13780 * - <tt>'w+'</tt>: Read-write stream, positioned at the end.
13781 * - <tt>'a+'</tt>: Read-write stream, positioned at the end.
13783 * For a writable file stream (that is, any except read-only),
13784 * the file is truncated to zero if it exists,
13785 * and is created if it does not exist.
13787 * Examples:
13789 * File.open('t.txt', 'r')
13790 * File.open('t.tmp', 'w')
13792 * Either of the following may be suffixed to any of the above:
13794 * - <tt>'t'</tt>: Text data; sets the default external encoding to +Encoding::UTF_8+;
13795 * on Windows, enables conversion between EOL and CRLF.
13796 * - <tt>'b'</tt>: Binary data; sets the default external encoding to +Encoding::ASCII_8BIT+;
13797 * on Windows, suppresses conversion between EOL and CRLF.
13799 * If neither is given, the stream defaults to text data.
13801 * Examples:
13803 * File.open('t.txt', 'rt')
13804 * File.open('t.dat', 'rb')
13806 * The following may be suffixed to any writable mode above:
13808 * - <tt>'x'</tt>: Creates the file if it does not exist;
13809 * raises an exception if the file exists.
13811 * Example:
13813 * File.open('t.tmp', 'wx')
13815 * Finally, the mode string may specify encodings --
13816 * either external encoding only or both external and internal encodings --
13817 * by appending one or both encoding names, separated by colons:
13819 * f = File.new('t.dat', 'rb')
13820 * f.external_encoding # => #<Encoding:ASCII-8BIT>
13821 * f.internal_encoding # => nil
13822 * f = File.new('t.dat', 'rb:UTF-16')
13823 * f.external_encoding # => #<Encoding:UTF-16 (dummy)>
13824 * f.internal_encoding # => nil
13825 * f = File.new('t.dat', 'rb:UTF-16:UTF-16')
13826 * f.external_encoding # => #<Encoding:UTF-16 (dummy)>
13827 * f.internal_encoding # => #<Encoding:UTF-16>
13829 * The numerous encoding names are available in array Encoding.name_list:
13831 * Encoding.name_list.size # => 175
13832 * Encoding.name_list.take(3) # => ["ASCII-8BIT", "UTF-8", "US-ASCII"]
13834 * == Encodings
13836 * When the external encoding is set,
13837 * strings read are tagged by that encoding
13838 * when reading, and strings written are converted to that
13839 * encoding when writing.
13841 * When both external and internal encodings are set,
13842 * strings read are converted from external to internal encoding,
13843 * and strings written are converted from internal to external encoding.
13844 * For further details about transcoding input and output, see Encoding.
13846 * If the external encoding is <tt>'BOM|UTF-8'</tt>, <tt>'BOM|UTF-16LE'</tt>
13847 * or <tt>'BOM|UTF16-BE'</tt>, Ruby checks for
13848 * a Unicode BOM in the input document to help determine the encoding. For
13849 * UTF-16 encodings the file open mode must be binary.
13850 * If the BOM is found, it is stripped and the external encoding from the BOM is used.
13852 * Note that the BOM-style encoding option is case insensitive,
13853 * so 'bom|utf-8' is also valid.)
13855 * == Open Options
13857 * A number of \IO methods accept an optional parameter +opts+,
13858 * which determines how a new stream is to be opened:
13860 * - +:mode+: Stream mode.
13861 * - +:flags+: \Integer file open flags;
13862 * If +mode+ is also given, the two are bitwise-ORed.
13863 * - +:external_encoding+: External encoding for the stream.
13864 * - +:internal_encoding+: Internal encoding for the stream.
13865 * <tt>'-'</tt> is a synonym for the default internal encoding.
13866 * If the value is +nil+ no conversion occurs.
13867 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
13868 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
13869 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
13870 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
13871 * when the stream closes; otherwise it remains open.
13873 * Also available are the options offered in String#encode,
13874 * which may control conversion between external internal encoding.
13876 * == Getline Options
13878 * A number of \IO methods accept optional keyword arguments
13879 * that determine how a stream is to be treated:
13881 * - +:chomp+: If +true+, line separators are omitted; default is +false+.
13883 * == Position
13885 * An \IO stream has a _position_, which is the non-negative integer offset
13886 * (in bytes) in the stream where the next read or write will occur.
13888 * Note that a text stream may have multi-byte characters,
13889 * so a text stream whose position is +n+ (_bytes_) may not have +n+ _characters_
13890 * preceding the current position -- there may be fewer.
13892 * A new stream is initially positioned:
13894 * - At the beginning (position +0+)
13895 * if its mode is <tt>'r'</tt>, <tt>'w'</tt>, or <tt>'r+'</tt>.
13896 * - At the end (position <tt>self.size</tt>)
13897 * if its mode is <tt>'a'</tt>, <tt>'w+'</tt>, or <tt>'a+'</tt>.
13899 * Methods to query the position:
13901 * - IO#tell and its alias IO#pos return the position for an open stream.
13902 * - IO#eof? and its alias IO#eof return whether the position is at the end
13903 * of a readable stream.
13905 * Reading from a stream usually changes its position:
13907 * f = File.open('t.txt')
13908 * f.tell # => 0
13909 * f.readline # => "This is line one.\n"
13910 * f.tell # => 19
13911 * f.readline # => "This is the second line.\n"
13912 * f.tell # => 45
13913 * f.eof? # => false
13914 * f.readline # => "Here's the third line.\n"
13915 * f.eof? # => true
13918 * Writing to a stream usually changes its position:
13920 * f = File.open('t.tmp', 'w')
13921 * f.tell # => 0
13922 * f.write('foo') # => 3
13923 * f.tell # => 3
13924 * f.write('bar') # => 3
13925 * f.tell # => 6
13928 * Iterating over a stream usually changes its position:
13930 * f = File.open('t.txt')
13931 * f.each do |line|
13932 * p "position=#{f.pos} eof?=#{f.eof?} line=#{line}"
13933 * end
13935 * Output:
13937 * "position=19 eof?=false line=This is line one.\n"
13938 * "position=45 eof?=false line=This is the second line.\n"
13939 * "position=70 eof?=true line=This is the third line.\n"
13941 * The position may also be changed by certain other methods:
13943 * - IO#pos= and IO#seek change the position to a specified offset.
13944 * - IO#rewind changes the position to the beginning.
13946 * == Line Number
13948 * A readable \IO stream has a _line_ _number_,
13949 * which is the non-negative integer line number
13950 * in the stream where the next read will occur.
13952 * A new stream is initially has line number +0+.
13954 * \Method IO#lineno returns the line number.
13956 * Reading lines from a stream usually changes its line number:
13958 * f = File.open('t.txt', 'r')
13959 * f.lineno # => 0
13960 * f.readline # => "This is line one.\n"
13961 * f.lineno # => 1
13962 * f.readline # => "This is the second line.\n"
13963 * f.lineno # => 2
13964 * f.readline # => "Here's the third line.\n"
13965 * f.lineno # => 3
13966 * f.eof? # => true
13968 * Iterating over lines in a stream usually changes its line number:
13970 * f = File.open('t.txt')
13971 * f.each_line do |line|
13972 * p "position=#{f.pos} eof?=#{f.eof?} line=#{line}"
13973 * end
13975 * Output:
13977 * "position=19 eof?=false line=This is line one.\n"
13978 * "position=45 eof?=false line=This is the second line.\n"
13979 * "position=70 eof?=true line=This is the third line.\n"
13981 * == What's Here
13983 * First, what's elsewhere. \Class \IO:
13985 * - Inherits from {class Object}[Object.html#class-Object-label-What-27s+Here].
13986 * - Includes {module Enumerable}[Enumerable.html#module-Enumerable-label-What-27s+Here],
13987 * which provides dozens of additional methods.
13989 * Here, class \IO provides methods that are useful for:
13991 * - {Creating}[#class-IO-label-Creating]
13992 * - {Reading}[#class-IO-label-Reading]
13993 * - {Writing}[#class-IO-label-Writing]
13994 * - {Positioning}[#class-IO-label-Positioning]
13995 * - {Iterating}[#class-IO-label-Iterating]
13996 * - {Settings}[#class-IO-label-Settings]
13997 * - {Querying}[#class-IO-label-Querying]
13998 * - {Buffering}[#class-IO-label-Buffering]
13999 * - {Low-Level Access}[#class-IO-label-Low-Level+Access]
14000 * - {Other}[#class-IO-label-Other]
14002 * === Creating
14004 * - ::new (aliased as ::for_fd):: Creates and returns a new \IO object for the given
14005 * integer file descriptor.
14006 * - ::open:: Creates a new \IO object.
14007 * - ::pipe:: Creates a connected pair of reader and writer \IO objects.
14008 * - ::popen:: Creates an \IO object to interact with a subprocess.
14009 * - ::select:: Selects which given \IO instances are ready for reading,
14010 * writing, or have pending exceptions.
14012 * === Reading
14014 * - ::binread:: Returns a binary string with all or a subset of bytes
14015 * from the given file.
14016 * - ::read:: Returns a string with all or a subset of bytes from the given file.
14017 * - ::readlines:: Returns an array of strings, which are the lines from the given file.
14018 * - #getbyte:: Returns the next 8-bit byte read from +self+ as an integer.
14019 * - #getc:: Returns the next character read from +self+ as a string.
14020 * - #gets:: Returns the line read from +self+.
14021 * - #pread:: Returns all or the next _n_ bytes read from +self+,
14022 * not updating the receiver's offset.
14023 * - #read:: Returns all remaining or the next _n_ bytes read from +self+
14024 * for a given _n_.
14025 * - #read_nonblock:: the next _n_ bytes read from +self+ for a given _n_,
14026 * in non-block mode.
14027 * - #readbyte:: Returns the next byte read from +self+;
14028 * same as #getbyte, but raises an exception on end-of-file.
14029 * - #readchar:: Returns the next character read from +self+;
14030 * same as #getc, but raises an exception on end-of-file.
14031 * - #readline:: Returns the next line read from +self+;
14032 * same as #getline, but raises an exception of end-of-file.
14033 * - #readlines:: Returns an array of all lines read read from +self+.
14034 * - #readpartial:: Returns up to the given number of bytes from +self+.
14036 * === Writing
14038 * - ::binwrite:: Writes the given string to the file at the given filepath,
14039 in binary mode.
14040 * - ::write:: Writes the given string to +self+.
14041 * - {::<<}[#method-i-3C-3C]:: Appends the given string to +self+.
14042 * - #print:: Prints last read line or given objects to +self+.
14043 * - #printf:: Writes to +self+ based on the given format string and objects.
14044 * - #putc:: Writes a character to +self+.
14045 * - #puts:: Writes lines to +self+, making sure line ends with a newline.
14046 * - #pwrite:: Writes the given string at the given offset,
14047 * not updating the receiver's offset.
14048 * - #write:: Writes one or more given strings to +self+.
14049 * - #write_nonblock:: Writes one or more given strings to +self+ in non-blocking mode.
14051 * === Positioning
14053 * - #lineno:: Returns the current line number in +self+.
14054 * - #lineno=:: Sets the line number is +self+.
14055 * - #pos (aliased as #tell):: Returns the current byte offset in +self+.
14056 * - #pos=:: Sets the byte offset in +self+.
14057 * - #reopen:: Reassociates +self+ with a new or existing \IO stream.
14058 * - #rewind:: Positions +self+ to the beginning of input.
14059 * - #seek:: Sets the offset for +self+ relative to given position.
14061 * === Iterating
14063 * - ::foreach:: Yields each line of given file to the block.
14064 * - #each (aliased as #each_line):: Calls the given block
14065 * with each successive line in +self+.
14066 * - #each_byte:: Calls the given block with each successive byte in +self+
14067 * as an integer.
14068 * - #each_char:: Calls the given block with each successive character in +self+
14069 * as a string.
14070 * - #each_codepoint:: Calls the given block with each successive codepoint in +self+
14071 * as an integer.
14073 * === Settings
14075 * - #autoclose=:: Sets whether +self+ auto-closes.
14076 * - #binmode:: Sets +self+ to binary mode.
14077 * - #close:: Closes +self+.
14078 * - #close_on_exec=:: Sets the close-on-exec flag.
14079 * - #close_read:: Closes +self+ for reading.
14080 * - #close_write:: Closes +self+ for writing.
14081 * - #set_encoding:: Sets the encoding for +self+.
14082 * - #set_encoding_by_bom:: Sets the encoding for +self+, based on its
14083 * Unicode byte-order-mark.
14084 * - #sync=:: Sets the sync-mode to the given value.
14086 * === Querying
14088 * - #autoclose?:: Returns whether +self+ auto-closes.
14089 * - #binmode?:: Returns whether +self+ is in binary mode.
14090 * - #close_on_exec?:: Returns the close-on-exec flag for +self+.
14091 * - #closed?:: Returns whether +self+ is closed.
14092 * - #eof? (aliased as #eof):: Returns whether +self+ is at end-of-file.
14093 * - #external_encoding:: Returns the external encoding object for +self+.
14094 * - #fileno (aliased as #to_i):: Returns the integer file descriptor for +self+
14095 * - #internal_encoding:: Returns the internal encoding object for +self+.
14096 * - #pid:: Returns the process ID of a child process associated with +self+,
14097 * if +self+ was created by ::popen.
14098 * - #stat:: Returns the File::Stat object containing status information for +self+.
14099 * - #sync:: Returns whether +self+ is in sync-mode.
14100 * - #tty (aliased as #isatty):: Returns whether +self+ is a terminal.
14102 * === Buffering
14104 * - #fdatasync:: Immediately writes all buffered data in +self+ to disk.
14105 * - #flush:: Flushes any buffered data within +self+ to the underlying
14106 * operating system.
14107 * - #fsync:: Immediately writes all buffered data and attributes in +self+ to disk.
14108 * - #ungetbyte:: Prepends buffer for +self+ with given integer byte or string.
14109 * - #ungetc:: Prepends buffer for +self+ with given string.
14111 * === Low-Level Access
14113 * - ::sysopen:: Opens the file given by its path,
14114 * returning the integer file descriptor.
14115 * - #advise:: Announces the intention to access data from +self+ in a specific way.
14116 * - #fcntl:: Passes a low-level command to the file specified
14117 * by the given file descriptor.
14118 * - #ioctl:: Passes a low-level command to the device specified
14119 * by the given file descriptor.
14120 * - #sysread:: Returns up to the next _n_ bytes read from self using a low-level read.
14121 * - #sysseek:: Sets the offset for +self+.
14122 * - #syswrite:: Writes the given string to +self+ using a low-level write.
14124 * === Other
14126 * - ::copy_stream:: Copies data from a source to a destination,
14127 * each of which is a filepath or an \IO-like object.
14128 * - ::try_convert:: Returns a new \IO object resulting from converting
14129 * the given object.
14130 * - #inspect:: Returns the string representation of +self+.
14134 void
14135 Init_IO(void)
14137 VALUE rb_cARGF;
14138 #ifdef __CYGWIN__
14139 #include <sys/cygwin.h>
14140 static struct __cygwin_perfile pf[] =
14142 {"", O_RDONLY | O_BINARY},
14143 {"", O_WRONLY | O_BINARY},
14144 {"", O_RDWR | O_BINARY},
14145 {"", O_APPEND | O_BINARY},
14146 {NULL, 0}
14148 cygwin_internal(CW_PERFILE, pf);
14149 #endif
14151 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
14152 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
14154 id_write = rb_intern_const("write");
14155 id_read = rb_intern_const("read");
14156 id_getc = rb_intern_const("getc");
14157 id_flush = rb_intern_const("flush");
14158 id_readpartial = rb_intern_const("readpartial");
14159 id_set_encoding = rb_intern_const("set_encoding");
14160 id_fileno = rb_intern_const("fileno");
14162 rb_define_global_function("syscall", rb_f_syscall, -1);
14164 rb_define_global_function("open", rb_f_open, -1);
14165 rb_define_global_function("printf", rb_f_printf, -1);
14166 rb_define_global_function("print", rb_f_print, -1);
14167 rb_define_global_function("putc", rb_f_putc, 1);
14168 rb_define_global_function("puts", rb_f_puts, -1);
14169 rb_define_global_function("gets", rb_f_gets, -1);
14170 rb_define_global_function("readline", rb_f_readline, -1);
14171 rb_define_global_function("select", rb_f_select, -1);
14173 rb_define_global_function("readlines", rb_f_readlines, -1);
14175 rb_define_global_function("`", rb_f_backquote, 1);
14177 rb_define_global_function("p", rb_f_p, -1);
14178 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
14180 rb_cIO = rb_define_class("IO", rb_cObject);
14181 rb_include_module(rb_cIO, rb_mEnumerable);
14183 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
14184 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
14185 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
14187 /* exception to wait for reading. see IO.select. */
14188 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
14189 /* exception to wait for writing. see IO.select. */
14190 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
14191 /* exception to wait for reading by EAGAIN. see IO.select. */
14192 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
14193 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
14194 /* exception to wait for writing by EAGAIN. see IO.select. */
14195 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
14196 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
14197 #if EAGAIN == EWOULDBLOCK
14198 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
14199 /* same as IO::EAGAINWaitReadable */
14200 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
14201 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
14202 /* same as IO::EAGAINWaitWritable */
14203 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
14204 #else
14205 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
14206 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
14207 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
14208 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
14209 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
14210 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
14211 #endif
14212 /* exception to wait for reading by EINPROGRESS. see IO.select. */
14213 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
14214 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
14215 /* exception to wait for writing by EINPROGRESS. see IO.select. */
14216 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
14217 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
14219 #if 0
14220 /* This is necessary only for forcing rdoc handle File::open */
14221 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
14222 #endif
14224 rb_define_alloc_func(rb_cIO, io_alloc);
14225 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
14226 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
14227 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
14228 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
14229 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
14230 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
14231 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
14232 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
14233 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
14234 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
14235 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
14236 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
14237 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
14238 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
14239 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
14241 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
14243 rb_output_fs = Qnil;
14244 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
14246 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
14247 rb_gc_register_mark_object(rb_default_rs);
14248 rb_rs = rb_default_rs;
14249 rb_output_rs = Qnil;
14250 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
14251 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
14252 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
14254 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
14255 rb_gvar_ractor_local("$_");
14257 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
14258 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
14260 rb_define_method(rb_cIO, "print", rb_io_print, -1);
14261 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
14262 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
14263 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
14265 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
14266 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
14267 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
14268 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
14269 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
14271 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
14272 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
14274 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
14275 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
14277 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
14278 rb_define_alias(rb_cIO, "to_i", "fileno");
14279 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
14281 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
14282 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
14283 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
14284 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
14286 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
14287 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
14289 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
14291 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
14292 rb_define_method(rb_cIO, "read", io_read, -1);
14293 rb_define_method(rb_cIO, "write", io_write_m, -1);
14294 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
14295 rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
14296 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
14297 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
14298 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
14299 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
14300 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
14301 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
14302 rb_define_method(rb_cIO, "<<", rb_io_addstr, 1);
14303 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
14304 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
14305 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
14306 /* Set I/O position from the beginning */
14307 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
14308 /* Set I/O position from the current position */
14309 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
14310 /* Set I/O position from the end */
14311 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
14312 #ifdef SEEK_DATA
14313 /* Set I/O position to the next location containing data */
14314 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
14315 #endif
14316 #ifdef SEEK_HOLE
14317 /* Set I/O position to the next hole */
14318 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
14319 #endif
14320 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
14321 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
14322 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
14323 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
14324 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
14326 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
14327 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
14329 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
14330 rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
14331 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
14332 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
14334 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
14335 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
14336 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
14337 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
14338 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
14339 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
14341 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
14342 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
14343 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
14344 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
14346 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
14347 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
14348 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
14349 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
14351 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
14352 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
14354 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
14355 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
14356 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
14357 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
14359 rb_gvar_ractor_local("$stdin");
14360 rb_gvar_ractor_local("$stdout");
14361 rb_gvar_ractor_local("$>");
14362 rb_gvar_ractor_local("$stderr");
14364 rb_stdin = rb_io_prep_stdin();
14365 rb_stdout = rb_io_prep_stdout();
14366 rb_stderr = rb_io_prep_stderr();
14368 rb_global_variable(&rb_stdin);
14369 rb_global_variable(&rb_stdout);
14370 rb_global_variable(&rb_stderr);
14372 orig_stdout = rb_stdout;
14373 orig_stderr = rb_stderr;
14375 /* Holds the original stdin */
14376 rb_define_global_const("STDIN", rb_stdin);
14377 /* Holds the original stdout */
14378 rb_define_global_const("STDOUT", rb_stdout);
14379 /* Holds the original stderr */
14380 rb_define_global_const("STDERR", rb_stderr);
14382 #if 0
14383 /* Hack to get rdoc to regard ARGF as a class: */
14384 rb_cARGF = rb_define_class("ARGF", rb_cObject);
14385 #endif
14387 rb_cARGF = rb_class_new(rb_cObject);
14388 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
14389 rb_define_alloc_func(rb_cARGF, argf_alloc);
14391 rb_include_module(rb_cARGF, rb_mEnumerable);
14393 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
14394 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
14395 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
14396 rb_define_alias(rb_cARGF, "inspect", "to_s");
14397 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
14399 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
14400 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
14401 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
14402 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
14403 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
14404 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
14405 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
14406 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
14407 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
14409 rb_define_method(rb_cARGF, "read", argf_read, -1);
14410 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
14411 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
14412 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
14413 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
14414 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
14415 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
14416 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
14417 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
14418 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
14419 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
14420 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
14421 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
14422 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
14423 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
14424 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
14425 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
14426 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
14427 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
14428 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
14430 rb_define_method(rb_cARGF, "write", argf_write, 1);
14431 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
14432 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
14433 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
14434 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
14436 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
14437 rb_define_method(rb_cARGF, "path", argf_filename, 0);
14438 rb_define_method(rb_cARGF, "file", argf_file, 0);
14439 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
14440 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
14441 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
14443 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
14444 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
14446 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
14447 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
14449 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
14450 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
14451 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
14453 argf = rb_class_new_instance(0, 0, rb_cARGF);
14455 rb_define_readonly_variable("$<", &argf);
14457 * ARGF is a stream designed for use in scripts that process files given
14458 * as command-line arguments or passed in via STDIN.
14460 * See ARGF (the class) for more details.
14462 rb_define_global_const("ARGF", argf);
14464 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
14465 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
14466 ARGF.filename = rb_str_new2("-");
14468 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
14469 rb_gvar_ractor_local("$-i");
14471 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
14473 #if defined (_WIN32) || defined(__CYGWIN__)
14474 atexit(pipe_atexit);
14475 #endif
14477 Init_File();
14479 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
14481 sym_mode = ID2SYM(rb_intern_const("mode"));
14482 sym_perm = ID2SYM(rb_intern_const("perm"));
14483 sym_flags = ID2SYM(rb_intern_const("flags"));
14484 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
14485 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
14486 sym_encoding = ID2SYM(rb_id_encoding());
14487 sym_open_args = ID2SYM(rb_intern_const("open_args"));
14488 sym_textmode = ID2SYM(rb_intern_const("textmode"));
14489 sym_binmode = ID2SYM(rb_intern_const("binmode"));
14490 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
14491 sym_normal = ID2SYM(rb_intern_const("normal"));
14492 sym_sequential = ID2SYM(rb_intern_const("sequential"));
14493 sym_random = ID2SYM(rb_intern_const("random"));
14494 sym_willneed = ID2SYM(rb_intern_const("willneed"));
14495 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
14496 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
14497 sym_SET = ID2SYM(rb_intern_const("SET"));
14498 sym_CUR = ID2SYM(rb_intern_const("CUR"));
14499 sym_END = ID2SYM(rb_intern_const("END"));
14500 #ifdef SEEK_DATA
14501 sym_DATA = ID2SYM(rb_intern_const("DATA"));
14502 #endif
14503 #ifdef SEEK_HOLE
14504 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
14505 #endif
14506 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
14507 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
14510 #include "io.rbinc"