Ruby 3.2.2p53 (2023-03-30 revision e51014f9c05aa65cbf203442d37fef7c12390015)
io.c
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#ifdef _WIN32
20# include "ruby/ruby.h"
21# include "ruby/io.h"
22#endif
23
24#include <ctype.h>
25#include <errno.h>
26#include <stddef.h>
27
28/* non-Linux poll may not work on all FDs */
29#if defined(HAVE_POLL)
30# if defined(__linux__)
31# define USE_POLL 1
32# endif
33# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
34# define USE_POLL 1
35# endif
36#endif
37
38#ifndef USE_POLL
39# define USE_POLL 0
40#endif
41
42#undef free
43#define free(x) xfree(x)
44
45#if defined(DOSISH) || defined(__CYGWIN__)
46#include <io.h>
47#endif
48
49#include <sys/types.h>
50#if defined HAVE_NET_SOCKET_H
51# include <net/socket.h>
52#elif defined HAVE_SYS_SOCKET_H
53# include <sys/socket.h>
54#endif
55
56#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
57# define NO_SAFE_RENAME
58#endif
59
60#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
61# define USE_SETVBUF
62#endif
63
64#ifdef __QNXNTO__
65#include <unix.h>
66#endif
67
68#include <sys/types.h>
69#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
70#include <sys/ioctl.h>
71#endif
72#if defined(HAVE_FCNTL_H) || defined(_WIN32)
73#include <fcntl.h>
74#elif defined(HAVE_SYS_FCNTL_H)
75#include <sys/fcntl.h>
76#endif
77
78#ifdef HAVE_SYS_TIME_H
79# include <sys/time.h>
80#endif
81
82#include <sys/stat.h>
83
84#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
85# include <sys/param.h>
86#endif
87
88#if !defined NOFILE
89# define NOFILE 64
90#endif
91
92#ifdef HAVE_UNISTD_H
93#include <unistd.h>
94#endif
95
96#ifdef HAVE_SYSCALL_H
97#include <syscall.h>
98#elif defined HAVE_SYS_SYSCALL_H
99#include <sys/syscall.h>
100#endif
101
102#ifdef HAVE_SYS_UIO_H
103#include <sys/uio.h>
104#endif
105
106#ifdef HAVE_SYS_WAIT_H
107# include <sys/wait.h> /* for WNOHANG on BSD */
108#endif
109
110#ifdef HAVE_COPYFILE_H
111# include <copyfile.h>
112#endif
113
115#include "ccan/list/list.h"
116#include "dln.h"
117#include "encindex.h"
118#include "id.h"
119#include "internal.h"
120#include "internal/encoding.h"
121#include "internal/error.h"
122#include "internal/inits.h"
123#include "internal/io.h"
124#include "internal/numeric.h"
125#include "internal/object.h"
126#include "internal/process.h"
127#include "internal/thread.h"
128#include "internal/transcode.h"
129#include "internal/variable.h"
130#include "ruby/io.h"
131#include "ruby/io/buffer.h"
132#include "ruby/missing.h"
133#include "ruby/thread.h"
134#include "ruby/util.h"
135#include "ruby_atomic.h"
136#include "ruby/ractor.h"
137
138#if !USE_POLL
139# include "vm_core.h"
140#endif
141
142#include "builtin.h"
143
144#ifndef O_ACCMODE
145#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
146#endif
147
148#ifndef PIPE_BUF
149# ifdef _POSIX_PIPE_BUF
150# define PIPE_BUF _POSIX_PIPE_BUF
151# else
152# define PIPE_BUF 512 /* is this ok? */
153# endif
154#endif
155
156#ifndef EWOULDBLOCK
157# define EWOULDBLOCK EAGAIN
158#endif
159
160#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
161/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
162off_t __syscall(quad_t number, ...);
163#endif
164
165#define IO_RBUF_CAPA_MIN 8192
166#define IO_CBUF_CAPA_MIN (128*1024)
167#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
168#define IO_WBUF_CAPA_MIN 8192
169
170#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
171
172/* define system APIs */
173#ifdef _WIN32
174#undef open
175#define open rb_w32_uopen
176#undef rename
177#define rename(f, t) rb_w32_urename((f), (t))
178#endif
179
186
187static VALUE rb_eEAGAINWaitReadable;
188static VALUE rb_eEAGAINWaitWritable;
189static VALUE rb_eEWOULDBLOCKWaitReadable;
190static VALUE rb_eEWOULDBLOCKWaitWritable;
191static VALUE rb_eEINPROGRESSWaitWritable;
192static VALUE rb_eEINPROGRESSWaitReadable;
193
195static VALUE orig_stdout, orig_stderr;
196
197VALUE rb_output_fs;
198VALUE rb_rs;
201
202static VALUE argf;
203
204static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
205static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
206static VALUE sym_textmode, sym_binmode, sym_autoclose;
207static VALUE sym_SET, sym_CUR, sym_END;
208static VALUE sym_wait_readable, sym_wait_writable;
209#ifdef SEEK_DATA
210static VALUE sym_DATA;
211#endif
212#ifdef SEEK_HOLE
213static VALUE sym_HOLE;
214#endif
215
216static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
217
218struct argf {
219 VALUE filename, current_file;
220 long last_lineno; /* $. */
221 long lineno;
222 VALUE argv;
223 VALUE inplace;
224 struct rb_io_enc_t encs;
225 int8_t init_p, next_p, binmode;
226};
227
228static rb_atomic_t max_file_descriptor = NOFILE;
229void
231{
232 rb_atomic_t afd = (rb_atomic_t)fd;
233 rb_atomic_t max_fd = max_file_descriptor;
234 int err;
235
236 if (fd < 0 || afd <= max_fd)
237 return;
238
239#if defined(HAVE_FCNTL) && defined(F_GETFL)
240 err = fcntl(fd, F_GETFL) == -1;
241#else
242 {
243 struct stat buf;
244 err = fstat(fd, &buf) != 0;
245 }
246#endif
247 if (err && errno == EBADF) {
248 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
249 }
250
251 while (max_fd < afd) {
252 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
253 }
254}
255
256void
257rb_maygvl_fd_fix_cloexec(int fd)
258{
259 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
260#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
261 int flags, flags2, ret;
262 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
263 if (flags == -1) {
264 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
265 }
266 if (fd <= 2)
267 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
268 else
269 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
270 if (flags != flags2) {
271 ret = fcntl(fd, F_SETFD, flags2);
272 if (ret != 0) {
273 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
274 }
275 }
276#endif
277}
278
279void
281{
282 rb_maygvl_fd_fix_cloexec(fd);
284}
285
286/* this is only called once */
287static int
288rb_fix_detect_o_cloexec(int fd)
289{
290#if defined(O_CLOEXEC) && defined(F_GETFD)
291 int flags = fcntl(fd, F_GETFD);
292
293 if (flags == -1)
294 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
295
296 if (flags & FD_CLOEXEC)
297 return 1;
298#endif /* fall through if O_CLOEXEC does not work: */
299 rb_maygvl_fd_fix_cloexec(fd);
300 return 0;
301}
302
303static inline bool
304io_again_p(int e)
305{
306 return (e == EWOULDBLOCK) || (e == EAGAIN);
307}
308
309int
310rb_cloexec_open(const char *pathname, int flags, mode_t mode)
311{
312 int ret;
313 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
314
315 static const int retry_interval = 0;
316 static const int retry_max_count = 10000;
317
318 int retry_count = 0;
319
320#ifdef O_CLOEXEC
321 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
322 flags |= O_CLOEXEC;
323#elif defined O_NOINHERIT
324 flags |= O_NOINHERIT;
325#endif
326
327 while ((ret = open(pathname, flags, mode)) == -1) {
328 int e = errno;
329 if (!io_again_p(e)) break;
330 if (retry_count++ >= retry_max_count) break;
331
332 sleep(retry_interval);
333 }
334
335 if (ret < 0) return ret;
336 if (ret <= 2 || o_cloexec_state == 0) {
337 rb_maygvl_fd_fix_cloexec(ret);
338 }
339 else if (o_cloexec_state > 0) {
340 return ret;
341 }
342 else {
343 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
344 }
345 return ret;
346}
347
348int
350{
351 /* Don't allocate standard file descriptors: 0, 1, 2 */
352 return rb_cloexec_fcntl_dupfd(oldfd, 3);
353}
354
355int
356rb_cloexec_dup2(int oldfd, int newfd)
357{
358 int ret;
359
360 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
361 * rb_cloexec_dup2 succeeds as dup2. */
362 if (oldfd == newfd) {
363 ret = newfd;
364 }
365 else {
366#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
367 static int try_dup3 = 1;
368 if (2 < newfd && try_dup3) {
369 ret = dup3(oldfd, newfd, O_CLOEXEC);
370 if (ret != -1)
371 return ret;
372 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
373 if (errno == ENOSYS) {
374 try_dup3 = 0;
375 ret = dup2(oldfd, newfd);
376 }
377 }
378 else {
379 ret = dup2(oldfd, newfd);
380 }
381#else
382 ret = dup2(oldfd, newfd);
383#endif
384 if (ret < 0) return ret;
385 }
386 rb_maygvl_fd_fix_cloexec(ret);
387 return ret;
388}
389
390static int
391rb_fd_set_nonblock(int fd)
392{
393#ifdef _WIN32
394 return rb_w32_set_nonblock(fd);
395#elif defined(F_GETFL)
396 int oflags = fcntl(fd, F_GETFL);
397
398 if (oflags == -1)
399 return -1;
400 if (oflags & O_NONBLOCK)
401 return 0;
402 oflags |= O_NONBLOCK;
403 return fcntl(fd, F_SETFL, oflags);
404#endif
405 return 0;
406}
407
408int
409rb_cloexec_pipe(int descriptors[2])
410{
411#ifdef HAVE_PIPE2
412 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
413#else
414 int result = pipe(descriptors);
415#endif
416
417 if (result < 0)
418 return result;
419
420#ifdef __CYGWIN__
421 if (result == 0 && descriptors[1] == -1) {
422 close(descriptors[0]);
423 descriptors[0] = -1;
424 errno = ENFILE;
425 return -1;
426 }
427#endif
428
429#ifndef HAVE_PIPE2
430 rb_maygvl_fd_fix_cloexec(descriptors[0]);
431 rb_maygvl_fd_fix_cloexec(descriptors[1]);
432
433#ifndef _WIN32
434 rb_fd_set_nonblock(descriptors[0]);
435 rb_fd_set_nonblock(descriptors[1]);
436#endif
437#endif
438
439 return result;
440}
441
442int
443rb_cloexec_fcntl_dupfd(int fd, int minfd)
444{
445 int ret;
446
447#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
448 static int try_dupfd_cloexec = 1;
449 if (try_dupfd_cloexec) {
450 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
451 if (ret != -1) {
452 if (ret <= 2)
453 rb_maygvl_fd_fix_cloexec(ret);
454 return ret;
455 }
456 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
457 if (errno == EINVAL) {
458 ret = fcntl(fd, F_DUPFD, minfd);
459 if (ret != -1) {
460 try_dupfd_cloexec = 0;
461 }
462 }
463 }
464 else {
465 ret = fcntl(fd, F_DUPFD, minfd);
466 }
467#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
468 ret = fcntl(fd, F_DUPFD, minfd);
469#else
470 ret = dup(fd);
471 if (ret >= 0 && ret < minfd) {
472 const int prev_fd = ret;
473 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
474 close(prev_fd);
475 }
476 return ret;
477#endif
478 if (ret < 0) return ret;
479 rb_maygvl_fd_fix_cloexec(ret);
480 return ret;
481}
482
483#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
484#define ARGF argf_of(argf)
485
486#define GetWriteIO(io) rb_io_get_write_io(io)
487
488#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
489#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
490#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
491#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
492
493#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
494#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
495#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
496
497#if defined(_WIN32)
498#define WAIT_FD_IN_WIN32(fptr) \
499 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
500#else
501#define WAIT_FD_IN_WIN32(fptr)
502#endif
503
504#define READ_CHECK(fptr) do {\
505 if (!READ_DATA_PENDING(fptr)) {\
506 WAIT_FD_IN_WIN32(fptr);\
507 rb_io_check_closed(fptr);\
508 }\
509} while(0)
510
511#ifndef S_ISSOCK
512# ifdef _S_ISSOCK
513# define S_ISSOCK(m) _S_ISSOCK(m)
514# else
515# ifdef _S_IFSOCK
516# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
517# else
518# ifdef S_IFSOCK
519# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
520# endif
521# endif
522# endif
523#endif
524
525static int io_fflush(rb_io_t *);
526static rb_io_t *flush_before_seek(rb_io_t *fptr);
527
528#define FMODE_PREP (1<<16)
529#define FMODE_SIGNAL_ON_EPIPE (1<<17)
530
531#define fptr_signal_on_epipe(fptr) \
532 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
533
534#define fptr_set_signal_on_epipe(fptr, flag) \
535 ((flag) ? \
536 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
537 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
538
539extern ID ruby_static_id_signo;
540
541NORETURN(static void raise_on_write(rb_io_t *fptr, int e, VALUE errinfo));
542static void
543raise_on_write(rb_io_t *fptr, int e, VALUE errinfo)
544{
545#if defined EPIPE
546 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
547 const VALUE sig =
548# if defined SIGPIPE
549 INT2FIX(SIGPIPE) - INT2FIX(0) +
550# endif
551 INT2FIX(0);
552 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
553 }
554#endif
555 rb_exc_raise(errinfo);
556}
557
558#define rb_sys_fail_on_write(fptr) \
559 do { \
560 int e = errno; \
561 raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
562 } while (0)
563
564#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
565#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
566#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
567# define RUBY_CRLF_ENVIRONMENT 1
568#else
569# define RUBY_CRLF_ENVIRONMENT 0
570#endif
571
572#if RUBY_CRLF_ENVIRONMENT
573/* Windows */
574# define DEFAULT_TEXTMODE FMODE_TEXTMODE
575# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
576/*
577 * CRLF newline is set as default newline decorator.
578 * If only CRLF newline conversion is needed, we use binary IO process
579 * with OS's text mode for IO performance improvement.
580 * If encoding conversion is needed or a user sets text mode, we use encoding
581 * conversion IO process and universal newline decorator by default.
582 */
583#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
584#define WRITECONV_MASK ( \
585 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
586 ECONV_STATEFUL_DECORATOR_MASK|\
587 0)
588#define NEED_WRITECONV(fptr) ( \
589 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
590 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
591 0)
592#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
593
594#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
595 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
596 if (((fptr)->mode & FMODE_READABLE) &&\
597 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
598 setmode((fptr)->fd, O_BINARY);\
599 }\
600 else {\
601 setmode((fptr)->fd, O_TEXT);\
602 }\
603 }\
604} while(0)
605
606#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
607 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
608 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
609 }\
610} while(0)
611
612/*
613 * IO unread with taking care of removed '\r' in text mode.
614 */
615static void
616io_unread(rb_io_t *fptr)
617{
618 rb_off_t r, pos;
619 ssize_t read_size;
620 long i;
621 long newlines = 0;
622 long extra_max;
623 char *p;
624 char *buf;
625
626 rb_io_check_closed(fptr);
627 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
628 return;
629 }
630
631 errno = 0;
632 if (!rb_w32_fd_is_text(fptr->fd)) {
633 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
634 if (r < 0 && errno) {
635 if (errno == ESPIPE)
636 fptr->mode |= FMODE_DUPLEX;
637 return;
638 }
639
640 fptr->rbuf.off = 0;
641 fptr->rbuf.len = 0;
642 return;
643 }
644
645 pos = lseek(fptr->fd, 0, SEEK_CUR);
646 if (pos < 0 && errno) {
647 if (errno == ESPIPE)
648 fptr->mode |= FMODE_DUPLEX;
649 return;
650 }
651
652 /* add extra offset for removed '\r' in rbuf */
653 extra_max = (long)(pos - fptr->rbuf.len);
654 p = fptr->rbuf.ptr + fptr->rbuf.off;
655
656 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
657 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
658 newlines++;
659 }
660
661 for (i = 0; i < fptr->rbuf.len; i++) {
662 if (*p == '\n') newlines++;
663 if (extra_max == newlines) break;
664 p++;
665 }
666
667 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
668 while (newlines >= 0) {
669 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
670 if (newlines == 0) break;
671 if (r < 0) {
672 newlines--;
673 continue;
674 }
675 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
676 if (read_size < 0) {
677 int e = errno;
678 free(buf);
679 rb_syserr_fail_path(e, fptr->pathv);
680 }
681 if (read_size == fptr->rbuf.len) {
682 lseek(fptr->fd, r, SEEK_SET);
683 break;
684 }
685 else {
686 newlines--;
687 }
688 }
689 free(buf);
690 fptr->rbuf.off = 0;
691 fptr->rbuf.len = 0;
692 return;
693}
694
695/*
696 * We use io_seek to back cursor position when changing mode from text to binary,
697 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
698 * conversion for working properly with mode change.
699 *
700 * Return previous translation mode.
701 */
702static inline int
703set_binary_mode_with_seek_cur(rb_io_t *fptr)
704{
705 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
706
707 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
708 return setmode(fptr->fd, O_BINARY);
709 }
710 flush_before_seek(fptr);
711 return setmode(fptr->fd, O_BINARY);
712}
713#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
714
715#else
716/* Unix */
717# define DEFAULT_TEXTMODE 0
718#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
719#define NEED_WRITECONV(fptr) ( \
720 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
721 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
722 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
723 0)
724#define SET_BINARY_MODE(fptr) (void)(fptr)
725#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
726#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
728#endif
729
730#if !defined HAVE_SHUTDOWN && !defined shutdown
731#define shutdown(a,b) 0
732#endif
733
734#if defined(_WIN32)
735#define is_socket(fd, path) rb_w32_is_socket(fd)
736#elif !defined(S_ISSOCK)
737#define is_socket(fd, path) 0
738#else
739static int
740is_socket(int fd, VALUE path)
741{
742 struct stat sbuf;
743 if (fstat(fd, &sbuf) < 0)
744 rb_sys_fail_path(path);
745 return S_ISSOCK(sbuf.st_mode);
746}
747#endif
748
749static const char closed_stream[] = "closed stream";
750
751static void
752io_fd_check_closed(int fd)
753{
754 if (fd < 0) {
755 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
756 rb_raise(rb_eIOError, closed_stream);
757 }
758}
759
760void
761rb_eof_error(void)
762{
763 rb_raise(rb_eEOFError, "end of file reached");
764}
765
766VALUE
768{
769 rb_check_frozen(io);
770 return io;
771}
772
773void
775{
776 if (!fptr) {
777 rb_raise(rb_eIOError, "uninitialized stream");
778 }
779}
780
781void
783{
785 io_fd_check_closed(fptr->fd);
786}
787
788static rb_io_t *
789rb_io_get_fptr(VALUE io)
790{
791 rb_io_t *fptr = RFILE(io)->fptr;
793 return fptr;
794}
795
796VALUE
798{
799 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
800}
801
802VALUE
804{
805 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
806}
807
808VALUE
810{
811 VALUE write_io;
812 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
813 if (write_io) {
814 return write_io;
815 }
816 return io;
817}
818
819VALUE
821{
822 VALUE write_io;
823 rb_io_t *fptr = rb_io_get_fptr(io);
824 if (!RTEST(w)) {
825 w = 0;
826 }
827 else {
828 GetWriteIO(w);
829 }
830 write_io = fptr->tied_io_for_writing;
831 fptr->tied_io_for_writing = w;
832 return write_io ? write_io : Qnil;
833}
834
835/*
836 * call-seq:
837 * timeout -> duration or nil
838 *
839 * Get the internal timeout duration or nil if it was not set.
840 *
841 */
842VALUE
844{
845 rb_io_t *fptr = rb_io_get_fptr(self);
846
847 return fptr->timeout;
848}
849
850/*
851 * call-seq:
852 * timeout = duration -> duration
853 * timeout = nil -> nil
854 *
855 * Set the internal timeout to the specified duration or nil. The timeout
856 * applies to all blocking operations where possible.
857 *
858 * This affects the following methods (but is not limited to): #gets, #puts,
859 * #read, #write, #wait_readable and #wait_writable. This also affects
860 * blocking socket operations like Socket#accept and Socket#connect.
861 *
862 * Some operations like File#open and IO#close are not affected by the
863 * timeout. A timeout during a write operation may leave the IO in an
864 * inconsistent state, e.g. data was partially written. Generally speaking, a
865 * timeout is a last ditch effort to prevent an application from hanging on
866 * slow I/O operations, such as those that occur during a slowloris attack.
867 */
868VALUE
870{
871 // Validate it:
872 if (RTEST(timeout)) {
873 rb_time_interval(timeout);
874 }
875
876 rb_io_t *fptr = rb_io_get_fptr(self);
877
878 fptr->timeout = timeout;
879
880 return self;
881}
882
883/*
884 * call-seq:
885 * IO.try_convert(object) -> new_io or nil
886 *
887 * Attempts to convert +object+ into an \IO object via method +to_io+;
888 * returns the new \IO object if successful, or +nil+ otherwise:
889 *
890 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
891 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
892 * IO.try_convert('STDOUT') # => nil
893 *
894 */
895static VALUE
896rb_io_s_try_convert(VALUE dummy, VALUE io)
897{
898 return rb_io_check_io(io);
899}
900
901#if !RUBY_CRLF_ENVIRONMENT
902static void
903io_unread(rb_io_t *fptr)
904{
905 rb_off_t r;
906 rb_io_check_closed(fptr);
907 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
908 return;
909 /* xxx: target position may be negative if buffer is filled by ungetc */
910 errno = 0;
911 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
912 if (r < 0 && errno) {
913 if (errno == ESPIPE)
914 fptr->mode |= FMODE_DUPLEX;
915 return;
916 }
917 fptr->rbuf.off = 0;
918 fptr->rbuf.len = 0;
919 return;
920}
921#endif
922
923static rb_encoding *io_input_encoding(rb_io_t *fptr);
924
925static void
926io_ungetbyte(VALUE str, rb_io_t *fptr)
927{
928 long len = RSTRING_LEN(str);
929
930 if (fptr->rbuf.ptr == NULL) {
931 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
932 fptr->rbuf.off = 0;
933 fptr->rbuf.len = 0;
934#if SIZEOF_LONG > SIZEOF_INT
935 if (len > INT_MAX)
936 rb_raise(rb_eIOError, "ungetbyte failed");
937#endif
938 if (len > min_capa)
939 fptr->rbuf.capa = (int)len;
940 else
941 fptr->rbuf.capa = min_capa;
942 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
943 }
944 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
945 rb_raise(rb_eIOError, "ungetbyte failed");
946 }
947 if (fptr->rbuf.off < len) {
948 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
949 fptr->rbuf.ptr+fptr->rbuf.off,
950 char, fptr->rbuf.len);
951 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
952 }
953 fptr->rbuf.off-=(int)len;
954 fptr->rbuf.len+=(int)len;
955 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
956}
957
958static rb_io_t *
959flush_before_seek(rb_io_t *fptr)
960{
961 if (io_fflush(fptr) < 0)
962 rb_sys_fail_on_write(fptr);
963 io_unread(fptr);
964 errno = 0;
965 return fptr;
966}
967
968#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
969#define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
970
971#ifndef SEEK_CUR
972# define SEEK_SET 0
973# define SEEK_CUR 1
974# define SEEK_END 2
975#endif
976
977void
979{
980 rb_io_check_closed(fptr);
981 if (!(fptr->mode & FMODE_READABLE)) {
982 rb_raise(rb_eIOError, "not opened for reading");
983 }
984 if (fptr->wbuf.len) {
985 if (io_fflush(fptr) < 0)
986 rb_sys_fail_on_write(fptr);
987 }
988 if (fptr->tied_io_for_writing) {
989 rb_io_t *wfptr;
990 GetOpenFile(fptr->tied_io_for_writing, wfptr);
991 if (io_fflush(wfptr) < 0)
992 rb_sys_fail_on_write(wfptr);
993 }
994}
995
996void
998{
1000 if (READ_CHAR_PENDING(fptr)) {
1001 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1002 }
1003}
1004
1005void
1010
1011static rb_encoding*
1012io_read_encoding(rb_io_t *fptr)
1013{
1014 if (fptr->encs.enc) {
1015 return fptr->encs.enc;
1016 }
1017 return rb_default_external_encoding();
1018}
1019
1020static rb_encoding*
1021io_input_encoding(rb_io_t *fptr)
1022{
1023 if (fptr->encs.enc2) {
1024 return fptr->encs.enc2;
1025 }
1026 return io_read_encoding(fptr);
1027}
1028
1029void
1031{
1032 rb_io_check_closed(fptr);
1033 if (!(fptr->mode & FMODE_WRITABLE)) {
1034 rb_raise(rb_eIOError, "not opened for writing");
1035 }
1036 if (fptr->rbuf.len) {
1037 io_unread(fptr);
1038 }
1039}
1040
1041int
1042rb_io_read_pending(rb_io_t *fptr)
1043{
1044 /* This function is used for bytes and chars. Confusing. */
1045 if (READ_CHAR_PENDING(fptr))
1046 return 1; /* should raise? */
1047 return READ_DATA_PENDING(fptr);
1048}
1049
1050void
1052{
1053 if (!READ_DATA_PENDING(fptr)) {
1054 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1055 }
1056 return;
1057}
1058
1059int
1060rb_gc_for_fd(int err)
1061{
1062 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1063 rb_gc();
1064 return 1;
1065 }
1066 return 0;
1067}
1068
1069static int
1070ruby_dup(int orig)
1071{
1072 int fd;
1073
1074 fd = rb_cloexec_dup(orig);
1075 if (fd < 0) {
1076 int e = errno;
1077 if (rb_gc_for_fd(e)) {
1078 fd = rb_cloexec_dup(orig);
1079 }
1080 if (fd < 0) {
1081 rb_syserr_fail(e, 0);
1082 }
1083 }
1084 rb_update_max_fd(fd);
1085 return fd;
1086}
1087
1088static VALUE
1089io_alloc(VALUE klass)
1090{
1091 NEWOBJ_OF(io, struct RFile, klass, T_FILE);
1092
1093 io->fptr = 0;
1094
1095 return (VALUE)io;
1096}
1097
1098#ifndef S_ISREG
1099# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1100#endif
1101
1103 VALUE th;
1104 rb_io_t *fptr;
1105 int nonblock;
1106 int fd;
1107
1108 void *buf;
1109 size_t capa;
1110 struct timeval *timeout;
1111};
1112
1114 VALUE th;
1115 rb_io_t *fptr;
1116 int nonblock;
1117 int fd;
1118
1119 const void *buf;
1120 size_t capa;
1121 struct timeval *timeout;
1122};
1123
1124#ifdef HAVE_WRITEV
1125struct io_internal_writev_struct {
1126 VALUE th;
1127 rb_io_t *fptr;
1128 int nonblock;
1129 int fd;
1130
1131 int iovcnt;
1132 const struct iovec *iov;
1133 struct timeval *timeout;
1134};
1135#endif
1136
1137static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1138
1144static inline int
1145io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1146{
1147 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1148
1149 if (ready > 0) {
1150 return ready;
1151 } else if (ready == 0) {
1152 errno = ETIMEDOUT;
1153 return -1;
1154 }
1155
1156 errno = error;
1157 return -1;
1158}
1159
1160static VALUE
1161internal_read_func(void *ptr)
1162{
1163 struct io_internal_read_struct *iis = ptr;
1164 ssize_t result;
1165
1166 if (iis->timeout && !iis->nonblock) {
1167 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1168 return -1;
1169 }
1170 }
1171
1172 retry:
1173 result = read(iis->fd, iis->buf, iis->capa);
1174
1175 if (result < 0 && !iis->nonblock) {
1176 if (io_again_p(errno)) {
1177 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1178 return -1;
1179 } else {
1180 goto retry;
1181 }
1182 }
1183 }
1184
1185 return result;
1186}
1187
1188#if defined __APPLE__
1189# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1190#else
1191# define do_write_retry(code) result = code
1192#endif
1193
1194static VALUE
1195internal_write_func(void *ptr)
1196{
1197 struct io_internal_write_struct *iis = ptr;
1198 ssize_t result;
1199
1200 if (iis->timeout && !iis->nonblock) {
1201 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1202 return -1;
1203 }
1204 }
1205
1206 retry:
1207 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1208
1209 if (result < 0 && !iis->nonblock) {
1210 int e = errno;
1211 if (io_again_p(e)) {
1212 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1213 return -1;
1214 } else {
1215 goto retry;
1216 }
1217 }
1218 }
1219
1220 return result;
1221}
1222
1223#ifdef HAVE_WRITEV
1224static VALUE
1225internal_writev_func(void *ptr)
1226{
1227 struct io_internal_writev_struct *iis = ptr;
1228 ssize_t result;
1229
1230 if (iis->timeout && !iis->nonblock) {
1231 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1232 return -1;
1233 }
1234 }
1235
1236 retry:
1237 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1238
1239 if (result < 0 && !iis->nonblock) {
1240 if (io_again_p(errno)) {
1241 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1242 return -1;
1243 } else {
1244 goto retry;
1245 }
1246 }
1247 }
1248
1249 return result;
1250}
1251#endif
1252
1253static ssize_t
1254rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1255{
1256 VALUE scheduler = rb_fiber_scheduler_current();
1257 if (scheduler != Qnil) {
1258 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1259
1260 if (!UNDEF_P(result)) {
1262 }
1263 }
1264
1265 struct io_internal_read_struct iis = {
1266 .th = rb_thread_current(),
1267 .fptr = fptr,
1268 .nonblock = 0,
1269 .fd = fptr->fd,
1270
1271 .buf = buf,
1272 .capa = count,
1273 .timeout = NULL,
1274 };
1275
1276 struct timeval timeout_storage;
1277
1278 if (fptr->timeout != Qnil) {
1279 timeout_storage = rb_time_interval(fptr->timeout);
1280 iis.timeout = &timeout_storage;
1281 }
1282
1283 return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fptr->fd);
1284}
1285
1286static ssize_t
1287rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1288{
1289 VALUE scheduler = rb_fiber_scheduler_current();
1290 if (scheduler != Qnil) {
1291 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1292
1293 if (!UNDEF_P(result)) {
1295 }
1296 }
1297
1298 struct io_internal_write_struct iis = {
1299 .th = rb_thread_current(),
1300 .fptr = fptr,
1301 .nonblock = 0,
1302 .fd = fptr->fd,
1303
1304 .buf = buf,
1305 .capa = count,
1306 .timeout = NULL
1307 };
1308
1309 struct timeval timeout_storage;
1310
1311 if (fptr->timeout != Qnil) {
1312 timeout_storage = rb_time_interval(fptr->timeout);
1313 iis.timeout = &timeout_storage;
1314 }
1315
1316 return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fptr->fd);
1317}
1318
1319#ifdef HAVE_WRITEV
1320static ssize_t
1321rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1322{
1323 VALUE scheduler = rb_fiber_scheduler_current();
1324 if (scheduler != Qnil) {
1325 for (int i = 0; i < iovcnt; i += 1) {
1326 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[i].iov_base, iov[i].iov_len, 0);
1327
1328 if (!UNDEF_P(result)) {
1330 }
1331 }
1332 }
1333
1334 struct io_internal_writev_struct iis = {
1335 .th = rb_thread_current(),
1336 .fptr = fptr,
1337 .nonblock = 0,
1338 .fd = fptr->fd,
1339
1340 .iov = iov,
1341 .iovcnt = iovcnt,
1342 .timeout = NULL
1343 };
1344
1345 struct timeval timeout_storage;
1346
1347 if (fptr->timeout != Qnil) {
1348 timeout_storage = rb_time_interval(fptr->timeout);
1349 iis.timeout = &timeout_storage;
1350 }
1351
1352 return (ssize_t)rb_thread_io_blocking_region(internal_writev_func, &iis, fptr->fd);
1353}
1354#endif
1355
1356static VALUE
1357io_flush_buffer_sync(void *arg)
1358{
1359 rb_io_t *fptr = arg;
1360 long l = fptr->wbuf.len;
1361 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1362
1363 if (fptr->wbuf.len <= r) {
1364 fptr->wbuf.off = 0;
1365 fptr->wbuf.len = 0;
1366 return 0;
1367 }
1368
1369 if (0 <= r) {
1370 fptr->wbuf.off += (int)r;
1371 fptr->wbuf.len -= (int)r;
1372 errno = EAGAIN;
1373 }
1374
1375 return (VALUE)-1;
1376}
1377
1378static VALUE
1379io_flush_buffer_async(VALUE arg)
1380{
1381 rb_io_t *fptr = (rb_io_t *)arg;
1382 return rb_thread_io_blocking_region(io_flush_buffer_sync, fptr, fptr->fd);
1383}
1384
1385static inline int
1386io_flush_buffer(rb_io_t *fptr)
1387{
1388 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1389 return (int)io_flush_buffer_async((VALUE)fptr);
1390 }
1391 else {
1392 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1393 }
1394}
1395
1396static int
1397io_fflush(rb_io_t *fptr)
1398{
1399 rb_io_check_closed(fptr);
1400
1401 if (fptr->wbuf.len == 0)
1402 return 0;
1403
1404 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1405 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1406 return -1;
1407
1408 rb_io_check_closed(fptr);
1409 }
1410
1411 return 0;
1412}
1413
1414VALUE
1415rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1416{
1417 VALUE scheduler = rb_fiber_scheduler_current();
1418
1419 if (scheduler != Qnil) {
1420 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1421 }
1422
1423 rb_io_t * fptr = NULL;
1424 RB_IO_POINTER(io, fptr);
1425
1426 struct timeval tv_storage;
1427 struct timeval *tv = NULL;
1428
1429 if (NIL_OR_UNDEF_P(timeout)) {
1430 timeout = fptr->timeout;
1431 }
1432
1433 if (timeout != Qnil) {
1434 tv_storage = rb_time_interval(timeout);
1435 tv = &tv_storage;
1436 }
1437
1438 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1439
1440 if (ready < 0) {
1441 rb_sys_fail(0);
1442 }
1443
1444 // Not sure if this is necessary:
1445 rb_io_check_closed(fptr);
1446
1447 if (ready) {
1448 return RB_INT2NUM(ready);
1449 }
1450 else {
1451 return Qfalse;
1452 }
1453}
1454
1455static VALUE
1456io_from_fd(int fd)
1457{
1458 return prep_io(fd, FMODE_PREP, rb_cIO, NULL);
1459}
1460
1461static int
1462io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1463{
1464 VALUE scheduler = rb_fiber_scheduler_current();
1465
1466 if (scheduler != Qnil) {
1467 return RTEST(
1468 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1469 );
1470 }
1471
1472 return rb_thread_wait_for_single_fd(fd, events, timeout);
1473}
1474
1475int
1477{
1478 io_fd_check_closed(f);
1479
1480 VALUE scheduler = rb_fiber_scheduler_current();
1481
1482 switch (errno) {
1483 case EINTR:
1484#if defined(ERESTART)
1485 case ERESTART:
1486#endif
1488 return TRUE;
1489
1490 case EAGAIN:
1491#if EWOULDBLOCK != EAGAIN
1492 case EWOULDBLOCK:
1493#endif
1494 if (scheduler != Qnil) {
1495 return RTEST(
1496 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1497 );
1498 }
1499 else {
1500 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1501 }
1502 return TRUE;
1503
1504 default:
1505 return FALSE;
1506 }
1507}
1508
1509int
1511{
1512 io_fd_check_closed(f);
1513
1514 VALUE scheduler = rb_fiber_scheduler_current();
1515
1516 switch (errno) {
1517 case EINTR:
1518#if defined(ERESTART)
1519 case ERESTART:
1520#endif
1521 /*
1522 * In old Linux, several special files under /proc and /sys don't handle
1523 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1524 * Otherwise, we face nasty hang up. Sigh.
1525 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1526 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1527 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1528 * Then rb_thread_check_ints() is enough.
1529 */
1531 return TRUE;
1532
1533 case EAGAIN:
1534#if EWOULDBLOCK != EAGAIN
1535 case EWOULDBLOCK:
1536#endif
1537 if (scheduler != Qnil) {
1538 return RTEST(
1539 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1540 );
1541 }
1542 else {
1543 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1544 }
1545 return TRUE;
1546
1547 default:
1548 return FALSE;
1549 }
1550}
1551
1552int
1553rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1554{
1555 return io_wait_for_single_fd(fd, events, timeout);
1556}
1557
1558int
1560{
1561 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1562}
1563
1564int
1566{
1567 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1568}
1569
1570VALUE
1571rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1572{
1573 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1574 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1575 // instead relies on `read(-1) -> -1` which causes this code path. We then
1576 // check here whether the IO was in fact closed. Probably it's better to
1577 // check that `fptr->fd != -1` before using it in syscall.
1578 rb_io_check_closed(RFILE(io)->fptr);
1579
1580 switch (error) {
1581 // In old Linux, several special files under /proc and /sys don't handle
1582 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1583 // Otherwise, we face nasty hang up. Sigh.
1584 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1585 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1586 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1587 // Then rb_thread_check_ints() is enough.
1588 case EINTR:
1589#if defined(ERESTART)
1590 case ERESTART:
1591#endif
1592 // We might have pending interrupts since the previous syscall was interrupted:
1594
1595 // The operation was interrupted, so retry it immediately:
1596 return events;
1597
1598 case EAGAIN:
1599#if EWOULDBLOCK != EAGAIN
1600 case EWOULDBLOCK:
1601#endif
1602 // The operation would block, so wait for the specified events:
1603 return rb_io_wait(io, events, timeout);
1604
1605 default:
1606 // Non-specific error, no event is ready:
1607 return Qfalse;
1608 }
1609}
1610
1611int
1613{
1614 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1615
1616 if (RTEST(result)) {
1617 return RB_NUM2INT(result);
1618 }
1619 else {
1620 return 0;
1621 }
1622}
1623
1624int
1626{
1627 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1628
1629 if (RTEST(result)) {
1630 return RB_NUM2INT(result);
1631 }
1632 else {
1633 return 0;
1634 }
1635}
1636
1637static void
1638make_writeconv(rb_io_t *fptr)
1639{
1640 if (!fptr->writeconv_initialized) {
1641 const char *senc, *denc;
1642 rb_encoding *enc;
1643 int ecflags;
1644 VALUE ecopts;
1645
1646 fptr->writeconv_initialized = 1;
1647
1648 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1649 ecopts = fptr->encs.ecopts;
1650
1651 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1652 /* no encoding conversion */
1653 fptr->writeconv_pre_ecflags = 0;
1654 fptr->writeconv_pre_ecopts = Qnil;
1655 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1656 if (!fptr->writeconv)
1657 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1659 }
1660 else {
1661 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1662 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1663 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1664 /* single conversion */
1665 fptr->writeconv_pre_ecflags = ecflags;
1666 fptr->writeconv_pre_ecopts = ecopts;
1667 fptr->writeconv = NULL;
1669 }
1670 else {
1671 /* double conversion */
1672 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1673 fptr->writeconv_pre_ecopts = ecopts;
1674 if (senc) {
1675 denc = rb_enc_name(enc);
1676 fptr->writeconv_asciicompat = rb_str_new2(senc);
1677 }
1678 else {
1679 senc = denc = "";
1680 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1681 }
1683 ecopts = fptr->encs.ecopts;
1684 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1685 if (!fptr->writeconv)
1686 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1687 }
1688 }
1689 }
1690}
1691
1692/* writing functions */
1694 rb_io_t *fptr;
1695 VALUE str;
1696 const char *ptr;
1697 long length;
1698};
1699
1701 VALUE io;
1702 VALUE str;
1703 int nosync;
1704};
1705
1706#ifdef HAVE_WRITEV
1707static ssize_t
1708io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1709{
1710 if (fptr->wbuf.len) {
1711 struct iovec iov[2];
1712
1713 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1714 iov[0].iov_len = fptr->wbuf.len;
1715 iov[1].iov_base = (void*)ptr;
1716 iov[1].iov_len = length;
1717
1718 ssize_t result = rb_writev_internal(fptr, iov, 2);
1719
1720 if (result < 0)
1721 return result;
1722
1723 if (result >= fptr->wbuf.len) {
1724 // We wrote more than the internal buffer:
1725 result -= fptr->wbuf.len;
1726 fptr->wbuf.off = 0;
1727 fptr->wbuf.len = 0;
1728 }
1729 else {
1730 // We only wrote less data than the internal buffer:
1731 fptr->wbuf.off += (int)result;
1732 fptr->wbuf.len -= (int)result;
1733
1734 result = 0;
1735 }
1736
1737 return result;
1738 }
1739 else {
1740 return rb_io_write_memory(fptr, ptr, length);
1741 }
1742}
1743#else
1744static ssize_t
1745io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1746{
1747 long remaining = length;
1748
1749 if (fptr->wbuf.len) {
1750 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1751 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1752 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1753 fptr->wbuf.off = 0;
1754 }
1755
1756 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1757 fptr->wbuf.len += (int)length;
1758
1759 // We copied the entire incoming data to the internal buffer:
1760 remaining = 0;
1761 }
1762
1763 // Flush the internal buffer:
1764 if (io_fflush(fptr) < 0) {
1765 return -1;
1766 }
1767
1768 // If all the data was buffered, we are done:
1769 if (remaining == 0) {
1770 return length;
1771 }
1772 }
1773
1774 // Otherwise, we should write the data directly:
1775 return rb_io_write_memory(fptr, ptr, length);
1776}
1777#endif
1778
1779static VALUE
1780io_binwrite_string(VALUE arg)
1781{
1782 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1783
1784 const char *ptr = p->ptr;
1785 size_t remaining = p->length;
1786
1787 while (remaining) {
1788 // Write as much as possible:
1789 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1790
1791 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1792 // should try again.
1793 if (result == 0) {
1794 errno = EWOULDBLOCK;
1795 }
1796
1797 if (result > 0) {
1798 if ((size_t)result == remaining) break;
1799 ptr += result;
1800 remaining -= result;
1801 }
1802 // Wait for it to become writable:
1803 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1804 rb_io_check_closed(p->fptr);
1805 }
1806 else {
1807 // The error was unrelated to waiting for it to become writable, so we fail:
1808 return -1;
1809 }
1810 }
1811
1812 return p->length;
1813}
1814
1815inline static void
1816io_allocate_write_buffer(rb_io_t *fptr, int sync)
1817{
1818 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1819 fptr->wbuf.off = 0;
1820 fptr->wbuf.len = 0;
1821 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1822 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1823 }
1824
1825 if (NIL_P(fptr->write_lock)) {
1826 fptr->write_lock = rb_mutex_new();
1827 rb_mutex_allow_trap(fptr->write_lock, 1);
1828 }
1829}
1830
1831static inline int
1832io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1833{
1834 // If the requested operation was synchronous and the output mode is synchronus or a TTY:
1835 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1836 return 1;
1837
1838 // If the amount of data we want to write exceeds the internal buffer:
1839 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1840 return 1;
1841
1842 // Otherwise, we can append to the internal buffer:
1843 return 0;
1844}
1845
1846static long
1847io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
1848{
1849 if (len <= 0) return len;
1850
1851 // Don't write anything if current thread has a pending interrupt:
1853
1854 io_allocate_write_buffer(fptr, !nosync);
1855
1856 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1857 struct binwrite_arg arg;
1858
1859 arg.fptr = fptr;
1860 arg.str = str;
1861 arg.ptr = ptr;
1862 arg.length = len;
1863
1864 if (!NIL_P(fptr->write_lock)) {
1865 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1866 }
1867 else {
1868 return io_binwrite_string((VALUE)&arg);
1869 }
1870 }
1871 else {
1872 if (fptr->wbuf.off) {
1873 if (fptr->wbuf.len)
1874 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1875 fptr->wbuf.off = 0;
1876 }
1877
1878 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1879 fptr->wbuf.len += (int)len;
1880
1881 return len;
1882 }
1883}
1884
1885# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1886 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1887
1888#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1889 MODE_BTMODE(d, e, f) : \
1890 MODE_BTMODE(a, b, c))
1891
1892static VALUE
1893do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1894{
1895 if (NEED_WRITECONV(fptr)) {
1896 VALUE common_encoding = Qnil;
1897 SET_BINARY_MODE(fptr);
1898
1899 make_writeconv(fptr);
1900
1901 if (fptr->writeconv) {
1902#define fmode (fptr->mode)
1903 if (!NIL_P(fptr->writeconv_asciicompat))
1904 common_encoding = fptr->writeconv_asciicompat;
1905 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1906 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1907 rb_enc_name(rb_enc_get(str)));
1908 }
1909#undef fmode
1910 }
1911 else {
1912 if (fptr->encs.enc2)
1913 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1914 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1915 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1916 }
1917
1918 if (!NIL_P(common_encoding)) {
1919 str = rb_str_encode(str, common_encoding,
1921 *converted = 1;
1922 }
1923
1924 if (fptr->writeconv) {
1926 *converted = 1;
1927 }
1928 }
1929#if RUBY_CRLF_ENVIRONMENT
1930#define fmode (fptr->mode)
1931 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1932 if ((fptr->mode & FMODE_READABLE) &&
1934 setmode(fptr->fd, O_BINARY);
1935 }
1936 else {
1937 setmode(fptr->fd, O_TEXT);
1938 }
1939 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1940 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1941 rb_enc_name(rb_enc_get(str)));
1942 }
1943 }
1944#undef fmode
1945#endif
1946 return str;
1947}
1948
1949static long
1950io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1951{
1952 int converted = 0;
1953 VALUE tmp;
1954 long n, len;
1955 const char *ptr;
1956
1957#ifdef _WIN32
1958 if (fptr->mode & FMODE_TTY) {
1959 long len = rb_w32_write_console(str, fptr->fd);
1960 if (len > 0) return len;
1961 }
1962#endif
1963
1964 str = do_writeconv(str, fptr, &converted);
1965 if (converted)
1966 OBJ_FREEZE(str);
1967
1968 tmp = rb_str_tmp_frozen_acquire(str);
1969 RSTRING_GETMEM(tmp, ptr, len);
1970 n = io_binwrite(tmp, ptr, len, fptr, nosync);
1971 rb_str_tmp_frozen_release(str, tmp);
1972
1973 return n;
1974}
1975
1976ssize_t
1977rb_io_bufwrite(VALUE io, const void *buf, size_t size)
1978{
1979 rb_io_t *fptr;
1980
1981 GetOpenFile(io, fptr);
1983 return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
1984}
1985
1986static VALUE
1987io_write(VALUE io, VALUE str, int nosync)
1988{
1989 rb_io_t *fptr;
1990 long n;
1991 VALUE tmp;
1992
1993 io = GetWriteIO(io);
1994 str = rb_obj_as_string(str);
1995 tmp = rb_io_check_io(io);
1996
1997 if (NIL_P(tmp)) {
1998 /* port is not IO, call write method for it. */
1999 return rb_funcall(io, id_write, 1, str);
2000 }
2001
2002 io = tmp;
2003 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2004
2005 GetOpenFile(io, fptr);
2007
2008 n = io_fwrite(str, fptr, nosync);
2009 if (n < 0L) rb_sys_fail_on_write(fptr);
2010
2011 return LONG2FIX(n);
2012}
2013
2014#ifdef HAVE_WRITEV
2015struct binwritev_arg {
2016 rb_io_t *fptr;
2017 struct iovec *iov;
2018 int iovcnt;
2019 size_t total;
2020};
2021
2022static VALUE
2023io_binwritev_internal(VALUE arg)
2024{
2025 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2026
2027 size_t remaining = p->total;
2028 size_t offset = 0;
2029
2030 rb_io_t *fptr = p->fptr;
2031 struct iovec *iov = p->iov;
2032 int iovcnt = p->iovcnt;
2033
2034 while (remaining) {
2035 long result = rb_writev_internal(fptr, iov, iovcnt);
2036
2037 if (result > 0) {
2038 offset += result;
2039 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2040 if (offset < (size_t)fptr->wbuf.len) {
2041 fptr->wbuf.off += result;
2042 fptr->wbuf.len -= result;
2043 }
2044 else {
2045 offset -= (size_t)fptr->wbuf.len;
2046 fptr->wbuf.off = 0;
2047 fptr->wbuf.len = 0;
2048 }
2049 }
2050
2051 if (offset == p->total) {
2052 return p->total;
2053 }
2054
2055 while (result >= (ssize_t)iov->iov_len) {
2056 /* iovcnt > 0 */
2057 result -= iov->iov_len;
2058 iov->iov_len = 0;
2059 iov++;
2060
2061 if (!--iovcnt) {
2062 // I don't believe this code path can ever occur.
2063 return offset;
2064 }
2065 }
2066
2067 iov->iov_base = (char *)iov->iov_base + result;
2068 iov->iov_len -= result;
2069 }
2070 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2071 rb_io_check_closed(fptr);
2072 }
2073 else {
2074 return -1;
2075 }
2076 }
2077
2078 return offset;
2079}
2080
2081static long
2082io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2083{
2084 // Don't write anything if current thread has a pending interrupt:
2086
2087 if (iovcnt == 0) return 0;
2088
2089 size_t total = 0;
2090 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2091
2092 io_allocate_write_buffer(fptr, 1);
2093
2094 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2095 // The end of the buffered data:
2096 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2097
2098 if (offset + total <= (size_t)fptr->wbuf.capa) {
2099 for (int i = 1; i < iovcnt; i++) {
2100 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2101 offset += iov[i].iov_len;
2102 }
2103
2104 fptr->wbuf.len += total;
2105
2106 return total;
2107 }
2108 else {
2109 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2110 iov[0].iov_len = fptr->wbuf.len;
2111 }
2112 }
2113 else {
2114 // The first iov is reserved for the internal buffer, and it's empty.
2115 iov++;
2116
2117 if (!--iovcnt) {
2118 // If there are no other io vectors we are done.
2119 return 0;
2120 }
2121 }
2122
2123 struct binwritev_arg arg;
2124 arg.fptr = fptr;
2125 arg.iov = iov;
2126 arg.iovcnt = iovcnt;
2127 arg.total = total;
2128
2129 if (!NIL_P(fptr->write_lock)) {
2130 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2131 }
2132 else {
2133 return io_binwritev_internal((VALUE)&arg);
2134 }
2135}
2136
2137static long
2138io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2139{
2140 int i, converted, iovcnt = argc + 1;
2141 long n;
2142 VALUE v1, v2, str, tmp, *tmp_array;
2143 struct iovec *iov;
2144
2145 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2146 tmp_array = ALLOCV_N(VALUE, v2, argc);
2147
2148 for (i = 0; i < argc; i++) {
2149 str = rb_obj_as_string(argv[i]);
2150 converted = 0;
2151 str = do_writeconv(str, fptr, &converted);
2152
2153 if (converted)
2154 OBJ_FREEZE(str);
2155
2156 tmp = rb_str_tmp_frozen_acquire(str);
2157 tmp_array[i] = tmp;
2158
2159 /* iov[0] is reserved for buffer of fptr */
2160 iov[i+1].iov_base = RSTRING_PTR(tmp);
2161 iov[i+1].iov_len = RSTRING_LEN(tmp);
2162 }
2163
2164 n = io_binwritev(iov, iovcnt, fptr);
2165 if (v1) ALLOCV_END(v1);
2166
2167 for (i = 0; i < argc; i++) {
2168 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2169 }
2170
2171 if (v2) ALLOCV_END(v2);
2172
2173 return n;
2174}
2175
2176static int
2177iovcnt_ok(int iovcnt)
2178{
2179#ifdef IOV_MAX
2180 return iovcnt < IOV_MAX;
2181#else /* GNU/Hurd has writev, but no IOV_MAX */
2182 return 1;
2183#endif
2184}
2185#endif /* HAVE_WRITEV */
2186
2187static VALUE
2188io_writev(int argc, const VALUE *argv, VALUE io)
2189{
2190 rb_io_t *fptr;
2191 long n;
2192 VALUE tmp, total = INT2FIX(0);
2193 int i, cnt = 1;
2194
2195 io = GetWriteIO(io);
2196 tmp = rb_io_check_io(io);
2197
2198 if (NIL_P(tmp)) {
2199 /* port is not IO, call write method for it. */
2200 return rb_funcallv(io, id_write, argc, argv);
2201 }
2202
2203 io = tmp;
2204
2205 GetOpenFile(io, fptr);
2207
2208 for (i = 0; i < argc; i += cnt) {
2209#ifdef HAVE_WRITEV
2210 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2211 n = io_fwritev(cnt, &argv[i], fptr);
2212 }
2213 else
2214#endif
2215 {
2216 cnt = 1;
2217 /* sync at last item */
2218 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2219 }
2220
2221 if (n < 0L)
2222 rb_sys_fail_on_write(fptr);
2223
2224 total = rb_fix_plus(LONG2FIX(n), total);
2225 }
2226
2227 return total;
2228}
2229
2230/*
2231 * call-seq:
2232 * write(*objects) -> integer
2233 *
2234 * Writes each of the given +objects+ to +self+,
2235 * which must be opened for writing
2236 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2237 * returns the total number bytes written;
2238 * each of +objects+ that is not a string is converted via method +to_s+:
2239 *
2240 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2241 * $stdout.write('foo', :bar, 2, "\n") # => 8
2242 *
2243 * Output:
2244 *
2245 * Hello, World!
2246 * foobar2
2247 *
2248 * Related: IO#read.
2249 */
2250
2251static VALUE
2252io_write_m(int argc, VALUE *argv, VALUE io)
2253{
2254 if (argc != 1) {
2255 return io_writev(argc, argv, io);
2256 }
2257 else {
2258 VALUE str = argv[0];
2259 return io_write(io, str, 0);
2260 }
2261}
2262
2263VALUE
2265{
2266 return rb_funcallv(io, id_write, 1, &str);
2267}
2268
2269static VALUE
2270rb_io_writev(VALUE io, int argc, const VALUE *argv)
2271{
2272 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2273 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2274 VALUE klass = CLASS_OF(io);
2275 char sep = FL_TEST(klass, FL_SINGLETON) ? (klass = io, '.') : '#';
2277 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2278 " which accepts just one argument",
2279 klass, sep
2280 );
2281 }
2282
2283 do rb_io_write(io, *argv++); while (--argc);
2284
2285 return Qnil;
2286 }
2287
2288 return rb_funcallv(io, id_write, argc, argv);
2289}
2290
2291/*
2292 * call-seq:
2293 * self << object -> self
2294 *
2295 * Writes the given +object+ to +self+,
2296 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2297 * returns +self+;
2298 * if +object+ is not a string, it is converted via method +to_s+:
2299 *
2300 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2301 * $stdout << 'foo' << :bar << 2 << "\n"
2302 *
2303 * Output:
2304 *
2305 * Hello, World!
2306 * foobar2
2307 *
2308 */
2309
2310
2311VALUE
2313{
2314 rb_io_write(io, str);
2315 return io;
2316}
2317
2318#ifdef HAVE_FSYNC
2319static VALUE
2320nogvl_fsync(void *ptr)
2321{
2322 rb_io_t *fptr = ptr;
2323
2324#ifdef _WIN32
2325 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2326 return 0;
2327#endif
2328 return (VALUE)fsync(fptr->fd);
2329}
2330#endif
2331
2332VALUE
2333rb_io_flush_raw(VALUE io, int sync)
2334{
2335 rb_io_t *fptr;
2336
2337 if (!RB_TYPE_P(io, T_FILE)) {
2338 return rb_funcall(io, id_flush, 0);
2339 }
2340
2341 io = GetWriteIO(io);
2342 GetOpenFile(io, fptr);
2343
2344 if (fptr->mode & FMODE_WRITABLE) {
2345 if (io_fflush(fptr) < 0)
2346 rb_sys_fail_on_write(fptr);
2347 }
2348 if (fptr->mode & FMODE_READABLE) {
2349 io_unread(fptr);
2350 }
2351
2352 return io;
2353}
2354
2355/*
2356 * call-seq:
2357 * flush -> self
2358 *
2359 * Flushes data buffered in +self+ to the operating system
2360 * (but does not necessarily flush data buffered in the operating system):
2361 *
2362 * $stdout.print 'no newline' # Not necessarily flushed.
2363 * $stdout.flush # Flushed.
2364 *
2365 */
2366
2367VALUE
2369{
2370 return rb_io_flush_raw(io, 1);
2371}
2372
2373/*
2374 * call-seq:
2375 * tell -> integer
2376 *
2377 * Returns the current position (in bytes) in +self+
2378 * (see {Position}[rdoc-ref:IO@Position]):
2379 *
2380 * f = File.open('t.txt')
2381 * f.tell # => 0
2382 * f.gets # => "First line\n"
2383 * f.tell # => 12
2384 * f.close
2385 *
2386 * Related: IO#pos=, IO#seek.
2387 *
2388 * IO#pos is an alias for IO#tell.
2389 *
2390 */
2391
2392static VALUE
2393rb_io_tell(VALUE io)
2394{
2395 rb_io_t *fptr;
2396 rb_off_t pos;
2397
2398 GetOpenFile(io, fptr);
2399 pos = io_tell(fptr);
2400 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2401 pos -= fptr->rbuf.len;
2402 return OFFT2NUM(pos);
2403}
2404
2405static VALUE
2406rb_io_seek(VALUE io, VALUE offset, int whence)
2407{
2408 rb_io_t *fptr;
2409 rb_off_t pos;
2410
2411 pos = NUM2OFFT(offset);
2412 GetOpenFile(io, fptr);
2413 pos = io_seek(fptr, pos, whence);
2414 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2415
2416 return INT2FIX(0);
2417}
2418
2419static int
2420interpret_seek_whence(VALUE vwhence)
2421{
2422 if (vwhence == sym_SET)
2423 return SEEK_SET;
2424 if (vwhence == sym_CUR)
2425 return SEEK_CUR;
2426 if (vwhence == sym_END)
2427 return SEEK_END;
2428#ifdef SEEK_DATA
2429 if (vwhence == sym_DATA)
2430 return SEEK_DATA;
2431#endif
2432#ifdef SEEK_HOLE
2433 if (vwhence == sym_HOLE)
2434 return SEEK_HOLE;
2435#endif
2436 return NUM2INT(vwhence);
2437}
2438
2439/*
2440 * call-seq:
2441 * seek(offset, whence = IO::SEEK_SET) -> 0
2442 *
2443 * Seeks to the position given by integer +offset+
2444 * (see {Position}[rdoc-ref:IO@Position])
2445 * and constant +whence+, which is one of:
2446 *
2447 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2448 * Repositions the stream to its current position plus the given +offset+:
2449 *
2450 * f = File.open('t.txt')
2451 * f.tell # => 0
2452 * f.seek(20, :CUR) # => 0
2453 * f.tell # => 20
2454 * f.seek(-10, :CUR) # => 0
2455 * f.tell # => 10
2456 * f.close
2457 *
2458 * - +:END+ or <tt>IO::SEEK_END</tt>:
2459 * Repositions the stream to its end plus the given +offset+:
2460 *
2461 * f = File.open('t.txt')
2462 * f.tell # => 0
2463 * f.seek(0, :END) # => 0 # Repositions to stream end.
2464 * f.tell # => 52
2465 * f.seek(-20, :END) # => 0
2466 * f.tell # => 32
2467 * f.seek(-40, :END) # => 0
2468 * f.tell # => 12
2469 * f.close
2470 *
2471 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2472 * Repositions the stream to the given +offset+:
2473 *
2474 * f = File.open('t.txt')
2475 * f.tell # => 0
2476 * f.seek(20, :SET) # => 0
2477 * f.tell # => 20
2478 * f.seek(40, :SET) # => 0
2479 * f.tell # => 40
2480 * f.close
2481 *
2482 * Related: IO#pos=, IO#tell.
2483 *
2484 */
2485
2486static VALUE
2487rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2488{
2489 VALUE offset, ptrname;
2490 int whence = SEEK_SET;
2491
2492 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2493 whence = interpret_seek_whence(ptrname);
2494 }
2495
2496 return rb_io_seek(io, offset, whence);
2497}
2498
2499/*
2500 * call-seq:
2501 * pos = new_position -> new_position
2502 *
2503 * Seeks to the given +new_position+ (in bytes);
2504 * see {Position}[rdoc-ref:IO@Position]:
2505 *
2506 * f = File.open('t.txt')
2507 * f.tell # => 0
2508 * f.pos = 20 # => 20
2509 * f.tell # => 20
2510 * f.close
2511 *
2512 * Related: IO#seek, IO#tell.
2513 *
2514 */
2515
2516static VALUE
2517rb_io_set_pos(VALUE io, VALUE offset)
2518{
2519 rb_io_t *fptr;
2520 rb_off_t pos;
2521
2522 pos = NUM2OFFT(offset);
2523 GetOpenFile(io, fptr);
2524 pos = io_seek(fptr, pos, SEEK_SET);
2525 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2526
2527 return OFFT2NUM(pos);
2528}
2529
2530static void clear_readconv(rb_io_t *fptr);
2531
2532/*
2533 * call-seq:
2534 * rewind -> 0
2535 *
2536 * Repositions the stream to its beginning,
2537 * setting both the position and the line number to zero;
2538 * see {Position}[rdoc-ref:IO@Position]
2539 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2540 *
2541 * f = File.open('t.txt')
2542 * f.tell # => 0
2543 * f.lineno # => 0
2544 * f.gets # => "First line\n"
2545 * f.tell # => 12
2546 * f.lineno # => 1
2547 * f.rewind # => 0
2548 * f.tell # => 0
2549 * f.lineno # => 0
2550 * f.close
2551 *
2552 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2553 *
2554 */
2555
2556static VALUE
2557rb_io_rewind(VALUE io)
2558{
2559 rb_io_t *fptr;
2560
2561 GetOpenFile(io, fptr);
2562 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2563 if (io == ARGF.current_file) {
2564 ARGF.lineno -= fptr->lineno;
2565 }
2566 fptr->lineno = 0;
2567 if (fptr->readconv) {
2568 clear_readconv(fptr);
2569 }
2570
2571 return INT2FIX(0);
2572}
2573
2574static int
2575fptr_wait_readable(rb_io_t *fptr)
2576{
2577 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2578
2579 if (result)
2580 rb_io_check_closed(fptr);
2581
2582 return result;
2583}
2584
2585static int
2586io_fillbuf(rb_io_t *fptr)
2587{
2588 ssize_t r;
2589
2590 if (fptr->rbuf.ptr == NULL) {
2591 fptr->rbuf.off = 0;
2592 fptr->rbuf.len = 0;
2593 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2594 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2595#ifdef _WIN32
2596 fptr->rbuf.capa--;
2597#endif
2598 }
2599 if (fptr->rbuf.len == 0) {
2600 retry:
2601 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2602
2603 if (r < 0) {
2604 if (fptr_wait_readable(fptr))
2605 goto retry;
2606
2607 int e = errno;
2608 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2609 if (!NIL_P(fptr->pathv)) {
2610 rb_str_append(path, fptr->pathv);
2611 }
2612
2613 rb_syserr_fail_path(e, path);
2614 }
2615 if (r > 0) rb_io_check_closed(fptr);
2616 fptr->rbuf.off = 0;
2617 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2618 if (r == 0)
2619 return -1; /* EOF */
2620 }
2621 return 0;
2622}
2623
2624/*
2625 * call-seq:
2626 * eof -> true or false
2627 *
2628 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2629 * see {Position}[rdoc-ref:IO@Position]:
2630 *
2631 * f = File.open('t.txt')
2632 * f.eof # => false
2633 * f.seek(0, :END) # => 0
2634 * f.eof # => true
2635 * f.close
2636 *
2637 * Raises an exception unless the stream is opened for reading;
2638 * see {Mode}[rdoc-ref:File@Access+Modes].
2639 *
2640 * If +self+ is a stream such as pipe or socket, this method
2641 * blocks until the other end sends some data or closes it:
2642 *
2643 * r, w = IO.pipe
2644 * Thread.new { sleep 1; w.close }
2645 * r.eof? # => true # After 1-second wait.
2646 *
2647 * r, w = IO.pipe
2648 * Thread.new { sleep 1; w.puts "a" }
2649 * r.eof? # => false # After 1-second wait.
2650 *
2651 * r, w = IO.pipe
2652 * r.eof? # blocks forever
2653 *
2654 * Note that this method reads data to the input byte buffer. So
2655 * IO#sysread may not behave as you intend with IO#eof?, unless you
2656 * call IO#rewind first (which is not available for some streams).
2657 *
2658 * IO#eof? is an alias for IO#eof.
2659 *
2660 */
2661
2662VALUE
2664{
2665 rb_io_t *fptr;
2666
2667 GetOpenFile(io, fptr);
2669
2670 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2671 if (READ_DATA_PENDING(fptr)) return Qfalse;
2672 READ_CHECK(fptr);
2673#if RUBY_CRLF_ENVIRONMENT
2674 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2675 return RBOOL(eof(fptr->fd));;
2676 }
2677#endif
2678 return RBOOL(io_fillbuf(fptr) < 0);
2679}
2680
2681/*
2682 * call-seq:
2683 * sync -> true or false
2684 *
2685 * Returns the current sync mode of the stream.
2686 * When sync mode is true, all output is immediately flushed to the underlying
2687 * operating system and is not buffered by Ruby internally. See also #fsync.
2688 *
2689 * f = File.open('t.tmp', 'w')
2690 * f.sync # => false
2691 * f.sync = true
2692 * f.sync # => true
2693 * f.close
2694 *
2695 */
2696
2697static VALUE
2698rb_io_sync(VALUE io)
2699{
2700 rb_io_t *fptr;
2701
2702 io = GetWriteIO(io);
2703 GetOpenFile(io, fptr);
2704 return RBOOL(fptr->mode & FMODE_SYNC);
2705}
2706
2707#ifdef HAVE_FSYNC
2708
2709/*
2710 * call-seq:
2711 * sync = boolean -> boolean
2712 *
2713 * Sets the _sync_ _mode_ for the stream to the given value;
2714 * returns the given value.
2715 *
2716 * Values for the sync mode:
2717 *
2718 * - +true+: All output is immediately flushed to the
2719 * underlying operating system and is not buffered internally.
2720 * - +false+: Output may be buffered internally.
2721 *
2722 * Example;
2723 *
2724 * f = File.open('t.tmp', 'w')
2725 * f.sync # => false
2726 * f.sync = true
2727 * f.sync # => true
2728 * f.close
2729 *
2730 * Related: IO#fsync.
2731 *
2732 */
2733
2734static VALUE
2735rb_io_set_sync(VALUE io, VALUE sync)
2736{
2737 rb_io_t *fptr;
2738
2739 io = GetWriteIO(io);
2740 GetOpenFile(io, fptr);
2741 if (RTEST(sync)) {
2742 fptr->mode |= FMODE_SYNC;
2743 }
2744 else {
2745 fptr->mode &= ~FMODE_SYNC;
2746 }
2747 return sync;
2748}
2749
2750/*
2751 * call-seq:
2752 * fsync -> 0
2753 *
2754 * Immediately writes to disk all data buffered in the stream,
2755 * via the operating system's <tt>fsync(2)</tt>.
2756
2757 * Note this difference:
2758 *
2759 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2760 * but does not guarantee that the operating system actually writes the data to disk.
2761 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2762 * and that data is written to disk.
2763 *
2764 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2765 *
2766 */
2767
2768static VALUE
2769rb_io_fsync(VALUE io)
2770{
2771 rb_io_t *fptr;
2772
2773 io = GetWriteIO(io);
2774 GetOpenFile(io, fptr);
2775
2776 if (io_fflush(fptr) < 0)
2777 rb_sys_fail_on_write(fptr);
2778 if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
2779 rb_sys_fail_path(fptr->pathv);
2780 return INT2FIX(0);
2781}
2782#else
2783# define rb_io_fsync rb_f_notimplement
2784# define rb_io_sync rb_f_notimplement
2785static VALUE
2786rb_io_set_sync(VALUE io, VALUE sync)
2787{
2790}
2791#endif
2792
2793#ifdef HAVE_FDATASYNC
2794static VALUE
2795nogvl_fdatasync(void *ptr)
2796{
2797 rb_io_t *fptr = ptr;
2798
2799#ifdef _WIN32
2800 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2801 return 0;
2802#endif
2803 return (VALUE)fdatasync(fptr->fd);
2804}
2805
2806/*
2807 * call-seq:
2808 * fdatasync -> 0
2809 *
2810 * Immediately writes to disk all data buffered in the stream,
2811 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2812 * otherwise via <tt>fsync(2)</tt>, if supported;
2813 * otherwise raises an exception.
2814 *
2815 */
2816
2817static VALUE
2818rb_io_fdatasync(VALUE io)
2819{
2820 rb_io_t *fptr;
2821
2822 io = GetWriteIO(io);
2823 GetOpenFile(io, fptr);
2824
2825 if (io_fflush(fptr) < 0)
2826 rb_sys_fail_on_write(fptr);
2827
2828 if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
2829 return INT2FIX(0);
2830
2831 /* fall back */
2832 return rb_io_fsync(io);
2833}
2834#else
2835#define rb_io_fdatasync rb_io_fsync
2836#endif
2837
2838/*
2839 * call-seq:
2840 * fileno -> integer
2841 *
2842 * Returns the integer file descriptor for the stream:
2843 *
2844 * $stdin.fileno # => 0
2845 * $stdout.fileno # => 1
2846 * $stderr.fileno # => 2
2847 * File.open('t.txt').fileno # => 10
2848 * f.close
2849 *
2850 * IO#to_i is an alias for IO#fileno.
2851 *
2852 */
2853
2854static VALUE
2855rb_io_fileno(VALUE io)
2856{
2857 rb_io_t *fptr = RFILE(io)->fptr;
2858 int fd;
2859
2860 rb_io_check_closed(fptr);
2861 fd = fptr->fd;
2862 return INT2FIX(fd);
2863}
2864
2865int
2867{
2868 if (RB_TYPE_P(io, T_FILE)) {
2869 rb_io_t *fptr = RFILE(io)->fptr;
2870 rb_io_check_closed(fptr);
2871 return fptr->fd;
2872 }
2873 else {
2874 return RB_NUM2INT(rb_funcall(io, id_fileno, 0));
2875 }
2876}
2877
2878/*
2879 * call-seq:
2880 * pid -> integer or nil
2881 *
2882 * Returns the process ID of a child process associated with the stream,
2883 * which will have been set by IO#popen, or +nil+ if the stream was not
2884 * created by IO#popen:
2885 *
2886 * pipe = IO.popen("-")
2887 * if pipe
2888 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2889 * else
2890 * $stderr.puts "In child, pid is #{$$}"
2891 * end
2892 *
2893 * Output:
2894 *
2895 * In child, pid is 26209
2896 * In parent, child pid is 26209
2897 *
2898 */
2899
2900static VALUE
2901rb_io_pid(VALUE io)
2902{
2903 rb_io_t *fptr;
2904
2905 GetOpenFile(io, fptr);
2906 if (!fptr->pid)
2907 return Qnil;
2908 return PIDT2NUM(fptr->pid);
2909}
2910
2911/*
2912 * call-seq:
2913 * path -> string or nil
2914 *
2915 * Returns the path associated with the IO, or +nil+ if there is no path
2916 * associated with the IO. It is not guaranteed that the path exists on
2917 * the filesystem.
2918 *
2919 * $stdin.path # => "<STDIN>"
2920 *
2921 * File.open("testfile") {|f| f.path} # => "testfile"
2922 */
2923
2924static VALUE
2925rb_io_path(VALUE io)
2926{
2927 rb_io_t *fptr = RFILE(io)->fptr;
2928
2929 if (!fptr)
2930 return Qnil;
2931
2932 return rb_obj_dup(fptr->pathv);
2933}
2934
2935/*
2936 * call-seq:
2937 * inspect -> string
2938 *
2939 * Returns a string representation of +self+:
2940 *
2941 * f = File.open('t.txt')
2942 * f.inspect # => "#<File:t.txt>"
2943 * f.close
2944 *
2945 */
2946
2947static VALUE
2948rb_io_inspect(VALUE obj)
2949{
2950 rb_io_t *fptr;
2951 VALUE result;
2952 static const char closed[] = " (closed)";
2953
2954 fptr = RFILE(obj)->fptr;
2955 if (!fptr) return rb_any_to_s(obj);
2956 result = rb_str_new_cstr("#<");
2957 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2958 rb_str_cat2(result, ":");
2959 if (NIL_P(fptr->pathv)) {
2960 if (fptr->fd < 0) {
2961 rb_str_cat(result, closed+1, strlen(closed)-1);
2962 }
2963 else {
2964 rb_str_catf(result, "fd %d", fptr->fd);
2965 }
2966 }
2967 else {
2968 rb_str_append(result, fptr->pathv);
2969 if (fptr->fd < 0) {
2970 rb_str_cat(result, closed, strlen(closed));
2971 }
2972 }
2973 return rb_str_cat2(result, ">");
2974}
2975
2976/*
2977 * call-seq:
2978 * to_io -> self
2979 *
2980 * Returns +self+.
2981 *
2982 */
2983
2984static VALUE
2985rb_io_to_io(VALUE io)
2986{
2987 return io;
2988}
2989
2990/* reading functions */
2991static long
2992read_buffered_data(char *ptr, long len, rb_io_t *fptr)
2993{
2994 int n;
2995
2996 n = READ_DATA_PENDING_COUNT(fptr);
2997 if (n <= 0) return 0;
2998 if (n > len) n = (int)len;
2999 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3000 fptr->rbuf.off += n;
3001 fptr->rbuf.len -= n;
3002 return n;
3003}
3004
3005static long
3006io_bufread(char *ptr, long len, rb_io_t *fptr)
3007{
3008 long offset = 0;
3009 long n = len;
3010 long c;
3011
3012 if (READ_DATA_PENDING(fptr) == 0) {
3013 while (n > 0) {
3014 again:
3015 rb_io_check_closed(fptr);
3016 c = rb_io_read_memory(fptr, ptr+offset, n);
3017 if (c == 0) break;
3018 if (c < 0) {
3019 if (fptr_wait_readable(fptr))
3020 goto again;
3021 return -1;
3022 }
3023 offset += c;
3024 if ((n -= c) <= 0) break;
3025 }
3026 return len - n;
3027 }
3028
3029 while (n > 0) {
3030 c = read_buffered_data(ptr+offset, n, fptr);
3031 if (c > 0) {
3032 offset += c;
3033 if ((n -= c) <= 0) break;
3034 }
3035 rb_io_check_closed(fptr);
3036 if (io_fillbuf(fptr) < 0) {
3037 break;
3038 }
3039 }
3040 return len - n;
3041}
3042
3043static int io_setstrbuf(VALUE *str, long len);
3044
3046 char *str_ptr;
3047 long len;
3048 rb_io_t *fptr;
3049};
3050
3051static VALUE
3052bufread_call(VALUE arg)
3053{
3054 struct bufread_arg *p = (struct bufread_arg *)arg;
3055 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3056 return Qundef;
3057}
3058
3059static long
3060io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3061{
3062 long len;
3063 struct bufread_arg arg;
3064
3065 io_setstrbuf(&str, offset + size);
3066 arg.str_ptr = RSTRING_PTR(str) + offset;
3067 arg.len = size;
3068 arg.fptr = fptr;
3069 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3070 len = arg.len;
3071 if (len < 0) rb_sys_fail_path(fptr->pathv);
3072 return len;
3073}
3074
3075static long
3076remain_size(rb_io_t *fptr)
3077{
3078 struct stat st;
3079 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3080 rb_off_t pos;
3081
3082 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3083#if defined(__HAIKU__)
3084 && (st.st_dev > 3)
3085#endif
3086 )
3087 {
3088 if (io_fflush(fptr) < 0)
3089 rb_sys_fail_on_write(fptr);
3090 pos = lseek(fptr->fd, 0, SEEK_CUR);
3091 if (st.st_size >= pos && pos >= 0) {
3092 siz += st.st_size - pos;
3093 if (siz > LONG_MAX) {
3094 rb_raise(rb_eIOError, "file too big for single read");
3095 }
3096 }
3097 }
3098 else {
3099 siz += BUFSIZ;
3100 }
3101 return (long)siz;
3102}
3103
3104static VALUE
3105io_enc_str(VALUE str, rb_io_t *fptr)
3106{
3107 rb_enc_associate(str, io_read_encoding(fptr));
3108 return str;
3109}
3110
3111static rb_encoding *io_read_encoding(rb_io_t *fptr);
3112
3113static void
3114make_readconv(rb_io_t *fptr, int size)
3115{
3116 if (!fptr->readconv) {
3117 int ecflags;
3118 VALUE ecopts;
3119 const char *sname, *dname;
3120 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3121 ecopts = fptr->encs.ecopts;
3122 if (fptr->encs.enc2) {
3123 sname = rb_enc_name(fptr->encs.enc2);
3124 dname = rb_enc_name(io_read_encoding(fptr));
3125 }
3126 else {
3127 sname = dname = "";
3128 }
3129 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3130 if (!fptr->readconv)
3131 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3132 fptr->cbuf.off = 0;
3133 fptr->cbuf.len = 0;
3134 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3135 fptr->cbuf.capa = size;
3136 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3137 }
3138}
3139
3140#define MORE_CHAR_SUSPENDED Qtrue
3141#define MORE_CHAR_FINISHED Qnil
3142static VALUE
3143fill_cbuf(rb_io_t *fptr, int ec_flags)
3144{
3145 const unsigned char *ss, *sp, *se;
3146 unsigned char *ds, *dp, *de;
3148 int putbackable;
3149 int cbuf_len0;
3150 VALUE exc;
3151
3152 ec_flags |= ECONV_PARTIAL_INPUT;
3153
3154 if (fptr->cbuf.len == fptr->cbuf.capa)
3155 return MORE_CHAR_SUSPENDED; /* cbuf full */
3156 if (fptr->cbuf.len == 0)
3157 fptr->cbuf.off = 0;
3158 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3159 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3160 fptr->cbuf.off = 0;
3161 }
3162
3163 cbuf_len0 = fptr->cbuf.len;
3164
3165 while (1) {
3166 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3167 se = sp + fptr->rbuf.len;
3168 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3169 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3170 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3171 fptr->rbuf.off += (int)(sp - ss);
3172 fptr->rbuf.len -= (int)(sp - ss);
3173 fptr->cbuf.len += (int)(dp - ds);
3174
3175 putbackable = rb_econv_putbackable(fptr->readconv);
3176 if (putbackable) {
3177 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3178 fptr->rbuf.off -= putbackable;
3179 fptr->rbuf.len += putbackable;
3180 }
3181
3182 exc = rb_econv_make_exception(fptr->readconv);
3183 if (!NIL_P(exc))
3184 return exc;
3185
3186 if (cbuf_len0 != fptr->cbuf.len)
3187 return MORE_CHAR_SUSPENDED;
3188
3189 if (res == econv_finished) {
3190 return MORE_CHAR_FINISHED;
3191 }
3192
3193 if (res == econv_source_buffer_empty) {
3194 if (fptr->rbuf.len == 0) {
3195 READ_CHECK(fptr);
3196 if (io_fillbuf(fptr) < 0) {
3197 if (!fptr->readconv) {
3198 return MORE_CHAR_FINISHED;
3199 }
3200 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3201 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3202 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3203 fptr->cbuf.len += (int)(dp - ds);
3205 break;
3206 }
3207 }
3208 }
3209 }
3210 if (cbuf_len0 != fptr->cbuf.len)
3211 return MORE_CHAR_SUSPENDED;
3212
3213 return MORE_CHAR_FINISHED;
3214}
3215
3216static VALUE
3217more_char(rb_io_t *fptr)
3218{
3219 VALUE v;
3220 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3221 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3222 rb_exc_raise(v);
3223 return v;
3224}
3225
3226static VALUE
3227io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3228{
3229 VALUE str = Qnil;
3230 if (strp) {
3231 str = *strp;
3232 if (NIL_P(str)) {
3233 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3234 }
3235 else {
3236 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3237 }
3238 rb_enc_associate(str, fptr->encs.enc);
3239 }
3240 fptr->cbuf.off += len;
3241 fptr->cbuf.len -= len;
3242 /* xxx: set coderange */
3243 if (fptr->cbuf.len == 0)
3244 fptr->cbuf.off = 0;
3245 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3246 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3247 fptr->cbuf.off = 0;
3248 }
3249 return str;
3250}
3251
3252static int
3253io_setstrbuf(VALUE *str, long len)
3254{
3255#ifdef _WIN32
3256 if (len > 0)
3257 len = (len + 1) & ~1L; /* round up for wide char */
3258#endif
3259 if (NIL_P(*str)) {
3260 *str = rb_str_new(0, len);
3261 return TRUE;
3262 }
3263 else {
3264 VALUE s = StringValue(*str);
3265 long clen = RSTRING_LEN(s);
3266 if (clen >= len) {
3267 rb_str_modify(s);
3268 return FALSE;
3269 }
3270 len -= clen;
3271 }
3272 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3273 rb_str_modify_expand(*str, len);
3274 }
3275 return FALSE;
3276}
3277
3278#define MAX_REALLOC_GAP 4096
3279static void
3280io_shrink_read_string(VALUE str, long n)
3281{
3282 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3283 rb_str_resize(str, n);
3284 }
3285}
3286
3287static void
3288io_set_read_length(VALUE str, long n, int shrinkable)
3289{
3290 if (RSTRING_LEN(str) != n) {
3291 rb_str_modify(str);
3292 rb_str_set_len(str, n);
3293 if (shrinkable) io_shrink_read_string(str, n);
3294 }
3295}
3296
3297static VALUE
3298read_all(rb_io_t *fptr, long siz, VALUE str)
3299{
3300 long bytes;
3301 long n;
3302 long pos;
3303 rb_encoding *enc;
3304 int cr;
3305 int shrinkable;
3306
3307 if (NEED_READCONV(fptr)) {
3308 int first = !NIL_P(str);
3309 SET_BINARY_MODE(fptr);
3310 shrinkable = io_setstrbuf(&str,0);
3311 make_readconv(fptr, 0);
3312 while (1) {
3313 VALUE v;
3314 if (fptr->cbuf.len) {
3315 if (first) rb_str_set_len(str, first = 0);
3316 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3317 }
3318 v = fill_cbuf(fptr, 0);
3319 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3320 if (fptr->cbuf.len) {
3321 if (first) rb_str_set_len(str, first = 0);
3322 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3323 }
3324 rb_exc_raise(v);
3325 }
3326 if (v == MORE_CHAR_FINISHED) {
3327 clear_readconv(fptr);
3328 if (first) rb_str_set_len(str, first = 0);
3329 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3330 return io_enc_str(str, fptr);
3331 }
3332 }
3333 }
3334
3335 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3336 bytes = 0;
3337 pos = 0;
3338
3339 enc = io_read_encoding(fptr);
3340 cr = 0;
3341
3342 if (siz == 0) siz = BUFSIZ;
3343 shrinkable = io_setstrbuf(&str, siz);
3344 for (;;) {
3345 READ_CHECK(fptr);
3346 n = io_fread(str, bytes, siz - bytes, fptr);
3347 if (n == 0 && bytes == 0) {
3348 rb_str_set_len(str, 0);
3349 break;
3350 }
3351 bytes += n;
3352 rb_str_set_len(str, bytes);
3353 if (cr != ENC_CODERANGE_BROKEN)
3354 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3355 if (bytes < siz) break;
3356 siz += BUFSIZ;
3357
3358 size_t capa = rb_str_capacity(str);
3359 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3360 if (capa < BUFSIZ) {
3361 capa = BUFSIZ;
3362 }
3363 else if (capa > IO_MAX_BUFFER_GROWTH) {
3364 capa = IO_MAX_BUFFER_GROWTH;
3365 }
3366 rb_str_modify_expand(str, capa);
3367 }
3368 }
3369 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3370 str = io_enc_str(str, fptr);
3371 ENC_CODERANGE_SET(str, cr);
3372 return str;
3373}
3374
3375void
3377{
3378 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3379 rb_sys_fail_path(fptr->pathv);
3380 }
3381}
3382
3383static VALUE
3384io_read_memory_call(VALUE arg)
3385{
3386 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3387
3388 VALUE scheduler = rb_fiber_scheduler_current();
3389 if (scheduler != Qnil) {
3390 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3391
3392 if (!UNDEF_P(result)) {
3393 // This is actually returned as a pseudo-VALUE and later cast to a long:
3395 }
3396 }
3397
3398 return rb_thread_io_blocking_region(internal_read_func, iis, iis->fptr->fd);
3399}
3400
3401static long
3402io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3403{
3404 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3405}
3406
3407#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3408
3409static VALUE
3410io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3411{
3412 rb_io_t *fptr;
3413 VALUE length, str;
3414 long n, len;
3415 struct io_internal_read_struct iis;
3416 int shrinkable;
3417
3418 rb_scan_args(argc, argv, "11", &length, &str);
3419
3420 if ((len = NUM2LONG(length)) < 0) {
3421 rb_raise(rb_eArgError, "negative length %ld given", len);
3422 }
3423
3424 shrinkable = io_setstrbuf(&str, len);
3425
3426 GetOpenFile(io, fptr);
3428
3429 if (len == 0) {
3430 io_set_read_length(str, 0, shrinkable);
3431 return str;
3432 }
3433
3434 if (!nonblock)
3435 READ_CHECK(fptr);
3436 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3437 if (n <= 0) {
3438 again:
3439 if (nonblock) {
3440 rb_io_set_nonblock(fptr);
3441 }
3442 io_setstrbuf(&str, len);
3443 iis.th = rb_thread_current();
3444 iis.fptr = fptr;
3445 iis.nonblock = nonblock;
3446 iis.fd = fptr->fd;
3447 iis.buf = RSTRING_PTR(str);
3448 iis.capa = len;
3449 iis.timeout = NULL;
3450 n = io_read_memory_locktmp(str, &iis);
3451 if (n < 0) {
3452 int e = errno;
3453 if (!nonblock && fptr_wait_readable(fptr))
3454 goto again;
3455 if (nonblock && (io_again_p(e))) {
3456 if (no_exception)
3457 return sym_wait_readable;
3458 else
3459 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3460 e, "read would block");
3461 }
3462 rb_syserr_fail_path(e, fptr->pathv);
3463 }
3464 }
3465 io_set_read_length(str, n, shrinkable);
3466
3467 if (n == 0)
3468 return Qnil;
3469 else
3470 return str;
3471}
3472
3473/*
3474 * call-seq:
3475 * readpartial(maxlen) -> string
3476 * readpartial(maxlen, out_string) -> out_string
3477 *
3478 * Reads up to +maxlen+ bytes from the stream;
3479 * returns a string (either a new string or the given +out_string+).
3480 * Its encoding is:
3481 *
3482 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3483 * - ASCII-8BIT, otherwise.
3484 *
3485 * - Contains +maxlen+ bytes from the stream, if available.
3486 * - Otherwise contains all available bytes, if any available.
3487 * - Otherwise is an empty string.
3488 *
3489 * With the single non-negative integer argument +maxlen+ given,
3490 * returns a new string:
3491 *
3492 * f = File.new('t.txt')
3493 * f.readpartial(20) # => "First line\nSecond l"
3494 * f.readpartial(20) # => "ine\n\nFourth line\n"
3495 * f.readpartial(20) # => "Fifth line\n"
3496 * f.readpartial(20) # Raises EOFError.
3497 * f.close
3498 *
3499 * With both argument +maxlen+ and string argument +out_string+ given,
3500 * returns modified +out_string+:
3501 *
3502 * f = File.new('t.txt')
3503 * s = 'foo'
3504 * f.readpartial(20, s) # => "First line\nSecond l"
3505 * s = 'bar'
3506 * f.readpartial(0, s) # => ""
3507 * f.close
3508 *
3509 * This method is useful for a stream such as a pipe, a socket, or a tty.
3510 * It blocks only when no data is immediately available.
3511 * This means that it blocks only when _all_ of the following are true:
3512 *
3513 * - The byte buffer in the stream is empty.
3514 * - The content of the stream is empty.
3515 * - The stream is not at EOF.
3516 *
3517 * When blocked, the method waits for either more data or EOF on the stream:
3518 *
3519 * - If more data is read, the method returns the data.
3520 * - If EOF is reached, the method raises EOFError.
3521 *
3522 * When not blocked, the method responds immediately:
3523 *
3524 * - Returns data from the buffer if there is any.
3525 * - Otherwise returns data from the stream if there is any.
3526 * - Otherwise raises EOFError if the stream has reached EOF.
3527 *
3528 * Note that this method is similar to sysread. The differences are:
3529 *
3530 * - If the byte buffer is not empty, read from the byte buffer
3531 * instead of "sysread for buffered IO (IOError)".
3532 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3533 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3534 * readpartial retries the system call.
3535 *
3536 * The latter means that readpartial is non-blocking-flag insensitive.
3537 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3538 * if the fd is blocking mode.
3539 *
3540 * Examples:
3541 *
3542 * # # Returned Buffer Content Pipe Content
3543 * r, w = IO.pipe #
3544 * w << 'abc' # "" "abc".
3545 * r.readpartial(4096) # => "abc" "" ""
3546 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3547 *
3548 * # # Returned Buffer Content Pipe Content
3549 * r, w = IO.pipe #
3550 * w << 'abc' # "" "abc"
3551 * w.close # "" "abc" EOF
3552 * r.readpartial(4096) # => "abc" "" EOF
3553 * r.readpartial(4096) # raises EOFError
3554 *
3555 * # # Returned Buffer Content Pipe Content
3556 * r, w = IO.pipe #
3557 * w << "abc\ndef\n" # "" "abc\ndef\n"
3558 * r.gets # => "abc\n" "def\n" ""
3559 * w << "ghi\n" # "def\n" "ghi\n"
3560 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3561 * r.readpartial(4096) # => "ghi\n" "" ""
3562 *
3563 */
3564
3565static VALUE
3566io_readpartial(int argc, VALUE *argv, VALUE io)
3567{
3568 VALUE ret;
3569
3570 ret = io_getpartial(argc, argv, io, Qnil, 0);
3571 if (NIL_P(ret))
3572 rb_eof_error();
3573 return ret;
3574}
3575
3576static VALUE
3577io_nonblock_eof(int no_exception)
3578{
3579 if (!no_exception) {
3580 rb_eof_error();
3581 }
3582 return Qnil;
3583}
3584
3585/* :nodoc: */
3586static VALUE
3587io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3588{
3589 rb_io_t *fptr;
3590 long n, len;
3591 struct io_internal_read_struct iis;
3592 int shrinkable;
3593
3594 if ((len = NUM2LONG(length)) < 0) {
3595 rb_raise(rb_eArgError, "negative length %ld given", len);
3596 }
3597
3598 shrinkable = io_setstrbuf(&str, len);
3599 rb_bool_expected(ex, "exception", TRUE);
3600
3601 GetOpenFile(io, fptr);
3603
3604 if (len == 0) {
3605 io_set_read_length(str, 0, shrinkable);
3606 return str;
3607 }
3608
3609 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3610 if (n <= 0) {
3611 rb_fd_set_nonblock(fptr->fd);
3612 shrinkable |= io_setstrbuf(&str, len);
3613 iis.fptr = fptr;
3614 iis.nonblock = 1;
3615 iis.fd = fptr->fd;
3616 iis.buf = RSTRING_PTR(str);
3617 iis.capa = len;
3618 iis.timeout = NULL;
3619 n = io_read_memory_locktmp(str, &iis);
3620 if (n < 0) {
3621 int e = errno;
3622 if (io_again_p(e)) {
3623 if (!ex) return sym_wait_readable;
3624 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3625 e, "read would block");
3626 }
3627 rb_syserr_fail_path(e, fptr->pathv);
3628 }
3629 }
3630 io_set_read_length(str, n, shrinkable);
3631
3632 if (n == 0) {
3633 if (!ex) return Qnil;
3634 rb_eof_error();
3635 }
3636
3637 return str;
3638}
3639
3640/* :nodoc: */
3641static VALUE
3642io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3643{
3644 rb_io_t *fptr;
3645 long n;
3646
3647 if (!RB_TYPE_P(str, T_STRING))
3648 str = rb_obj_as_string(str);
3649 rb_bool_expected(ex, "exception", TRUE);
3650
3651 io = GetWriteIO(io);
3652 GetOpenFile(io, fptr);
3654
3655 if (io_fflush(fptr) < 0)
3656 rb_sys_fail_on_write(fptr);
3657
3658 rb_fd_set_nonblock(fptr->fd);
3659 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3660 RB_GC_GUARD(str);
3661
3662 if (n < 0) {
3663 int e = errno;
3664 if (io_again_p(e)) {
3665 if (!ex) {
3666 return sym_wait_writable;
3667 }
3668 else {
3669 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3670 }
3671 }
3672 rb_syserr_fail_path(e, fptr->pathv);
3673 }
3674
3675 return LONG2FIX(n);
3676}
3677
3678/*
3679 * call-seq:
3680 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3681 *
3682 * Reads bytes from the stream; the stream must be opened for reading
3683 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3684 *
3685 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3686 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3687 *
3688 * Returns a string (either a new string or the given +out_string+)
3689 * containing the bytes read.
3690 * The encoding of the string depends on both +maxLen+ and +out_string+:
3691 *
3692 * - +maxlen+ is +nil+: uses internal encoding of +self+
3693 * (regardless of whether +out_string+ was given).
3694 * - +maxlen+ not +nil+:
3695 *
3696 * - +out_string+ given: encoding of +out_string+ not modified.
3697 * - +out_string+ not given: ASCII-8BIT is used.
3698 *
3699 * <b>Without Argument +out_string+</b>
3700 *
3701 * When argument +out_string+ is omitted,
3702 * the returned value is a new string:
3703 *
3704 * f = File.new('t.txt')
3705 * f.read
3706 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3707 * f.rewind
3708 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3709 * f.read(30) # => "rth line\r\nFifth line\r\n"
3710 * f.read(30) # => nil
3711 * f.close
3712 *
3713 * If +maxlen+ is zero, returns an empty string.
3714 *
3715 * <b> With Argument +out_string+</b>
3716 *
3717 * When argument +out_string+ is given,
3718 * the returned value is +out_string+, whose content is replaced:
3719 *
3720 * f = File.new('t.txt')
3721 * s = 'foo' # => "foo"
3722 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3723 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3724 * f.rewind
3725 * s = 'bar'
3726 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3727 * s # => "First line\r\nSecond line\r\n\r\nFou"
3728 * s = 'baz'
3729 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3730 * s # => "rth line\r\nFifth line\r\n"
3731 * s = 'bat'
3732 * f.read(30, s) # => nil
3733 * s # => ""
3734 * f.close
3735 *
3736 * Note that this method behaves like the fread() function in C.
3737 * This means it retries to invoke read(2) system calls to read data
3738 * with the specified maxlen (or until EOF).
3739 *
3740 * This behavior is preserved even if the stream is in non-blocking mode.
3741 * (This method is non-blocking-flag insensitive as other methods.)
3742 *
3743 * If you need the behavior like a single read(2) system call,
3744 * consider #readpartial, #read_nonblock, and #sysread.
3745 *
3746 * Related: IO#write.
3747 */
3748
3749static VALUE
3750io_read(int argc, VALUE *argv, VALUE io)
3751{
3752 rb_io_t *fptr;
3753 long n, len;
3754 VALUE length, str;
3755 int shrinkable;
3756#if RUBY_CRLF_ENVIRONMENT
3757 int previous_mode;
3758#endif
3759
3760 rb_scan_args(argc, argv, "02", &length, &str);
3761
3762 if (NIL_P(length)) {
3763 GetOpenFile(io, fptr);
3765 return read_all(fptr, remain_size(fptr), str);
3766 }
3767 len = NUM2LONG(length);
3768 if (len < 0) {
3769 rb_raise(rb_eArgError, "negative length %ld given", len);
3770 }
3771
3772 shrinkable = io_setstrbuf(&str,len);
3773
3774 GetOpenFile(io, fptr);
3776 if (len == 0) {
3777 io_set_read_length(str, 0, shrinkable);
3778 return str;
3779 }
3780
3781 READ_CHECK(fptr);
3782#if RUBY_CRLF_ENVIRONMENT
3783 previous_mode = set_binary_mode_with_seek_cur(fptr);
3784#endif
3785 n = io_fread(str, 0, len, fptr);
3786 io_set_read_length(str, n, shrinkable);
3787#if RUBY_CRLF_ENVIRONMENT
3788 if (previous_mode == O_TEXT) {
3789 setmode(fptr->fd, O_TEXT);
3790 }
3791#endif
3792 if (n == 0) return Qnil;
3793
3794 return str;
3795}
3796
3797static void
3798rscheck(const char *rsptr, long rslen, VALUE rs)
3799{
3800 if (!rs) return;
3801 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3802 rb_raise(rb_eRuntimeError, "rs modified");
3803}
3804
3805static int
3806appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
3807{
3808 VALUE str = *strp;
3809 long limit = *lp;
3810
3811 if (NEED_READCONV(fptr)) {
3812 SET_BINARY_MODE(fptr);
3813 make_readconv(fptr, 0);
3814 do {
3815 const char *p, *e;
3816 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3817 if (searchlen) {
3818 p = READ_CHAR_PENDING_PTR(fptr);
3819 if (0 < limit && limit < searchlen)
3820 searchlen = (int)limit;
3821 e = memchr(p, delim, searchlen);
3822 if (e) {
3823 int len = (int)(e-p+1);
3824 if (NIL_P(str))
3825 *strp = str = rb_str_new(p, len);
3826 else
3827 rb_str_buf_cat(str, p, len);
3828 fptr->cbuf.off += len;
3829 fptr->cbuf.len -= len;
3830 limit -= len;
3831 *lp = limit;
3832 return delim;
3833 }
3834
3835 if (NIL_P(str))
3836 *strp = str = rb_str_new(p, searchlen);
3837 else
3838 rb_str_buf_cat(str, p, searchlen);
3839 fptr->cbuf.off += searchlen;
3840 fptr->cbuf.len -= searchlen;
3841 limit -= searchlen;
3842
3843 if (limit == 0) {
3844 *lp = limit;
3845 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3846 }
3847 }
3848 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3849 clear_readconv(fptr);
3850 *lp = limit;
3851 return EOF;
3852 }
3853
3854 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3855 do {
3856 long pending = READ_DATA_PENDING_COUNT(fptr);
3857 if (pending > 0) {
3858 const char *p = READ_DATA_PENDING_PTR(fptr);
3859 const char *e;
3860 long last;
3861
3862 if (limit > 0 && pending > limit) pending = limit;
3863 e = memchr(p, delim, pending);
3864 if (e) pending = e - p + 1;
3865 if (!NIL_P(str)) {
3866 last = RSTRING_LEN(str);
3867 rb_str_resize(str, last + pending);
3868 }
3869 else {
3870 last = 0;
3871 *strp = str = rb_str_buf_new(pending);
3872 rb_str_set_len(str, pending);
3873 }
3874 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3875 limit -= pending;
3876 *lp = limit;
3877 if (e) return delim;
3878 if (limit == 0)
3879 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3880 }
3881 READ_CHECK(fptr);
3882 } while (io_fillbuf(fptr) >= 0);
3883 *lp = limit;
3884 return EOF;
3885}
3886
3887static inline int
3888swallow(rb_io_t *fptr, int term)
3889{
3890 if (NEED_READCONV(fptr)) {
3891 rb_encoding *enc = io_read_encoding(fptr);
3892 int needconv = rb_enc_mbminlen(enc) != 1;
3893 SET_BINARY_MODE(fptr);
3894 make_readconv(fptr, 0);
3895 do {
3896 size_t cnt;
3897 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3898 const char *p = READ_CHAR_PENDING_PTR(fptr);
3899 int i;
3900 if (!needconv) {
3901 if (*p != term) return TRUE;
3902 i = (int)cnt;
3903 while (--i && *++p == term);
3904 }
3905 else {
3906 const char *e = p + cnt;
3907 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3908 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3909 i = (int)(e - p);
3910 }
3911 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3912 }
3913 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3914 return FALSE;
3915 }
3916
3917 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3918 do {
3919 size_t cnt;
3920 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3921 char buf[1024];
3922 const char *p = READ_DATA_PENDING_PTR(fptr);
3923 int i;
3924 if (cnt > sizeof buf) cnt = sizeof buf;
3925 if (*p != term) return TRUE;
3926 i = (int)cnt;
3927 while (--i && *++p == term);
3928 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
3929 rb_sys_fail_path(fptr->pathv);
3930 }
3931 READ_CHECK(fptr);
3932 } while (io_fillbuf(fptr) == 0);
3933 return FALSE;
3934}
3935
3936static VALUE
3937rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
3938{
3939 VALUE str = Qnil;
3940 int len = 0;
3941 long pos = 0;
3942 int cr = 0;
3943
3944 do {
3945 int pending = READ_DATA_PENDING_COUNT(fptr);
3946
3947 if (pending > 0) {
3948 const char *p = READ_DATA_PENDING_PTR(fptr);
3949 const char *e;
3950 int chomplen = 0;
3951
3952 e = memchr(p, '\n', pending);
3953 if (e) {
3954 pending = (int)(e - p + 1);
3955 if (chomp) {
3956 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
3957 }
3958 }
3959 if (NIL_P(str)) {
3960 str = rb_str_new(p, pending - chomplen);
3961 fptr->rbuf.off += pending;
3962 fptr->rbuf.len -= pending;
3963 }
3964 else {
3965 rb_str_resize(str, len + pending - chomplen);
3966 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
3967 fptr->rbuf.off += chomplen;
3968 fptr->rbuf.len -= chomplen;
3969 if (pending == 1 && chomplen == 1 && len > 0) {
3970 if (RSTRING_PTR(str)[len-1] == '\r') {
3971 rb_str_resize(str, --len);
3972 break;
3973 }
3974 }
3975 }
3976 len += pending - chomplen;
3977 if (cr != ENC_CODERANGE_BROKEN)
3978 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
3979 if (e) break;
3980 }
3981 READ_CHECK(fptr);
3982 } while (io_fillbuf(fptr) >= 0);
3983 if (NIL_P(str)) return Qnil;
3984
3985 str = io_enc_str(str, fptr);
3986 ENC_CODERANGE_SET(str, cr);
3987 fptr->lineno++;
3988
3989 return str;
3990}
3991
3993 VALUE io;
3994 VALUE rs;
3995 long limit;
3996 unsigned int chomp: 1;
3997};
3998
3999static void
4000extract_getline_opts(VALUE opts, struct getline_arg *args)
4001{
4002 int chomp = FALSE;
4003 if (!NIL_P(opts)) {
4004 static ID kwds[1];
4005 VALUE vchomp;
4006 if (!kwds[0]) {
4007 kwds[0] = rb_intern_const("chomp");
4008 }
4009 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4010 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4011 }
4012 args->chomp = chomp;
4013}
4014
4015static void
4016extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4017{
4018 VALUE rs = rb_rs, lim = Qnil;
4019
4020 if (argc == 1) {
4021 VALUE tmp = Qnil;
4022
4023 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4024 rs = tmp;
4025 }
4026 else {
4027 lim = argv[0];
4028 }
4029 }
4030 else if (2 <= argc) {
4031 rs = argv[0], lim = argv[1];
4032 if (!NIL_P(rs))
4033 StringValue(rs);
4034 }
4035 args->rs = rs;
4036 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4037}
4038
4039static void
4040check_getline_args(VALUE *rsp, long *limit, VALUE io)
4041{
4042 rb_io_t *fptr;
4043 VALUE rs = *rsp;
4044
4045 if (!NIL_P(rs)) {
4046 rb_encoding *enc_rs, *enc_io;
4047
4048 GetOpenFile(io, fptr);
4049 enc_rs = rb_enc_get(rs);
4050 enc_io = io_read_encoding(fptr);
4051 if (enc_io != enc_rs &&
4052 (!is_ascii_string(rs) ||
4053 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4054 if (rs == rb_default_rs) {
4055 rs = rb_enc_str_new(0, 0, enc_io);
4056 rb_str_buf_cat_ascii(rs, "\n");
4057 *rsp = rs;
4058 }
4059 else {
4060 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4061 rb_enc_name(enc_io),
4062 rb_enc_name(enc_rs));
4063 }
4064 }
4065 }
4066}
4067
4068static void
4069prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4070{
4071 VALUE opts;
4072 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4073 extract_getline_args(argc, argv, args);
4074 extract_getline_opts(opts, args);
4075 check_getline_args(&args->rs, &args->limit, io);
4076}
4077
4078static VALUE
4079rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4080{
4081 VALUE str = Qnil;
4082 int nolimit = 0;
4083 rb_encoding *enc;
4084
4086 if (NIL_P(rs) && limit < 0) {
4087 str = read_all(fptr, 0, Qnil);
4088 if (RSTRING_LEN(str) == 0) return Qnil;
4089 }
4090 else if (limit == 0) {
4091 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4092 }
4093 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4094 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4095 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4096 return rb_io_getline_fast(fptr, enc, chomp);
4097 }
4098 else {
4099 int c, newline = -1;
4100 const char *rsptr = 0;
4101 long rslen = 0;
4102 int rspara = 0;
4103 int extra_limit = 16;
4104 int chomp_cr = chomp;
4105
4106 SET_BINARY_MODE(fptr);
4107 enc = io_read_encoding(fptr);
4108
4109 if (!NIL_P(rs)) {
4110 rslen = RSTRING_LEN(rs);
4111 if (rslen == 0) {
4112 rsptr = "\n\n";
4113 rslen = 2;
4114 rspara = 1;
4115 swallow(fptr, '\n');
4116 rs = 0;
4117 if (!rb_enc_asciicompat(enc)) {
4118 rs = rb_usascii_str_new(rsptr, rslen);
4119 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
4120 OBJ_FREEZE(rs);
4121 rsptr = RSTRING_PTR(rs);
4122 rslen = RSTRING_LEN(rs);
4123 }
4124 }
4125 else {
4126 rsptr = RSTRING_PTR(rs);
4127 }
4128 newline = (unsigned char)rsptr[rslen - 1];
4129 chomp_cr = chomp && rslen == 1 && newline == '\n';
4130 }
4131
4132 /* MS - Optimization */
4133 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
4134 const char *s, *p, *pp, *e;
4135
4136 if (c == newline) {
4137 if (RSTRING_LEN(str) < rslen) continue;
4138 s = RSTRING_PTR(str);
4139 e = RSTRING_END(str);
4140 p = e - rslen;
4141 pp = rb_enc_left_char_head(s, p, e, enc);
4142 if (pp != p) continue;
4143 if (!rspara) rscheck(rsptr, rslen, rs);
4144 if (memcmp(p, rsptr, rslen) == 0) {
4145 if (chomp) {
4146 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4147 rb_str_set_len(str, p - s);
4148 }
4149 break;
4150 }
4151 }
4152 if (limit == 0) {
4153 s = RSTRING_PTR(str);
4154 p = RSTRING_END(str);
4155 pp = rb_enc_left_char_head(s, p-1, p, enc);
4156 if (extra_limit &&
4157 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4158 /* relax the limit while incomplete character.
4159 * extra_limit limits the relax length */
4160 limit = 1;
4161 extra_limit--;
4162 }
4163 else {
4164 nolimit = 1;
4165 break;
4166 }
4167 }
4168 }
4169
4170 if (rspara && c != EOF)
4171 swallow(fptr, '\n');
4172 if (!NIL_P(str))
4173 str = io_enc_str(str, fptr);
4174 }
4175
4176 if (!NIL_P(str) && !nolimit) {
4177 fptr->lineno++;
4178 }
4179
4180 return str;
4181}
4182
4183static VALUE
4184rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4185{
4186 rb_io_t *fptr;
4187 int old_lineno, new_lineno;
4188 VALUE str;
4189
4190 GetOpenFile(io, fptr);
4191 old_lineno = fptr->lineno;
4192 str = rb_io_getline_0(rs, limit, chomp, fptr);
4193 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4194 if (io == ARGF.current_file) {
4195 ARGF.lineno += new_lineno - old_lineno;
4196 ARGF.last_lineno = ARGF.lineno;
4197 }
4198 else {
4199 ARGF.last_lineno = new_lineno;
4200 }
4201 }
4202
4203 return str;
4204}
4205
4206static VALUE
4207rb_io_getline(int argc, VALUE *argv, VALUE io)
4208{
4209 struct getline_arg args;
4210
4211 prepare_getline_args(argc, argv, &args, io);
4212 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4213}
4214
4215VALUE
4217{
4218 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4219}
4220
4221VALUE
4222rb_io_gets_internal(VALUE io)
4223{
4224 rb_io_t *fptr;
4225 GetOpenFile(io, fptr);
4226 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4227}
4228
4229/*
4230 * call-seq:
4231 * gets(sep = $/, chomp: false) -> string or nil
4232 * gets(limit, chomp: false) -> string or nil
4233 * gets(sep, limit, chomp: false) -> string or nil
4234 *
4235 * Reads and returns a line from the stream;
4236 * assigns the return value to <tt>$_</tt>.
4237 * See {Line IO}[rdoc-ref:IO@Line+IO].
4238 *
4239 * With no arguments given, returns the next line
4240 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4241 *
4242 * f = File.open('t.txt')
4243 * f.gets # => "First line\n"
4244 * $_ # => "First line\n"
4245 * f.gets # => "\n"
4246 * f.gets # => "Fourth line\n"
4247 * f.gets # => "Fifth line\n"
4248 * f.gets # => nil
4249 * f.close
4250 *
4251 * With only string argument +sep+ given,
4252 * returns the next line as determined by line separator +sep+,
4253 * or +nil+ if none;
4254 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4255 *
4256 * f = File.new('t.txt')
4257 * f.gets('l') # => "First l"
4258 * f.gets('li') # => "ine\nSecond li"
4259 * f.gets('lin') # => "ne\n\nFourth lin"
4260 * f.gets # => "e\n"
4261 * f.close
4262 *
4263 * The two special values for +sep+ are honored:
4264 *
4265 * f = File.new('t.txt')
4266 * # Get all.
4267 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4268 * f.rewind
4269 * # Get paragraph (up to two line separators).
4270 * f.gets('') # => "First line\nSecond line\n\n"
4271 * f.close
4272 *
4273 * With only integer argument +limit+ given,
4274 * limits the number of bytes in the line;
4275 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4276 *
4277 * # No more than one line.
4278 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4279 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4280 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4281 *
4282 * With arguments +sep+ and +limit+ given,
4283 * combines the two behaviors:
4284 *
4285 * - Returns the next line as determined by line separator +sep+,
4286 * or +nil+ if none.
4287 * - But returns no more bytes than are allowed by the limit.
4288 *
4289 * Optional keyword argument +chomp+ specifies whether line separators
4290 * are to be omitted:
4291 *
4292 * f = File.open('t.txt')
4293 * # Chomp the lines.
4294 * f.gets(chomp: true) # => "First line"
4295 * f.gets(chomp: true) # => "Second line"
4296 * f.gets(chomp: true) # => ""
4297 * f.gets(chomp: true) # => "Fourth line"
4298 * f.gets(chomp: true) # => "Fifth line"
4299 * f.gets(chomp: true) # => nil
4300 * f.close
4301 *
4302 */
4303
4304static VALUE
4305rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4306{
4307 VALUE str;
4308
4309 str = rb_io_getline(argc, argv, io);
4310 rb_lastline_set(str);
4311
4312 return str;
4313}
4314
4315/*
4316 * call-seq:
4317 * lineno -> integer
4318 *
4319 * Returns the current line number for the stream;
4320 * see {Line Number}[rdoc-ref:IO@Line+Number].
4321 *
4322 */
4323
4324static VALUE
4325rb_io_lineno(VALUE io)
4326{
4327 rb_io_t *fptr;
4328
4329 GetOpenFile(io, fptr);
4331 return INT2NUM(fptr->lineno);
4332}
4333
4334/*
4335 * call-seq:
4336 * lineno = integer -> integer
4337 *
4338 * Sets and returns the line number for the stream;
4339 * see {Line Number}[rdoc-ref:IO@Line+Number].
4340 *
4341 */
4342
4343static VALUE
4344rb_io_set_lineno(VALUE io, VALUE lineno)
4345{
4346 rb_io_t *fptr;
4347
4348 GetOpenFile(io, fptr);
4350 fptr->lineno = NUM2INT(lineno);
4351 return lineno;
4352}
4353
4354/*
4355 * call-seq:
4356 * readline(sep = $/, chomp: false) -> string
4357 * readline(limit, chomp: false) -> string
4358 * readline(sep, limit, chomp: false) -> string
4359 *
4360 * Reads a line as with IO#gets, but raises EOFError if already at end-of-stream.
4361 *
4362 * Optional keyword argument +chomp+ specifies whether line separators
4363 * are to be omitted.
4364 */
4365
4366static VALUE
4367rb_io_readline(int argc, VALUE *argv, VALUE io)
4368{
4369 VALUE line = rb_io_gets_m(argc, argv, io);
4370
4371 if (NIL_P(line)) {
4372 rb_eof_error();
4373 }
4374 return line;
4375}
4376
4377static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4378
4379/*
4380 * call-seq:
4381 * readlines(sep = $/, chomp: false) -> array
4382 * readlines(limit, chomp: false) -> array
4383 * readlines(sep, limit, chomp: false) -> array
4384 *
4385 * Reads and returns all remaining line from the stream;
4386 * does not modify <tt>$_</tt>.
4387 * See {Line IO}[rdoc-ref:IO@Line+IO].
4388 *
4389 * With no arguments given, returns lines
4390 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4391 *
4392 * f = File.new('t.txt')
4393 * f.readlines
4394 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4395 * f.readlines # => []
4396 * f.close
4397 *
4398 * With only string argument +sep+ given,
4399 * returns lines as determined by line separator +sep+,
4400 * or +nil+ if none;
4401 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4402 *
4403 * f = File.new('t.txt')
4404 * f.readlines('li')
4405 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4406 * f.close
4407 *
4408 * The two special values for +sep+ are honored:
4409 *
4410 * f = File.new('t.txt')
4411 * # Get all into one string.
4412 * f.readlines(nil)
4413 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4414 * # Get paragraphs (up to two line separators).
4415 * f.rewind
4416 * f.readlines('')
4417 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4418 * f.close
4419 *
4420 * With only integer argument +limit+ given,
4421 * limits the number of bytes in each line;
4422 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4423 *
4424 * f = File.new('t.txt')
4425 * f.readlines(8)
4426 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4427 * f.close
4428 *
4429 * With arguments +sep+ and +limit+ given,
4430 * combines the two behaviors:
4431 *
4432 * - Returns lines as determined by line separator +sep+.
4433 * - But returns no more bytes in a line than are allowed by the limit.
4434 *
4435 * Optional keyword argument +chomp+ specifies whether line separators
4436 * are to be omitted:
4437 *
4438 * f = File.new('t.txt')
4439 * f.readlines(chomp: true)
4440 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4441 * f.close
4442 *
4443 */
4444
4445static VALUE
4446rb_io_readlines(int argc, VALUE *argv, VALUE io)
4447{
4448 struct getline_arg args;
4449
4450 prepare_getline_args(argc, argv, &args, io);
4451 return io_readlines(&args, io);
4452}
4453
4454static VALUE
4455io_readlines(const struct getline_arg *arg, VALUE io)
4456{
4457 VALUE line, ary;
4458
4459 if (arg->limit == 0)
4460 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4461 ary = rb_ary_new();
4462 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4463 rb_ary_push(ary, line);
4464 }
4465 return ary;
4466}
4467
4468/*
4469 * call-seq:
4470 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4471 * each_line(limit, chomp: false) {|line| ... } -> self
4472 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4473 * each_line -> enumerator
4474 *
4475 * Calls the block with each remaining line read from the stream;
4476 * returns +self+.
4477 * Does nothing if already at end-of-stream;
4478 * See {Line IO}[rdoc-ref:IO@Line+IO].
4479 *
4480 * With no arguments given, reads lines
4481 * as determined by line separator <tt>$/</tt>:
4482 *
4483 * f = File.new('t.txt')
4484 * f.each_line {|line| p line }
4485 * f.each_line {|line| fail 'Cannot happen' }
4486 * f.close
4487 *
4488 * Output:
4489 *
4490 * "First line\n"
4491 * "Second line\n"
4492 * "\n"
4493 * "Fourth line\n"
4494 * "Fifth line\n"
4495 *
4496 * With only string argument +sep+ given,
4497 * reads lines as determined by line separator +sep+;
4498 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4499 *
4500 * f = File.new('t.txt')
4501 * f.each_line('li') {|line| p line }
4502 * f.close
4503 *
4504 * Output:
4505 *
4506 * "First li"
4507 * "ne\nSecond li"
4508 * "ne\n\nFourth li"
4509 * "ne\nFifth li"
4510 * "ne\n"
4511 *
4512 * The two special values for +sep+ are honored:
4513 *
4514 * f = File.new('t.txt')
4515 * # Get all into one string.
4516 * f.each_line(nil) {|line| p line }
4517 * f.close
4518 *
4519 * Output:
4520 *
4521 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4522 *
4523 * f.rewind
4524 * # Get paragraphs (up to two line separators).
4525 * f.each_line('') {|line| p line }
4526 *
4527 * Output:
4528 *
4529 * "First line\nSecond line\n\n"
4530 * "Fourth line\nFifth line\n"
4531 *
4532 * With only integer argument +limit+ given,
4533 * limits the number of bytes in each line;
4534 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4535 *
4536 * f = File.new('t.txt')
4537 * f.each_line(8) {|line| p line }
4538 * f.close
4539 *
4540 * Output:
4541 *
4542 * "First li"
4543 * "ne\n"
4544 * "Second l"
4545 * "ine\n"
4546 * "\n"
4547 * "Fourth l"
4548 * "ine\n"
4549 * "Fifth li"
4550 * "ne\n"
4551 *
4552 * With arguments +sep+ and +limit+ given,
4553 * combines the two behaviors:
4554 *
4555 * - Calls with the next line as determined by line separator +sep+.
4556 * - But returns no more bytes than are allowed by the limit.
4557 *
4558 * Optional keyword argument +chomp+ specifies whether line separators
4559 * are to be omitted:
4560 *
4561 * f = File.new('t.txt')
4562 * f.each_line(chomp: true) {|line| p line }
4563 * f.close
4564 *
4565 * Output:
4566 *
4567 * "First line"
4568 * "Second line"
4569 * ""
4570 * "Fourth line"
4571 * "Fifth line"
4572 *
4573 * Returns an Enumerator if no block is given.
4574 *
4575 * IO#each is an alias for IO#each_line.
4576 *
4577 */
4578
4579static VALUE
4580rb_io_each_line(int argc, VALUE *argv, VALUE io)
4581{
4582 VALUE str;
4583 struct getline_arg args;
4584
4585 RETURN_ENUMERATOR(io, argc, argv);
4586 prepare_getline_args(argc, argv, &args, io);
4587 if (args.limit == 0)
4588 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4589 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4590 rb_yield(str);
4591 }
4592 return io;
4593}
4594
4595/*
4596 * call-seq:
4597 * each_byte {|byte| ... } -> self
4598 * each_byte -> enumerator
4599 *
4600 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4601 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4602 *
4603 * f = File.new('t.rus')
4604 * a = []
4605 * f.each_byte {|b| a << b }
4606 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4607 * f.close
4608 *
4609 * Returns an Enumerator if no block is given.
4610 *
4611 * Related: IO#each_char, IO#each_codepoint.
4612 *
4613 */
4614
4615static VALUE
4616rb_io_each_byte(VALUE io)
4617{
4618 rb_io_t *fptr;
4619
4620 RETURN_ENUMERATOR(io, 0, 0);
4621 GetOpenFile(io, fptr);
4622
4623 do {
4624 while (fptr->rbuf.len > 0) {
4625 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4626 fptr->rbuf.len--;
4627 rb_yield(INT2FIX(*p & 0xff));
4629 errno = 0;
4630 }
4631 READ_CHECK(fptr);
4632 } while (io_fillbuf(fptr) >= 0);
4633 return io;
4634}
4635
4636static VALUE
4637io_getc(rb_io_t *fptr, rb_encoding *enc)
4638{
4639 int r, n, cr = 0;
4640 VALUE str;
4641
4642 if (NEED_READCONV(fptr)) {
4643 rb_encoding *read_enc = io_read_encoding(fptr);
4644
4645 str = Qnil;
4646 SET_BINARY_MODE(fptr);
4647 make_readconv(fptr, 0);
4648
4649 while (1) {
4650 if (fptr->cbuf.len) {
4651 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4652 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4653 read_enc);
4654 if (!MBCLEN_NEEDMORE_P(r))
4655 break;
4656 if (fptr->cbuf.len == fptr->cbuf.capa) {
4657 rb_raise(rb_eIOError, "too long character");
4658 }
4659 }
4660
4661 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4662 if (fptr->cbuf.len == 0) {
4663 clear_readconv(fptr);
4664 return Qnil;
4665 }
4666 /* return an unit of an incomplete character just before EOF */
4667 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4668 fptr->cbuf.off += 1;
4669 fptr->cbuf.len -= 1;
4670 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4672 return str;
4673 }
4674 }
4675 if (MBCLEN_INVALID_P(r)) {
4676 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4677 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4678 read_enc);
4679 io_shift_cbuf(fptr, r, &str);
4681 }
4682 else {
4683 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4685 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4686 ISASCII(RSTRING_PTR(str)[0])) {
4687 cr = ENC_CODERANGE_7BIT;
4688 }
4689 }
4690 str = io_enc_str(str, fptr);
4691 ENC_CODERANGE_SET(str, cr);
4692 return str;
4693 }
4694
4695 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4696 if (io_fillbuf(fptr) < 0) {
4697 return Qnil;
4698 }
4699 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4700 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4701 fptr->rbuf.off += 1;
4702 fptr->rbuf.len -= 1;
4703 cr = ENC_CODERANGE_7BIT;
4704 }
4705 else {
4706 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4707 if (MBCLEN_CHARFOUND_P(r) &&
4708 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4709 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4710 fptr->rbuf.off += n;
4711 fptr->rbuf.len -= n;
4713 }
4714 else if (MBCLEN_NEEDMORE_P(r)) {
4715 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4716 fptr->rbuf.len = 0;
4717 getc_needmore:
4718 if (io_fillbuf(fptr) != -1) {
4719 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4720 fptr->rbuf.off++;
4721 fptr->rbuf.len--;
4722 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4723 if (MBCLEN_NEEDMORE_P(r)) {
4724 goto getc_needmore;
4725 }
4726 else if (MBCLEN_CHARFOUND_P(r)) {
4728 }
4729 }
4730 }
4731 else {
4732 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4733 fptr->rbuf.off++;
4734 fptr->rbuf.len--;
4735 }
4736 }
4737 if (!cr) cr = ENC_CODERANGE_BROKEN;
4738 str = io_enc_str(str, fptr);
4739 ENC_CODERANGE_SET(str, cr);
4740 return str;
4741}
4742
4743/*
4744 * call-seq:
4745 * each_char {|c| ... } -> self
4746 * each_char -> enumerator
4747 *
4748 * Calls the given block with each character in the stream; returns +self+.
4749 * See {Character IO}[rdoc-ref:IO@Character+IO].
4750 *
4751 * f = File.new('t.rus')
4752 * a = []
4753 * f.each_char {|c| a << c.ord }
4754 * a # => [1090, 1077, 1089, 1090]
4755 * f.close
4756 *
4757 * Returns an Enumerator if no block is given.
4758 *
4759 * Related: IO#each_byte, IO#each_codepoint.
4760 *
4761 */
4762
4763static VALUE
4764rb_io_each_char(VALUE io)
4765{
4766 rb_io_t *fptr;
4767 rb_encoding *enc;
4768 VALUE c;
4769
4770 RETURN_ENUMERATOR(io, 0, 0);
4771 GetOpenFile(io, fptr);
4773
4774 enc = io_input_encoding(fptr);
4775 READ_CHECK(fptr);
4776 while (!NIL_P(c = io_getc(fptr, enc))) {
4777 rb_yield(c);
4778 }
4779 return io;
4780}
4781
4782/*
4783 * call-seq:
4784 * each_codepoint {|c| ... } -> self
4785 * each_codepoint -> enumerator
4786 *
4787 * Calls the given block with each codepoint in the stream; returns +self+:
4788 *
4789 * f = File.new('t.rus')
4790 * a = []
4791 * f.each_codepoint {|c| a << c }
4792 * a # => [1090, 1077, 1089, 1090]
4793 * f.close
4794 *
4795 * Returns an Enumerator if no block is given.
4796 *
4797 * Related: IO#each_byte, IO#each_char.
4798 *
4799 */
4800
4801static VALUE
4802rb_io_each_codepoint(VALUE io)
4803{
4804 rb_io_t *fptr;
4805 rb_encoding *enc;
4806 unsigned int c;
4807 int r, n;
4808
4809 RETURN_ENUMERATOR(io, 0, 0);
4810 GetOpenFile(io, fptr);
4812
4813 READ_CHECK(fptr);
4814 if (NEED_READCONV(fptr)) {
4815 SET_BINARY_MODE(fptr);
4816 r = 1; /* no invalid char yet */
4817 for (;;) {
4818 make_readconv(fptr, 0);
4819 for (;;) {
4820 if (fptr->cbuf.len) {
4821 if (fptr->encs.enc)
4822 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4823 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4824 fptr->encs.enc);
4825 else
4826 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4827 if (!MBCLEN_NEEDMORE_P(r))
4828 break;
4829 if (fptr->cbuf.len == fptr->cbuf.capa) {
4830 rb_raise(rb_eIOError, "too long character");
4831 }
4832 }
4833 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4834 clear_readconv(fptr);
4835 if (!MBCLEN_CHARFOUND_P(r)) {
4836 enc = fptr->encs.enc;
4837 goto invalid;
4838 }
4839 return io;
4840 }
4841 }
4842 if (MBCLEN_INVALID_P(r)) {
4843 enc = fptr->encs.enc;
4844 goto invalid;
4845 }
4846 n = MBCLEN_CHARFOUND_LEN(r);
4847 if (fptr->encs.enc) {
4848 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4849 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4850 fptr->encs.enc);
4851 }
4852 else {
4853 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4854 }
4855 fptr->cbuf.off += n;
4856 fptr->cbuf.len -= n;
4857 rb_yield(UINT2NUM(c));
4859 }
4860 }
4861 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4862 enc = io_input_encoding(fptr);
4863 while (io_fillbuf(fptr) >= 0) {
4864 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4865 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4866 if (MBCLEN_CHARFOUND_P(r) &&
4867 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4868 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4869 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4870 fptr->rbuf.off += n;
4871 fptr->rbuf.len -= n;
4872 rb_yield(UINT2NUM(c));
4873 }
4874 else if (MBCLEN_INVALID_P(r)) {
4875 goto invalid;
4876 }
4877 else if (MBCLEN_NEEDMORE_P(r)) {
4878 char cbuf[8], *p = cbuf;
4879 int more = MBCLEN_NEEDMORE_LEN(r);
4880 if (more > numberof(cbuf)) goto invalid;
4881 more += n = fptr->rbuf.len;
4882 if (more > numberof(cbuf)) goto invalid;
4883 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4884 (p += n, (more -= n) > 0)) {
4885 if (io_fillbuf(fptr) < 0) goto invalid;
4886 if ((n = fptr->rbuf.len) > more) n = more;
4887 }
4888 r = rb_enc_precise_mbclen(cbuf, p, enc);
4889 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4890 c = rb_enc_codepoint(cbuf, p, enc);
4891 rb_yield(UINT2NUM(c));
4892 }
4893 else {
4894 continue;
4895 }
4897 }
4898 return io;
4899
4900 invalid:
4901 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4903}
4904
4905/*
4906 * call-seq:
4907 * getc -> character or nil
4908 *
4909 * Reads and returns the next 1-character string from the stream;
4910 * returns +nil+ if already at end-of-stream.
4911 * See {Character IO}[rdoc-ref:IO@Character+IO].
4912 *
4913 * f = File.open('t.txt')
4914 * f.getc # => "F"
4915 * f.close
4916 * f = File.open('t.rus')
4917 * f.getc.ord # => 1090
4918 * f.close
4919 *
4920 * Related: IO#readchar (may raise EOFError).
4921 *
4922 */
4923
4924static VALUE
4925rb_io_getc(VALUE io)
4926{
4927 rb_io_t *fptr;
4928 rb_encoding *enc;
4929
4930 GetOpenFile(io, fptr);
4932
4933 enc = io_input_encoding(fptr);
4934 READ_CHECK(fptr);
4935 return io_getc(fptr, enc);
4936}
4937
4938/*
4939 * call-seq:
4940 * readchar -> string
4941 *
4942 * Reads and returns the next 1-character string from the stream;
4943 * raises EOFError if already at end-of-stream.
4944 * See {Character IO}[rdoc-ref:IO@Character+IO].
4945 *
4946 * f = File.open('t.txt')
4947 * f.readchar # => "F"
4948 * f.close
4949 * f = File.open('t.rus')
4950 * f.readchar.ord # => 1090
4951 * f.close
4952 *
4953 * Related: IO#getc (will not raise EOFError).
4954 *
4955 */
4956
4957static VALUE
4958rb_io_readchar(VALUE io)
4959{
4960 VALUE c = rb_io_getc(io);
4961
4962 if (NIL_P(c)) {
4963 rb_eof_error();
4964 }
4965 return c;
4966}
4967
4968/*
4969 * call-seq:
4970 * getbyte -> integer or nil
4971 *
4972 * Reads and returns the next byte (in range 0..255) from the stream;
4973 * returns +nil+ if already at end-of-stream.
4974 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4975 *
4976 * f = File.open('t.txt')
4977 * f.getbyte # => 70
4978 * f.close
4979 * f = File.open('t.rus')
4980 * f.getbyte # => 209
4981 * f.close
4982 *
4983 * Related: IO#readbyte (may raise EOFError).
4984 */
4985
4986VALUE
4988{
4989 rb_io_t *fptr;
4990 int c;
4991
4992 GetOpenFile(io, fptr);
4994 READ_CHECK(fptr);
4995 VALUE r_stdout = rb_ractor_stdout();
4996 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
4997 rb_io_t *ofp;
4998 GetOpenFile(r_stdout, ofp);
4999 if (ofp->mode & FMODE_TTY) {
5000 rb_io_flush(r_stdout);
5001 }
5002 }
5003 if (io_fillbuf(fptr) < 0) {
5004 return Qnil;
5005 }
5006 fptr->rbuf.off++;
5007 fptr->rbuf.len--;
5008 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5009 return INT2FIX(c & 0xff);
5010}
5011
5012/*
5013 * call-seq:
5014 * readbyte -> integer
5015 *
5016 * Reads and returns the next byte (in range 0..255) from the stream;
5017 * raises EOFError if already at end-of-stream.
5018 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5019 *
5020 * f = File.open('t.txt')
5021 * f.readbyte # => 70
5022 * f.close
5023 * f = File.open('t.rus')
5024 * f.readbyte # => 209
5025 * f.close
5026 *
5027 * Related: IO#getbyte (will not raise EOFError).
5028 *
5029 */
5030
5031static VALUE
5032rb_io_readbyte(VALUE io)
5033{
5034 VALUE c = rb_io_getbyte(io);
5035
5036 if (NIL_P(c)) {
5037 rb_eof_error();
5038 }
5039 return c;
5040}
5041
5042/*
5043 * call-seq:
5044 * ungetbyte(integer) -> nil
5045 * ungetbyte(string) -> nil
5046 *
5047 * Pushes back ("unshifts") the given data onto the stream's buffer,
5048 * placing the data so that it is next to be read; returns +nil+.
5049 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5050 *
5051 * Note that:
5052 *
5053 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5054 * - Calling #rewind on the stream discards the pushed-back data.
5055 *
5056 * When argument +integer+ is given, uses only its low-order byte:
5057 *
5058 * File.write('t.tmp', '012')
5059 * f = File.open('t.tmp')
5060 * f.ungetbyte(0x41) # => nil
5061 * f.read # => "A012"
5062 * f.rewind
5063 * f.ungetbyte(0x4243) # => nil
5064 * f.read # => "C012"
5065 * f.close
5066 *
5067 * When argument +string+ is given, uses all bytes:
5068 *
5069 * File.write('t.tmp', '012')
5070 * f = File.open('t.tmp')
5071 * f.ungetbyte('A') # => nil
5072 * f.read # => "A012"
5073 * f.rewind
5074 * f.ungetbyte('BCDE') # => nil
5075 * f.read # => "BCDE012"
5076 * f.close
5077 *
5078 */
5079
5080VALUE
5082{
5083 rb_io_t *fptr;
5084
5085 GetOpenFile(io, fptr);
5087 switch (TYPE(b)) {
5088 case T_NIL:
5089 return Qnil;
5090 case T_FIXNUM:
5091 case T_BIGNUM: ;
5092 VALUE v = rb_int_modulo(b, INT2FIX(256));
5093 unsigned char c = NUM2INT(v) & 0xFF;
5094 b = rb_str_new((const char *)&c, 1);
5095 break;
5096 default:
5097 SafeStringValue(b);
5098 }
5099 io_ungetbyte(b, fptr);
5100 return Qnil;
5101}
5102
5103/*
5104 * call-seq:
5105 * ungetc(integer) -> nil
5106 * ungetc(string) -> nil
5107 *
5108 * Pushes back ("unshifts") the given data onto the stream's buffer,
5109 * placing the data so that it is next to be read; returns +nil+.
5110 * See {Character IO}[rdoc-ref:IO@Character+IO].
5111 *
5112 * Note that:
5113 *
5114 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5115 * - Calling #rewind on the stream discards the pushed-back data.
5116 *
5117 * When argument +integer+ is given, interprets the integer as a character:
5118 *
5119 * File.write('t.tmp', '012')
5120 * f = File.open('t.tmp')
5121 * f.ungetc(0x41) # => nil
5122 * f.read # => "A012"
5123 * f.rewind
5124 * f.ungetc(0x0442) # => nil
5125 * f.getc.ord # => 1090
5126 * f.close
5127 *
5128 * When argument +string+ is given, uses all characters:
5129 *
5130 * File.write('t.tmp', '012')
5131 * f = File.open('t.tmp')
5132 * f.ungetc('A') # => nil
5133 * f.read # => "A012"
5134 * f.rewind
5135 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5136 * f.getc.ord # => 1090
5137 * f.getc.ord # => 1077
5138 * f.getc.ord # => 1089
5139 * f.getc.ord # => 1090
5140 * f.close
5141 *
5142 */
5143
5144VALUE
5146{
5147 rb_io_t *fptr;
5148 long len;
5149
5150 GetOpenFile(io, fptr);
5152 if (FIXNUM_P(c)) {
5153 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5154 }
5155 else if (RB_BIGNUM_TYPE_P(c)) {
5156 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5157 }
5158 else {
5159 SafeStringValue(c);
5160 }
5161 if (NEED_READCONV(fptr)) {
5162 SET_BINARY_MODE(fptr);
5163 len = RSTRING_LEN(c);
5164#if SIZEOF_LONG > SIZEOF_INT
5165 if (len > INT_MAX)
5166 rb_raise(rb_eIOError, "ungetc failed");
5167#endif
5168 make_readconv(fptr, (int)len);
5169 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5170 rb_raise(rb_eIOError, "ungetc failed");
5171 if (fptr->cbuf.off < len) {
5172 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5173 fptr->cbuf.ptr+fptr->cbuf.off,
5174 char, fptr->cbuf.len);
5175 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5176 }
5177 fptr->cbuf.off -= (int)len;
5178 fptr->cbuf.len += (int)len;
5179 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5180 }
5181 else {
5182 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5183 io_ungetbyte(c, fptr);
5184 }
5185 return Qnil;
5186}
5187
5188/*
5189 * call-seq:
5190 * isatty -> true or false
5191 *
5192 * Returns +true+ if the stream is associated with a terminal device (tty),
5193 * +false+ otherwise:
5194 *
5195 * f = File.new('t.txt').isatty #=> false
5196 * f.close
5197 * f = File.new('/dev/tty').isatty #=> true
5198 * f.close
5199 *
5200 * IO#tty? is an alias for IO#isatty.
5201 *
5202 */
5203
5204static VALUE
5205rb_io_isatty(VALUE io)
5206{
5207 rb_io_t *fptr;
5208
5209 GetOpenFile(io, fptr);
5210 return RBOOL(isatty(fptr->fd) != 0);
5211}
5212
5213#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5214/*
5215 * call-seq:
5216 * close_on_exec? -> true or false
5217 *
5218 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5219 *
5220 * f = File.open('t.txt')
5221 * f.close_on_exec? # => true
5222 * f.close_on_exec = false
5223 * f.close_on_exec? # => false
5224 * f.close
5225 *
5226 */
5227
5228static VALUE
5229rb_io_close_on_exec_p(VALUE io)
5230{
5231 rb_io_t *fptr;
5232 VALUE write_io;
5233 int fd, ret;
5234
5235 write_io = GetWriteIO(io);
5236 if (io != write_io) {
5237 GetOpenFile(write_io, fptr);
5238 if (fptr && 0 <= (fd = fptr->fd)) {
5239 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5240 if (!(ret & FD_CLOEXEC)) return Qfalse;
5241 }
5242 }
5243
5244 GetOpenFile(io, fptr);
5245 if (fptr && 0 <= (fd = fptr->fd)) {
5246 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5247 if (!(ret & FD_CLOEXEC)) return Qfalse;
5248 }
5249 return Qtrue;
5250}
5251#else
5252#define rb_io_close_on_exec_p rb_f_notimplement
5253#endif
5254
5255#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5256/*
5257 * call-seq:
5258 * self.close_on_exec = bool -> true or false
5259 *
5260 * Sets a close-on-exec flag.
5261 *
5262 * f = open("/dev/null")
5263 * f.close_on_exec = true
5264 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5265 * f.closed? #=> false
5266 *
5267 * Ruby sets close-on-exec flags of all file descriptors by default
5268 * since Ruby 2.0.0.
5269 * So you don't need to set by yourself.
5270 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5271 * if another thread use fork() and exec() (via system() method for example).
5272 * If you really needs file descriptor inheritance to child process,
5273 * use spawn()'s argument such as fd=>fd.
5274 */
5275
5276static VALUE
5277rb_io_set_close_on_exec(VALUE io, VALUE arg)
5278{
5279 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5280 rb_io_t *fptr;
5281 VALUE write_io;
5282 int fd, ret;
5283
5284 write_io = GetWriteIO(io);
5285 if (io != write_io) {
5286 GetOpenFile(write_io, fptr);
5287 if (fptr && 0 <= (fd = fptr->fd)) {
5288 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5289 if ((ret & FD_CLOEXEC) != flag) {
5290 ret = (ret & ~FD_CLOEXEC) | flag;
5291 ret = fcntl(fd, F_SETFD, ret);
5292 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5293 }
5294 }
5295
5296 }
5297
5298 GetOpenFile(io, fptr);
5299 if (fptr && 0 <= (fd = fptr->fd)) {
5300 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5301 if ((ret & FD_CLOEXEC) != flag) {
5302 ret = (ret & ~FD_CLOEXEC) | flag;
5303 ret = fcntl(fd, F_SETFD, ret);
5304 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5305 }
5306 }
5307 return Qnil;
5308}
5309#else
5310#define rb_io_set_close_on_exec rb_f_notimplement
5311#endif
5312
5313#define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
5314#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5315
5316static VALUE
5317finish_writeconv(rb_io_t *fptr, int noalloc)
5318{
5319 unsigned char *ds, *dp, *de;
5321
5322 if (!fptr->wbuf.ptr) {
5323 unsigned char buf[1024];
5324
5326 while (res == econv_destination_buffer_full) {
5327 ds = dp = buf;
5328 de = buf + sizeof(buf);
5329 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5330 while (dp-ds) {
5331 size_t remaining = dp-ds;
5332 long result = rb_io_write_memory(fptr, ds, remaining);
5333
5334 if (result > 0) {
5335 ds += result;
5336 if ((size_t)result == remaining) break;
5337 }
5338 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5339 if (fptr->fd < 0)
5340 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5341 }
5342 else {
5343 return noalloc ? Qtrue : INT2NUM(errno);
5344 }
5345 }
5346 if (res == econv_invalid_byte_sequence ||
5347 res == econv_incomplete_input ||
5349 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5350 }
5351 }
5352
5353 return Qnil;
5354 }
5355
5357 while (res == econv_destination_buffer_full) {
5358 if (fptr->wbuf.len == fptr->wbuf.capa) {
5359 if (io_fflush(fptr) < 0) {
5360 return noalloc ? Qtrue : INT2NUM(errno);
5361 }
5362 }
5363
5364 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5365 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5366 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5367 fptr->wbuf.len += (int)(dp - ds);
5368 if (res == econv_invalid_byte_sequence ||
5369 res == econv_incomplete_input ||
5371 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5372 }
5373 }
5374 return Qnil;
5375}
5376
5378 rb_io_t *fptr;
5379 int noalloc;
5380};
5381
5382static VALUE
5383finish_writeconv_sync(VALUE arg)
5384{
5385 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5386 return finish_writeconv(p->fptr, p->noalloc);
5387}
5388
5389static void*
5390nogvl_close(void *ptr)
5391{
5392 int *fd = ptr;
5393
5394 return (void*)(intptr_t)close(*fd);
5395}
5396
5397static int
5398maygvl_close(int fd, int keepgvl)
5399{
5400 if (keepgvl)
5401 return close(fd);
5402
5403 /*
5404 * close() may block for certain file types (NFS, SO_LINGER sockets,
5405 * inotify), so let other threads run.
5406 */
5407 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
5408}
5409
5410static void*
5411nogvl_fclose(void *ptr)
5412{
5413 FILE *file = ptr;
5414
5415 return (void*)(intptr_t)fclose(file);
5416}
5417
5418static int
5419maygvl_fclose(FILE *file, int keepgvl)
5420{
5421 if (keepgvl)
5422 return fclose(file);
5423
5424 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
5425}
5426
5427static void free_io_buffer(rb_io_buffer_t *buf);
5428static void clear_codeconv(rb_io_t *fptr);
5429
5430static void
5431fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5432 struct ccan_list_head *busy)
5433{
5434 VALUE error = Qnil;
5435 int fd = fptr->fd;
5436 FILE *stdio_file = fptr->stdio_file;
5437 int mode = fptr->mode;
5438
5439 if (fptr->writeconv) {
5440 if (!NIL_P(fptr->write_lock) && !noraise) {
5441 struct finish_writeconv_arg arg;
5442 arg.fptr = fptr;
5443 arg.noalloc = noraise;
5444 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5445 }
5446 else {
5447 error = finish_writeconv(fptr, noraise);
5448 }
5449 }
5450 if (fptr->wbuf.len) {
5451 if (noraise) {
5452 io_flush_buffer_sync(fptr);
5453 }
5454 else {
5455 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5456 error = INT2NUM(errno);
5457 }
5458 }
5459 }
5460
5461 int done = 0;
5462
5463 if (IS_PREP_STDIO(fptr) || fd <= 2) {
5464 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5465 done = 1;
5466 }
5467
5468 fptr->fd = -1;
5469 fptr->stdio_file = 0;
5471
5472 // Ensure waiting_fd users do not hit EBADF.
5473 if (busy) {
5474 // Wait for them to exit before we call close().
5475 do rb_thread_schedule(); while (!ccan_list_empty(busy));
5476 }
5477
5478 // Disable for now.
5479 // if (!done && fd >= 0) {
5480 // VALUE scheduler = rb_fiber_scheduler_current();
5481 // if (scheduler != Qnil) {
5482 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5483 // if (!UNDEF_P(result)) done = 1;
5484 // }
5485 // }
5486
5487 if (!done && stdio_file) {
5488 // stdio_file is deallocated anyway even if fclose failed.
5489 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5490 if (!noraise) {
5491 error = INT2NUM(errno);
5492 }
5493 }
5494
5495 done = 1;
5496 }
5497
5498 if (!done && fd >= 0) {
5499 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5500 // We assumes it is closed.
5501
5502 keepgvl |= !(mode & FMODE_WRITABLE);
5503 keepgvl |= noraise;
5504 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5505 if (!noraise) {
5506 error = INT2NUM(errno);
5507 }
5508 }
5509
5510 done = 1;
5511 }
5512
5513 if (!NIL_P(error) && !noraise) {
5514 if (RB_INTEGER_TYPE_P(error))
5515 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5516 else
5517 rb_exc_raise(error);
5518 }
5519}
5520
5521static void
5522fptr_finalize(rb_io_t *fptr, int noraise)
5523{
5524 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5525 free_io_buffer(&fptr->rbuf);
5526 free_io_buffer(&fptr->wbuf);
5527 clear_codeconv(fptr);
5528}
5529
5530static void
5531rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5532{
5533 if (fptr->finalize) {
5534 (*fptr->finalize)(fptr, noraise);
5535 }
5536 else {
5537 fptr_finalize(fptr, noraise);
5538 }
5539}
5540
5541static void
5542free_io_buffer(rb_io_buffer_t *buf)
5543{
5544 if (buf->ptr) {
5545 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5546 buf->ptr = NULL;
5547 }
5548}
5549
5550static void
5551clear_readconv(rb_io_t *fptr)
5552{
5553 if (fptr->readconv) {
5554 rb_econv_close(fptr->readconv);
5555 fptr->readconv = NULL;
5556 }
5557 free_io_buffer(&fptr->cbuf);
5558}
5559
5560static void
5561clear_writeconv(rb_io_t *fptr)
5562{
5563 if (fptr->writeconv) {
5565 fptr->writeconv = NULL;
5566 }
5567 fptr->writeconv_initialized = 0;
5568}
5569
5570static void
5571clear_codeconv(rb_io_t *fptr)
5572{
5573 clear_readconv(fptr);
5574 clear_writeconv(fptr);
5575}
5576
5577void
5578rb_io_fptr_finalize_internal(void *ptr)
5579{
5580 rb_io_t *fptr = ptr;
5581
5582 if (!ptr) return;
5583 fptr->pathv = Qnil;
5584 if (0 <= fptr->fd)
5585 rb_io_fptr_cleanup(fptr, TRUE);
5586 fptr->write_lock = Qnil;
5587 free_io_buffer(&fptr->rbuf);
5588 free_io_buffer(&fptr->wbuf);
5589 clear_codeconv(fptr);
5590 free(fptr);
5591}
5592
5593#undef rb_io_fptr_finalize
5594int
5595rb_io_fptr_finalize(rb_io_t *fptr)
5596{
5597 if (!fptr) {
5598 return 0;
5599 }
5600 else {
5601 rb_io_fptr_finalize_internal(fptr);
5602 return 1;
5603 }
5604}
5605#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5606
5607RUBY_FUNC_EXPORTED size_t
5608rb_io_memsize(const rb_io_t *fptr)
5609{
5610 size_t size = sizeof(rb_io_t);
5611 size += fptr->rbuf.capa;
5612 size += fptr->wbuf.capa;
5613 size += fptr->cbuf.capa;
5614 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5615 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5616 return size;
5617}
5618
5619#ifdef _WIN32
5620/* keep GVL while closing to prevent crash on Windows */
5621# define KEEPGVL TRUE
5622#else
5623# define KEEPGVL FALSE
5624#endif
5625
5626int rb_notify_fd_close(int fd, struct ccan_list_head *);
5627static rb_io_t *
5628io_close_fptr(VALUE io)
5629{
5630 rb_io_t *fptr;
5631 VALUE write_io;
5632 rb_io_t *write_fptr;
5633 struct ccan_list_head busy;
5634
5635 ccan_list_head_init(&busy);
5636 write_io = GetWriteIO(io);
5637 if (io != write_io) {
5638 write_fptr = RFILE(write_io)->fptr;
5639 if (write_fptr && 0 <= write_fptr->fd) {
5640 rb_io_fptr_cleanup(write_fptr, TRUE);
5641 }
5642 }
5643
5644 fptr = RFILE(io)->fptr;
5645 if (!fptr) return 0;
5646 if (fptr->fd < 0) return 0;
5647
5648 if (rb_notify_fd_close(fptr->fd, &busy)) {
5649 /* calls close(fptr->fd): */
5650 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5651 }
5652 rb_io_fptr_cleanup(fptr, FALSE);
5653 return fptr;
5654}
5655
5656static void
5657fptr_waitpid(rb_io_t *fptr, int nohang)
5658{
5659 int status;
5660 if (fptr->pid) {
5661 rb_last_status_clear();
5662 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5663 fptr->pid = 0;
5664 }
5665}
5666
5667VALUE
5669{
5670 rb_io_t *fptr = io_close_fptr(io);
5671 if (fptr) fptr_waitpid(fptr, 0);
5672 return Qnil;
5673}
5674
5675/*
5676 * call-seq:
5677 * close -> nil
5678 *
5679 * Closes the stream for both reading and writing
5680 * if open for either or both; returns +nil+.
5681 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5682 *
5683 * If the stream is open for writing, flushes any buffered writes
5684 * to the operating system before closing.
5685 *
5686 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5687 * (child exit status).
5688 *
5689 * Example:
5690 *
5691 * IO.popen('ruby', 'r+') do |pipe|
5692 * puts pipe.closed?
5693 * pipe.close
5694 * puts $?
5695 * puts pipe.closed?
5696 * end
5697 *
5698 * Output:
5699 *
5700 * false
5701 * pid 13760 exit 0
5702 * true
5703 *
5704 * Related: IO#close_read, IO#close_write, IO#closed?.
5705 */
5706
5707static VALUE
5708rb_io_close_m(VALUE io)
5709{
5710 rb_io_t *fptr = rb_io_get_fptr(io);
5711 if (fptr->fd < 0) {
5712 return Qnil;
5713 }
5714 rb_io_close(io);
5715 return Qnil;
5716}
5717
5718static VALUE
5719io_call_close(VALUE io)
5720{
5721 rb_check_funcall(io, rb_intern("close"), 0, 0);
5722 return io;
5723}
5724
5725static VALUE
5726ignore_closed_stream(VALUE io, VALUE exc)
5727{
5728 enum {mesg_len = sizeof(closed_stream)-1};
5729 VALUE mesg = rb_attr_get(exc, idMesg);
5730 if (!RB_TYPE_P(mesg, T_STRING) ||
5731 RSTRING_LEN(mesg) != mesg_len ||
5732 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5733 rb_exc_raise(exc);
5734 }
5735 return io;
5736}
5737
5738static VALUE
5739io_close(VALUE io)
5740{
5741 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5742 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5743 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5744 rb_eIOError, (VALUE)0);
5745 return io;
5746}
5747
5748/*
5749 * call-seq:
5750 * closed? -> true or false
5751 *
5752 * Returns +true+ if the stream is closed for both reading and writing,
5753 * +false+ otherwise.
5754 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5755 *
5756 * IO.popen('ruby', 'r+') do |pipe|
5757 * puts pipe.closed?
5758 * pipe.close_read
5759 * puts pipe.closed?
5760 * pipe.close_write
5761 * puts pipe.closed?
5762 * end
5763 *
5764 * Output:
5765 *
5766 * false
5767 * false
5768 * true
5769 *
5770 * Related: IO#close_read, IO#close_write, IO#close.
5771 */
5772
5773
5774static VALUE
5775rb_io_closed(VALUE io)
5776{
5777 rb_io_t *fptr;
5778 VALUE write_io;
5779 rb_io_t *write_fptr;
5780
5781 write_io = GetWriteIO(io);
5782 if (io != write_io) {
5783 write_fptr = RFILE(write_io)->fptr;
5784 if (write_fptr && 0 <= write_fptr->fd) {
5785 return Qfalse;
5786 }
5787 }
5788
5789 fptr = rb_io_get_fptr(io);
5790 return RBOOL(0 > fptr->fd);
5791}
5792
5793/*
5794 * call-seq:
5795 * close_read -> nil
5796 *
5797 * Closes the stream for reading if open for reading;
5798 * returns +nil+.
5799 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5800 *
5801 * If the stream was opened by IO.popen and is also closed for writing,
5802 * sets global variable <tt>$?</tt> (child exit status).
5803 *
5804 * Example:
5805 *
5806 * IO.popen('ruby', 'r+') do |pipe|
5807 * puts pipe.closed?
5808 * pipe.close_write
5809 * puts pipe.closed?
5810 * pipe.close_read
5811 * puts $?
5812 * puts pipe.closed?
5813 * end
5814 *
5815 * Output:
5816 *
5817 * false
5818 * false
5819 * pid 14748 exit 0
5820 * true
5821 *
5822 * Related: IO#close, IO#close_write, IO#closed?.
5823 */
5824
5825static VALUE
5826rb_io_close_read(VALUE io)
5827{
5828 rb_io_t *fptr;
5829 VALUE write_io;
5830
5831 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5832 if (fptr->fd < 0) return Qnil;
5833 if (is_socket(fptr->fd, fptr->pathv)) {
5834#ifndef SHUT_RD
5835# define SHUT_RD 0
5836#endif
5837 if (shutdown(fptr->fd, SHUT_RD) < 0)
5838 rb_sys_fail_path(fptr->pathv);
5839 fptr->mode &= ~FMODE_READABLE;
5840 if (!(fptr->mode & FMODE_WRITABLE))
5841 return rb_io_close(io);
5842 return Qnil;
5843 }
5844
5845 write_io = GetWriteIO(io);
5846 if (io != write_io) {
5847 rb_io_t *wfptr;
5848 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5849 wfptr->pid = fptr->pid;
5850 fptr->pid = 0;
5851 RFILE(io)->fptr = wfptr;
5852 /* bind to write_io temporarily to get rid of memory/fd leak */
5853 fptr->tied_io_for_writing = 0;
5854 RFILE(write_io)->fptr = fptr;
5855 rb_io_fptr_cleanup(fptr, FALSE);
5856 /* should not finalize fptr because another thread may be reading it */
5857 return Qnil;
5858 }
5859
5860 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5861 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5862 }
5863 return rb_io_close(io);
5864}
5865
5866/*
5867 * call-seq:
5868 * close_write -> nil
5869 *
5870 * Closes the stream for writing if open for writing;
5871 * returns +nil+.
5872 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5873 *
5874 * Flushes any buffered writes to the operating system before closing.
5875 *
5876 * If the stream was opened by IO.popen and is also closed for reading,
5877 * sets global variable <tt>$?</tt> (child exit status).
5878 *
5879 * IO.popen('ruby', 'r+') do |pipe|
5880 * puts pipe.closed?
5881 * pipe.close_read
5882 * puts pipe.closed?
5883 * pipe.close_write
5884 * puts $?
5885 * puts pipe.closed?
5886 * end
5887 *
5888 * Output:
5889 *
5890 * false
5891 * false
5892 * pid 15044 exit 0
5893 * true
5894 *
5895 * Related: IO#close, IO#close_read, IO#closed?.
5896 */
5897
5898static VALUE
5899rb_io_close_write(VALUE io)
5900{
5901 rb_io_t *fptr;
5902 VALUE write_io;
5903
5904 write_io = GetWriteIO(io);
5905 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5906 if (fptr->fd < 0) return Qnil;
5907 if (is_socket(fptr->fd, fptr->pathv)) {
5908#ifndef SHUT_WR
5909# define SHUT_WR 1
5910#endif
5911 if (shutdown(fptr->fd, SHUT_WR) < 0)
5912 rb_sys_fail_path(fptr->pathv);
5913 fptr->mode &= ~FMODE_WRITABLE;
5914 if (!(fptr->mode & FMODE_READABLE))
5915 return rb_io_close(write_io);
5916 return Qnil;
5917 }
5918
5919 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
5920 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
5921 }
5922
5923 if (io != write_io) {
5924 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5925 fptr->tied_io_for_writing = 0;
5926 }
5927 rb_io_close(write_io);
5928 return Qnil;
5929}
5930
5931/*
5932 * call-seq:
5933 * sysseek(offset, whence = IO::SEEK_SET) -> integer
5934 *
5935 * Behaves like IO#seek, except that it:
5936 *
5937 * - Uses low-level system functions.
5938 * - Returns the new position.
5939 *
5940 */
5941
5942static VALUE
5943rb_io_sysseek(int argc, VALUE *argv, VALUE io)
5944{
5945 VALUE offset, ptrname;
5946 int whence = SEEK_SET;
5947 rb_io_t *fptr;
5948 rb_off_t pos;
5949
5950 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
5951 whence = interpret_seek_whence(ptrname);
5952 }
5953 pos = NUM2OFFT(offset);
5954 GetOpenFile(io, fptr);
5955 if ((fptr->mode & FMODE_READABLE) &&
5956 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5957 rb_raise(rb_eIOError, "sysseek for buffered IO");
5958 }
5959 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
5960 rb_warn("sysseek for buffered IO");
5961 }
5962 errno = 0;
5963 pos = lseek(fptr->fd, pos, whence);
5964 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
5965
5966 return OFFT2NUM(pos);
5967}
5968
5969/*
5970 * call-seq:
5971 * syswrite(object) -> integer
5972 *
5973 * Writes the given +object+ to self, which must be opened for writing (see Modes);
5974 * returns the number bytes written.
5975 * If +object+ is not a string is converted via method to_s:
5976 *
5977 * f = File.new('t.tmp', 'w')
5978 * f.syswrite('foo') # => 3
5979 * f.syswrite(30) # => 2
5980 * f.syswrite(:foo) # => 3
5981 * f.close
5982 *
5983 * This methods should not be used with other stream-writer methods.
5984 *
5985 */
5986
5987static VALUE
5988rb_io_syswrite(VALUE io, VALUE str)
5989{
5990 VALUE tmp;
5991 rb_io_t *fptr;
5992 long n, len;
5993 const char *ptr;
5994
5995 if (!RB_TYPE_P(str, T_STRING))
5996 str = rb_obj_as_string(str);
5997
5998 io = GetWriteIO(io);
5999 GetOpenFile(io, fptr);
6001
6002 if (fptr->wbuf.len) {
6003 rb_warn("syswrite for buffered IO");
6004 }
6005
6006 tmp = rb_str_tmp_frozen_acquire(str);
6007 RSTRING_GETMEM(tmp, ptr, len);
6008 n = rb_io_write_memory(fptr, ptr, len);
6009 if (n < 0) rb_sys_fail_path(fptr->pathv);
6010 rb_str_tmp_frozen_release(str, tmp);
6011
6012 return LONG2FIX(n);
6013}
6014
6015/*
6016 * call-seq:
6017 * sysread(maxlen) -> string
6018 * sysread(maxlen, out_string) -> string
6019 *
6020 * Behaves like IO#readpartial, except that it uses low-level system functions.
6021 *
6022 * This method should not be used with other stream-reader methods.
6023 *
6024 */
6025
6026static VALUE
6027rb_io_sysread(int argc, VALUE *argv, VALUE io)
6028{
6029 VALUE len, str;
6030 rb_io_t *fptr;
6031 long n, ilen;
6032 struct io_internal_read_struct iis;
6033 int shrinkable;
6034
6035 rb_scan_args(argc, argv, "11", &len, &str);
6036 ilen = NUM2LONG(len);
6037
6038 shrinkable = io_setstrbuf(&str, ilen);
6039 if (ilen == 0) return str;
6040
6041 GetOpenFile(io, fptr);
6043
6044 if (READ_DATA_BUFFERED(fptr)) {
6045 rb_raise(rb_eIOError, "sysread for buffered IO");
6046 }
6047
6048 rb_io_check_closed(fptr);
6049
6050 io_setstrbuf(&str, ilen);
6051 iis.th = rb_thread_current();
6052 iis.fptr = fptr;
6053 iis.nonblock = 0;
6054 iis.fd = fptr->fd;
6055 iis.buf = RSTRING_PTR(str);
6056 iis.capa = ilen;
6057 iis.timeout = NULL;
6058 n = io_read_memory_locktmp(str, &iis);
6059
6060 if (n < 0) {
6061 rb_sys_fail_path(fptr->pathv);
6062 }
6063
6064 io_set_read_length(str, n, shrinkable);
6065
6066 if (n == 0 && ilen > 0) {
6067 rb_eof_error();
6068 }
6069
6070 return str;
6071}
6072
6073#if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
6074struct prdwr_internal_arg {
6075 int fd;
6076 void *buf;
6077 size_t count;
6078 rb_off_t offset;
6079};
6080#endif /* HAVE_PREAD || HAVE_PWRITE */
6081
6082#if defined(HAVE_PREAD)
6083static VALUE
6084internal_pread_func(void *arg)
6085{
6086 struct prdwr_internal_arg *p = arg;
6087 return (VALUE)pread(p->fd, p->buf, p->count, p->offset);
6088}
6089
6090static VALUE
6091pread_internal_call(VALUE arg)
6092{
6093 struct prdwr_internal_arg *p = (struct prdwr_internal_arg *)arg;
6094 return rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
6095}
6096
6097/*
6098 * call-seq:
6099 * pread(maxlen, offset) -> string
6100 * pread(maxlen, offset, out_string) -> string
6101 *
6102 * Behaves like IO#readpartial, except that it:
6103 *
6104 * - Reads at the given +offset+ (in bytes).
6105 * - Disregards, and does not modify, the stream's position
6106 * (see {Position}[rdoc-ref:IO@Position]).
6107 * - Bypasses any user space buffering in the stream.
6108 *
6109 * Because this method does not disturb the stream's state
6110 * (its position, in particular), +pread+ allows multiple threads and processes
6111 * to use the same \IO object for reading at various offsets.
6112 *
6113 * f = File.open('t.txt')
6114 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6115 * f.pos # => 52
6116 * # Read 12 bytes at offset 0.
6117 * f.pread(12, 0) # => "First line\n"
6118 * # Read 9 bytes at offset 8.
6119 * f.pread(9, 8) # => "ne\nSecon"
6120 * f.close
6121 *
6122 * Not available on some platforms.
6123 *
6124 */
6125static VALUE
6126rb_io_pread(int argc, VALUE *argv, VALUE io)
6127{
6128 VALUE len, offset, str;
6129 rb_io_t *fptr;
6130 ssize_t n;
6131 struct prdwr_internal_arg arg;
6132 int shrinkable;
6133
6134 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6135 arg.count = NUM2SIZET(len);
6136 arg.offset = NUM2OFFT(offset);
6137
6138 shrinkable = io_setstrbuf(&str, (long)arg.count);
6139 if (arg.count == 0) return str;
6140 arg.buf = RSTRING_PTR(str);
6141
6142 GetOpenFile(io, fptr);
6144
6145 arg.fd = fptr->fd;
6146 rb_io_check_closed(fptr);
6147
6148 rb_str_locktmp(str);
6149 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6150
6151 if (n < 0) {
6152 rb_sys_fail_path(fptr->pathv);
6153 }
6154 io_set_read_length(str, n, shrinkable);
6155 if (n == 0 && arg.count > 0) {
6156 rb_eof_error();
6157 }
6158
6159 return str;
6160}
6161#else
6162# define rb_io_pread rb_f_notimplement
6163#endif /* HAVE_PREAD */
6164
6165#if defined(HAVE_PWRITE)
6166static VALUE
6167internal_pwrite_func(void *ptr)
6168{
6169 struct prdwr_internal_arg *arg = ptr;
6170
6171 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6172}
6173
6174/*
6175 * call-seq:
6176 * pwrite(object, offset) -> integer
6177 *
6178 * Behaves like IO#write, except that it:
6179 *
6180 * - Writes at the given +offset+ (in bytes).
6181 * - Disregards, and does not modify, the stream's position
6182 * (see {Position}[rdoc-ref:IO@Position]).
6183 * - Bypasses any user space buffering in the stream.
6184 *
6185 * Because this method does not disturb the stream's state
6186 * (its position, in particular), +pwrite+ allows multiple threads and processes
6187 * to use the same \IO object for writing at various offsets.
6188 *
6189 * f = File.open('t.tmp', 'w+')
6190 * # Write 6 bytes at offset 3.
6191 * f.pwrite('ABCDEF', 3) # => 6
6192 * f.rewind
6193 * f.read # => "\u0000\u0000\u0000ABCDEF"
6194 * f.close
6195 *
6196 * Not available on some platforms.
6197 *
6198 */
6199static VALUE
6200rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6201{
6202 rb_io_t *fptr;
6203 ssize_t n;
6204 struct prdwr_internal_arg arg;
6205 VALUE tmp;
6206
6207 if (!RB_TYPE_P(str, T_STRING))
6208 str = rb_obj_as_string(str);
6209
6210 arg.offset = NUM2OFFT(offset);
6211
6212 io = GetWriteIO(io);
6213 GetOpenFile(io, fptr);
6215 arg.fd = fptr->fd;
6216
6217 tmp = rb_str_tmp_frozen_acquire(str);
6218 arg.buf = RSTRING_PTR(tmp);
6219 arg.count = (size_t)RSTRING_LEN(tmp);
6220
6221 n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
6222 if (n < 0) rb_sys_fail_path(fptr->pathv);
6223 rb_str_tmp_frozen_release(str, tmp);
6224
6225 return SSIZET2NUM(n);
6226}
6227#else
6228# define rb_io_pwrite rb_f_notimplement
6229#endif /* HAVE_PWRITE */
6230
6231VALUE
6233{
6234 rb_io_t *fptr;
6235
6236 GetOpenFile(io, fptr);
6237 if (fptr->readconv)
6239 if (fptr->writeconv)
6241 fptr->mode |= FMODE_BINMODE;
6242 fptr->mode &= ~FMODE_TEXTMODE;
6243 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6244#ifdef O_BINARY
6245 if (!fptr->readconv) {
6246 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6247 }
6248 else {
6249 setmode(fptr->fd, O_BINARY);
6250 }
6251#endif
6252 return io;
6253}
6254
6255static void
6256io_ascii8bit_binmode(rb_io_t *fptr)
6257{
6258 if (fptr->readconv) {
6259 rb_econv_close(fptr->readconv);
6260 fptr->readconv = NULL;
6261 }
6262 if (fptr->writeconv) {
6264 fptr->writeconv = NULL;
6265 }
6266 fptr->mode |= FMODE_BINMODE;
6267 fptr->mode &= ~FMODE_TEXTMODE;
6268 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6269
6270 fptr->encs.enc = rb_ascii8bit_encoding();
6271 fptr->encs.enc2 = NULL;
6272 fptr->encs.ecflags = 0;
6273 fptr->encs.ecopts = Qnil;
6274 clear_codeconv(fptr);
6275}
6276
6277VALUE
6279{
6280 rb_io_t *fptr;
6281
6282 GetOpenFile(io, fptr);
6283 io_ascii8bit_binmode(fptr);
6284
6285 return io;
6286}
6287
6288/*
6289 * call-seq:
6290 * binmode -> self
6291 *
6292 * Sets the stream's data mode as binary
6293 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6294 *
6295 * A stream's data mode may not be changed from binary to text.
6296 *
6297 */
6298
6299static VALUE
6300rb_io_binmode_m(VALUE io)
6301{
6302 VALUE write_io;
6303
6305
6306 write_io = GetWriteIO(io);
6307 if (write_io != io)
6308 rb_io_ascii8bit_binmode(write_io);
6309 return io;
6310}
6311
6312/*
6313 * call-seq:
6314 * binmode? -> true or false
6315 *
6316 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6317 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6318 *
6319 */
6320static VALUE
6321rb_io_binmode_p(VALUE io)
6322{
6323 rb_io_t *fptr;
6324 GetOpenFile(io, fptr);
6325 return RBOOL(fptr->mode & FMODE_BINMODE);
6326}
6327
6328static const char*
6329rb_io_fmode_modestr(int fmode)
6330{
6331 if (fmode & FMODE_APPEND) {
6332 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6333 return MODE_BTMODE("a+", "ab+", "at+");
6334 }
6335 return MODE_BTMODE("a", "ab", "at");
6336 }
6337 switch (fmode & FMODE_READWRITE) {
6338 default:
6339 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6340 case FMODE_READABLE:
6341 return MODE_BTMODE("r", "rb", "rt");
6342 case FMODE_WRITABLE:
6343 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6344 case FMODE_READWRITE:
6345 if (fmode & FMODE_CREATE) {
6346 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6347 }
6348 return MODE_BTMODE("r+", "rb+", "rt+");
6349 }
6350}
6351
6352static const char bom_prefix[] = "bom|";
6353static const char utf_prefix[] = "utf-";
6354enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6355enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6356
6357static int
6358io_encname_bom_p(const char *name, long len)
6359{
6360 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6361}
6362
6363int
6364rb_io_modestr_fmode(const char *modestr)
6365{
6366 int fmode = 0;
6367 const char *m = modestr, *p = NULL;
6368
6369 switch (*m++) {
6370 case 'r':
6371 fmode |= FMODE_READABLE;
6372 break;
6373 case 'w':
6375 break;
6376 case 'a':
6378 break;
6379 default:
6380 goto error;
6381 }
6382
6383 while (*m) {
6384 switch (*m++) {
6385 case 'b':
6386 fmode |= FMODE_BINMODE;
6387 break;
6388 case 't':
6389 fmode |= FMODE_TEXTMODE;
6390 break;
6391 case '+':
6392 fmode |= FMODE_READWRITE;
6393 break;
6394 case 'x':
6395 if (modestr[0] != 'w')
6396 goto error;
6397 fmode |= FMODE_EXCL;
6398 break;
6399 default:
6400 goto error;
6401 case ':':
6402 p = strchr(m, ':');
6403 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6404 fmode |= FMODE_SETENC_BY_BOM;
6405 goto finished;
6406 }
6407 }
6408
6409 finished:
6410 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6411 goto error;
6412
6413 return fmode;
6414
6415 error:
6416 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6418}
6419
6420int
6421rb_io_oflags_fmode(int oflags)
6422{
6423 int fmode = 0;
6424
6425 switch (oflags & O_ACCMODE) {
6426 case O_RDONLY:
6427 fmode = FMODE_READABLE;
6428 break;
6429 case O_WRONLY:
6430 fmode = FMODE_WRITABLE;
6431 break;
6432 case O_RDWR:
6433 fmode = FMODE_READWRITE;
6434 break;
6435 }
6436
6437 if (oflags & O_APPEND) {
6438 fmode |= FMODE_APPEND;
6439 }
6440 if (oflags & O_TRUNC) {
6441 fmode |= FMODE_TRUNC;
6442 }
6443 if (oflags & O_CREAT) {
6444 fmode |= FMODE_CREATE;
6445 }
6446 if (oflags & O_EXCL) {
6447 fmode |= FMODE_EXCL;
6448 }
6449#ifdef O_BINARY
6450 if (oflags & O_BINARY) {
6451 fmode |= FMODE_BINMODE;
6452 }
6453#endif
6454
6455 return fmode;
6456}
6457
6458static int
6459rb_io_fmode_oflags(int fmode)
6460{
6461 int oflags = 0;
6462
6463 switch (fmode & FMODE_READWRITE) {
6464 case FMODE_READABLE:
6465 oflags |= O_RDONLY;
6466 break;
6467 case FMODE_WRITABLE:
6468 oflags |= O_WRONLY;
6469 break;
6470 case FMODE_READWRITE:
6471 oflags |= O_RDWR;
6472 break;
6473 }
6474
6475 if (fmode & FMODE_APPEND) {
6476 oflags |= O_APPEND;
6477 }
6478 if (fmode & FMODE_TRUNC) {
6479 oflags |= O_TRUNC;
6480 }
6481 if (fmode & FMODE_CREATE) {
6482 oflags |= O_CREAT;
6483 }
6484 if (fmode & FMODE_EXCL) {
6485 oflags |= O_EXCL;
6486 }
6487#ifdef O_BINARY
6488 if (fmode & FMODE_BINMODE) {
6489 oflags |= O_BINARY;
6490 }
6491#endif
6492
6493 return oflags;
6494}
6495
6496int
6497rb_io_modestr_oflags(const char *modestr)
6498{
6499 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6500}
6501
6502static const char*
6503rb_io_oflags_modestr(int oflags)
6504{
6505#ifdef O_BINARY
6506# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6507#else
6508# define MODE_BINARY(a,b) (a)
6509#endif
6510 int accmode;
6511 if (oflags & O_EXCL) {
6512 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6513 }
6514 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6515 if (oflags & O_APPEND) {
6516 if (accmode == O_WRONLY) {
6517 return MODE_BINARY("a", "ab");
6518 }
6519 if (accmode == O_RDWR) {
6520 return MODE_BINARY("a+", "ab+");
6521 }
6522 }
6523 switch (accmode) {
6524 default:
6525 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6526 case O_RDONLY:
6527 return MODE_BINARY("r", "rb");
6528 case O_WRONLY:
6529 return MODE_BINARY("w", "wb");
6530 case O_RDWR:
6531 if (oflags & O_TRUNC) {
6532 return MODE_BINARY("w+", "wb+");
6533 }
6534 return MODE_BINARY("r+", "rb+");
6535 }
6536}
6537
6538/*
6539 * Convert external/internal encodings to enc/enc2
6540 * NULL => use default encoding
6541 * Qnil => no encoding specified (internal only)
6542 */
6543static void
6544rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6545{
6546 int default_ext = 0;
6547
6548 if (ext == NULL) {
6549 ext = rb_default_external_encoding();
6550 default_ext = 1;
6551 }
6552 if (rb_is_ascii8bit_enc(ext)) {
6553 /* If external is ASCII-8BIT, no transcoding */
6554 intern = NULL;
6555 }
6556 else if (intern == NULL) {
6557 intern = rb_default_internal_encoding();
6558 }
6559 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6560 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6561 /* No internal encoding => use external + no transcoding */
6562 *enc = (default_ext && intern != ext) ? NULL : ext;
6563 *enc2 = NULL;
6564 }
6565 else {
6566 *enc = intern;
6567 *enc2 = ext;
6568 }
6569}
6570
6571static void
6572unsupported_encoding(const char *name, rb_encoding *enc)
6573{
6574 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6575}
6576
6577static void
6578parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6579 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6580{
6581 const char *p;
6582 char encname[ENCODING_MAXNAMELEN+1];
6583 int idx, idx2;
6584 int fmode = fmode_p ? *fmode_p : 0;
6585 rb_encoding *ext_enc, *int_enc;
6586 long len;
6587
6588 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6589
6590 p = strrchr(estr, ':');
6591 len = p ? (p++ - estr) : (long)strlen(estr);
6592 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6593 estr += bom_prefix_len;
6594 len -= bom_prefix_len;
6595 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6596 fmode |= FMODE_SETENC_BY_BOM;
6597 }
6598 else {
6599 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6600 fmode &= ~FMODE_SETENC_BY_BOM;
6601 }
6602 }
6603 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6604 idx = -1;
6605 }
6606 else {
6607 if (p) {
6608 memcpy(encname, estr, len);
6609 encname[len] = '\0';
6610 estr = encname;
6611 }
6612 idx = rb_enc_find_index(estr);
6613 }
6614 if (fmode_p) *fmode_p = fmode;
6615
6616 if (idx >= 0)
6617 ext_enc = rb_enc_from_index(idx);
6618 else {
6619 if (idx != -2)
6620 unsupported_encoding(estr, estr_enc);
6621 ext_enc = NULL;
6622 }
6623
6624 int_enc = NULL;
6625 if (p) {
6626 if (*p == '-' && *(p+1) == '\0') {
6627 /* Special case - "-" => no transcoding */
6628 int_enc = (rb_encoding *)Qnil;
6629 }
6630 else {
6631 idx2 = rb_enc_find_index(p);
6632 if (idx2 < 0)
6633 unsupported_encoding(p, estr_enc);
6634 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6635 int_enc = (rb_encoding *)Qnil;
6636 }
6637 else
6638 int_enc = rb_enc_from_index(idx2);
6639 }
6640 }
6641
6642 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6643}
6644
6645int
6646rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6647{
6648 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6649 int extracted = 0;
6650 rb_encoding *extencoding = NULL;
6651 rb_encoding *intencoding = NULL;
6652
6653 if (!NIL_P(opt)) {
6654 VALUE v;
6655 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6656 if (v != Qnil) encoding = v;
6657 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6658 if (v != Qnil) extenc = v;
6659 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6660 if (!UNDEF_P(v)) intenc = v;
6661 }
6662 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6663 if (!NIL_P(ruby_verbose)) {
6664 int idx = rb_to_encoding_index(encoding);
6665 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6666 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6667 encoding, UNDEF_P(extenc) ? "internal" : "external");
6668 }
6669 encoding = Qnil;
6670 }
6671 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6672 extencoding = rb_to_encoding(extenc);
6673 }
6674 if (!UNDEF_P(intenc)) {
6675 if (NIL_P(intenc)) {
6676 /* internal_encoding: nil => no transcoding */
6677 intencoding = (rb_encoding *)Qnil;
6678 }
6679 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6680 char *p = StringValueCStr(tmp);
6681
6682 if (*p == '-' && *(p+1) == '\0') {
6683 /* Special case - "-" => no transcoding */
6684 intencoding = (rb_encoding *)Qnil;
6685 }
6686 else {
6687 intencoding = rb_to_encoding(intenc);
6688 }
6689 }
6690 else {
6691 intencoding = rb_to_encoding(intenc);
6692 }
6693 if (extencoding == intencoding) {
6694 intencoding = (rb_encoding *)Qnil;
6695 }
6696 }
6697 if (!NIL_P(encoding)) {
6698 extracted = 1;
6699 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6700 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6701 enc_p, enc2_p, fmode_p);
6702 }
6703 else {
6704 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6705 }
6706 }
6707 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6708 extracted = 1;
6709 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6710 }
6711 return extracted;
6712}
6713
6714typedef struct rb_io_enc_t convconfig_t;
6715
6716static void
6717validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6718{
6719 int fmode = *fmode_p;
6720
6721 if ((fmode & FMODE_READABLE) &&
6722 !enc2 &&
6723 !(fmode & FMODE_BINMODE) &&
6724 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6725 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6726
6727 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6728 rb_raise(rb_eArgError, "newline decorator with binary mode");
6729 }
6730 if (!(fmode & FMODE_BINMODE) &&
6731 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6732 fmode |= FMODE_TEXTMODE;
6733 *fmode_p = fmode;
6734 }
6735#if !DEFAULT_TEXTMODE
6736 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6737 fmode &= ~FMODE_TEXTMODE;
6738 *fmode_p = fmode;
6739 }
6740#endif
6741}
6742
6743static void
6744extract_binmode(VALUE opthash, int *fmode)
6745{
6746 if (!NIL_P(opthash)) {
6747 VALUE v;
6748 v = rb_hash_aref(opthash, sym_textmode);
6749 if (!NIL_P(v)) {
6750 if (*fmode & FMODE_TEXTMODE)
6751 rb_raise(rb_eArgError, "textmode specified twice");
6752 if (*fmode & FMODE_BINMODE)
6753 rb_raise(rb_eArgError, "both textmode and binmode specified");
6754 if (RTEST(v))
6755 *fmode |= FMODE_TEXTMODE;
6756 }
6757 v = rb_hash_aref(opthash, sym_binmode);
6758 if (!NIL_P(v)) {
6759 if (*fmode & FMODE_BINMODE)
6760 rb_raise(rb_eArgError, "binmode specified twice");
6761 if (*fmode & FMODE_TEXTMODE)
6762 rb_raise(rb_eArgError, "both textmode and binmode specified");
6763 if (RTEST(v))
6764 *fmode |= FMODE_BINMODE;
6765 }
6766
6767 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6768 rb_raise(rb_eArgError, "both textmode and binmode specified");
6769 }
6770}
6771
6772void
6773rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6774 int *oflags_p, int *fmode_p, convconfig_t *convconfig_p)
6775{
6776 VALUE vmode;
6777 int oflags, fmode;
6778 rb_encoding *enc, *enc2;
6779 int ecflags;
6780 VALUE ecopts;
6781 int has_enc = 0, has_vmode = 0;
6782 VALUE intmode;
6783
6784 vmode = *vmode_p;
6785
6786 /* Set to defaults */
6787 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6788
6789 vmode_handle:
6790 if (NIL_P(vmode)) {
6791 fmode = FMODE_READABLE;
6792 oflags = O_RDONLY;
6793 }
6794 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6795 vmode = intmode;
6796 oflags = NUM2INT(intmode);
6797 fmode = rb_io_oflags_fmode(oflags);
6798 }
6799 else {
6800 const char *p;
6801
6802 SafeStringValue(vmode);
6803 p = StringValueCStr(vmode);
6804 fmode = rb_io_modestr_fmode(p);
6805 oflags = rb_io_fmode_oflags(fmode);
6806 p = strchr(p, ':');
6807 if (p) {
6808 has_enc = 1;
6809 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6810 }
6811 else {
6812 rb_encoding *e;
6813
6814 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6815 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6816 }
6817 }
6818
6819 if (NIL_P(opthash)) {
6820 ecflags = (fmode & FMODE_READABLE) ?
6823#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6824 ecflags |= (fmode & FMODE_WRITABLE) ?
6825 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6826 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6827#endif
6828 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6829 ecopts = Qnil;
6830 if (fmode & FMODE_BINMODE) {
6831#ifdef O_BINARY
6832 oflags |= O_BINARY;
6833#endif
6834 if (!has_enc)
6835 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6836 }
6837#if DEFAULT_TEXTMODE
6838 else if (NIL_P(vmode)) {
6839 fmode |= DEFAULT_TEXTMODE;
6840 }
6841#endif
6842 }
6843 else {
6844 VALUE v;
6845 if (!has_vmode) {
6846 v = rb_hash_aref(opthash, sym_mode);
6847 if (!NIL_P(v)) {
6848 if (!NIL_P(vmode)) {
6849 rb_raise(rb_eArgError, "mode specified twice");
6850 }
6851 has_vmode = 1;
6852 vmode = v;
6853 goto vmode_handle;
6854 }
6855 }
6856 v = rb_hash_aref(opthash, sym_flags);
6857 if (!NIL_P(v)) {
6858 v = rb_to_int(v);
6859 oflags |= NUM2INT(v);
6860 vmode = INT2NUM(oflags);
6861 fmode = rb_io_oflags_fmode(oflags);
6862 }
6863 extract_binmode(opthash, &fmode);
6864 if (fmode & FMODE_BINMODE) {
6865#ifdef O_BINARY
6866 oflags |= O_BINARY;
6867#endif
6868 if (!has_enc)
6869 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6870 }
6871#if DEFAULT_TEXTMODE
6872 else if (NIL_P(vmode)) {
6873 fmode |= DEFAULT_TEXTMODE;
6874 }
6875#endif
6876 v = rb_hash_aref(opthash, sym_perm);
6877 if (!NIL_P(v)) {
6878 if (vperm_p) {
6879 if (!NIL_P(*vperm_p)) {
6880 rb_raise(rb_eArgError, "perm specified twice");
6881 }
6882 *vperm_p = v;
6883 }
6884 else {
6885 /* perm no use, just ignore */
6886 }
6887 }
6888 ecflags = (fmode & FMODE_READABLE) ?
6891#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6892 ecflags |= (fmode & FMODE_WRITABLE) ?
6893 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6894 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6895#endif
6896
6897 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6898 if (has_enc) {
6899 rb_raise(rb_eArgError, "encoding specified twice");
6900 }
6901 }
6902 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6904 }
6905
6906 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6907
6908 *vmode_p = vmode;
6909
6910 *oflags_p = oflags;
6911 *fmode_p = fmode;
6912 convconfig_p->enc = enc;
6913 convconfig_p->enc2 = enc2;
6914 convconfig_p->ecflags = ecflags;
6915 convconfig_p->ecopts = ecopts;
6916}
6917
6919 VALUE fname;
6920 int oflags;
6921 mode_t perm;
6922};
6923
6924static void *
6925sysopen_func(void *ptr)
6926{
6927 const struct sysopen_struct *data = ptr;
6928 const char *fname = RSTRING_PTR(data->fname);
6929 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
6930}
6931
6932static inline int
6933rb_sysopen_internal(struct sysopen_struct *data)
6934{
6935 int fd;
6936 fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
6937 if (0 <= fd)
6938 rb_update_max_fd(fd);
6939 return fd;
6940}
6941
6942static int
6943rb_sysopen(VALUE fname, int oflags, mode_t perm)
6944{
6945 int fd;
6946 struct sysopen_struct data;
6947
6948 data.fname = rb_str_encode_ospath(fname);
6949 StringValueCStr(data.fname);
6950 data.oflags = oflags;
6951 data.perm = perm;
6952
6953 fd = rb_sysopen_internal(&data);
6954 if (fd < 0) {
6955 int e = errno;
6956 if (rb_gc_for_fd(e)) {
6957 fd = rb_sysopen_internal(&data);
6958 }
6959 if (fd < 0) {
6960 rb_syserr_fail_path(e, fname);
6961 }
6962 }
6963 return fd;
6964}
6965
6966FILE *
6967rb_fdopen(int fd, const char *modestr)
6968{
6969 FILE *file;
6970
6971#if defined(__sun)
6972 errno = 0;
6973#endif
6974 file = fdopen(fd, modestr);
6975 if (!file) {
6976 int e = errno;
6977#if defined(__sun)
6978 if (e == 0) {
6979 rb_gc();
6980 errno = 0;
6981 file = fdopen(fd, modestr);
6982 }
6983 else
6984#endif
6985 if (rb_gc_for_fd(e)) {
6986 file = fdopen(fd, modestr);
6987 }
6988 if (!file) {
6989#ifdef _WIN32
6990 if (e == 0) e = EINVAL;
6991#elif defined(__sun)
6992 if (e == 0) e = EMFILE;
6993#endif
6994 rb_syserr_fail(e, 0);
6995 }
6996 }
6997
6998 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
6999#ifdef USE_SETVBUF
7000 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7001 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7002#endif
7003 return file;
7004}
7005
7006static int
7007io_check_tty(rb_io_t *fptr)
7008{
7009 int t = isatty(fptr->fd);
7010 if (t)
7011 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7012 return t;
7013}
7014
7015static VALUE rb_io_internal_encoding(VALUE);
7016static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7017
7018static int
7019io_strip_bom(VALUE io)
7020{
7021 VALUE b1, b2, b3, b4;
7022 rb_io_t *fptr;
7023
7024 GetOpenFile(io, fptr);
7025 if (!(fptr->mode & FMODE_READABLE)) return 0;
7026 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7027 switch (b1) {
7028 case INT2FIX(0xEF):
7029 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7030 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7031 if (b3 == INT2FIX(0xBF)) {
7032 return rb_utf8_encindex();
7033 }
7034 rb_io_ungetbyte(io, b3);
7035 }
7036 rb_io_ungetbyte(io, b2);
7037 break;
7038
7039 case INT2FIX(0xFE):
7040 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7041 if (b2 == INT2FIX(0xFF)) {
7042 return ENCINDEX_UTF_16BE;
7043 }
7044 rb_io_ungetbyte(io, b2);
7045 break;
7046
7047 case INT2FIX(0xFF):
7048 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7049 if (b2 == INT2FIX(0xFE)) {
7050 b3 = rb_io_getbyte(io);
7051 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7052 if (b4 == INT2FIX(0)) {
7053 return ENCINDEX_UTF_32LE;
7054 }
7055 rb_io_ungetbyte(io, b4);
7056 }
7057 rb_io_ungetbyte(io, b3);
7058 return ENCINDEX_UTF_16LE;
7059 }
7060 rb_io_ungetbyte(io, b2);
7061 break;
7062
7063 case INT2FIX(0):
7064 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7065 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7066 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7067 if (b4 == INT2FIX(0xFF)) {
7068 return ENCINDEX_UTF_32BE;
7069 }
7070 rb_io_ungetbyte(io, b4);
7071 }
7072 rb_io_ungetbyte(io, b3);
7073 }
7074 rb_io_ungetbyte(io, b2);
7075 break;
7076 }
7077 rb_io_ungetbyte(io, b1);
7078 return 0;
7079}
7080
7081static rb_encoding *
7082io_set_encoding_by_bom(VALUE io)
7083{
7084 int idx = io_strip_bom(io);
7085 rb_io_t *fptr;
7086 rb_encoding *extenc = NULL;
7087
7088 GetOpenFile(io, fptr);
7089 if (idx) {
7090 extenc = rb_enc_from_index(idx);
7091 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7092 rb_io_internal_encoding(io), Qnil);
7093 }
7094 else {
7095 fptr->encs.enc2 = NULL;
7096 }
7097 return extenc;
7098}
7099
7100static VALUE
7101rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7102 const convconfig_t *convconfig, mode_t perm)
7103{
7104 VALUE pathv;
7105 rb_io_t *fptr;
7106 convconfig_t cc;
7107 if (!convconfig) {
7108 /* Set to default encodings */
7109 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7110 cc.ecflags = 0;
7111 cc.ecopts = Qnil;
7112 convconfig = &cc;
7113 }
7114 validate_enc_binmode(&fmode, convconfig->ecflags,
7115 convconfig->enc, convconfig->enc2);
7116
7117 MakeOpenFile(io, fptr);
7118 fptr->mode = fmode;
7119 fptr->encs = *convconfig;
7120 pathv = rb_str_new_frozen(filename);
7121#ifdef O_TMPFILE
7122 if (!(oflags & O_TMPFILE)) {
7123 fptr->pathv = pathv;
7124 }
7125#else
7126 fptr->pathv = pathv;
7127#endif
7128 fptr->fd = rb_sysopen(pathv, oflags, perm);
7129 io_check_tty(fptr);
7130 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7131
7132 return io;
7133}
7134
7135static VALUE
7136rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7137{
7138 int fmode = rb_io_modestr_fmode(modestr);
7139 const char *p = strchr(modestr, ':');
7140 convconfig_t convconfig;
7141
7142 if (p) {
7143 parse_mode_enc(p+1, rb_usascii_encoding(),
7144 &convconfig.enc, &convconfig.enc2, &fmode);
7145 convconfig.ecflags = 0;
7146 convconfig.ecopts = Qnil;
7147 }
7148 else {
7149 rb_encoding *e;
7150 /* Set to default encodings */
7151
7152 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7153 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7154 convconfig.ecflags = 0;
7155 convconfig.ecopts = Qnil;
7156 }
7157
7158 return rb_file_open_generic(io, filename,
7159 rb_io_fmode_oflags(fmode),
7160 fmode,
7161 &convconfig,
7162 0666);
7163}
7164
7165VALUE
7166rb_file_open_str(VALUE fname, const char *modestr)
7167{
7168 FilePathValue(fname);
7169 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7170}
7171
7172VALUE
7173rb_file_open(const char *fname, const char *modestr)
7174{
7175 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7176}
7177
7178#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7179static struct pipe_list {
7180 rb_io_t *fptr;
7181 struct pipe_list *next;
7182} *pipe_list;
7183
7184static void
7185pipe_add_fptr(rb_io_t *fptr)
7186{
7187 struct pipe_list *list;
7188
7189 list = ALLOC(struct pipe_list);
7190 list->fptr = fptr;
7191 list->next = pipe_list;
7192 pipe_list = list;
7193}
7194
7195static void
7196pipe_del_fptr(rb_io_t *fptr)
7197{
7198 struct pipe_list **prev = &pipe_list;
7199 struct pipe_list *tmp;
7200
7201 while ((tmp = *prev) != 0) {
7202 if (tmp->fptr == fptr) {
7203 *prev = tmp->next;
7204 free(tmp);
7205 return;
7206 }
7207 prev = &tmp->next;
7208 }
7209}
7210
7211#if defined (_WIN32) || defined(__CYGWIN__)
7212static void
7213pipe_atexit(void)
7214{
7215 struct pipe_list *list = pipe_list;
7216 struct pipe_list *tmp;
7217
7218 while (list) {
7219 tmp = list->next;
7220 rb_io_fptr_finalize(list->fptr);
7221 list = tmp;
7222 }
7223}
7224#endif
7225
7226static void
7227pipe_finalize(rb_io_t *fptr, int noraise)
7228{
7229#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7230 int status = 0;
7231 if (fptr->stdio_file) {
7232 status = pclose(fptr->stdio_file);
7233 }
7234 fptr->fd = -1;
7235 fptr->stdio_file = 0;
7236 rb_last_status_set(status, fptr->pid);
7237#else
7238 fptr_finalize(fptr, noraise);
7239#endif
7240 pipe_del_fptr(fptr);
7241}
7242#endif
7243
7244static void
7245fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7246{
7247#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7248 void (*const old_finalize)(struct rb_io_t*,int) = fptr->finalize;
7249
7250 if (old_finalize == orig->finalize) return;
7251#endif
7252
7253 fptr->finalize = orig->finalize;
7254
7255#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7256 if (old_finalize != pipe_finalize) {
7257 struct pipe_list *list;
7258 for (list = pipe_list; list; list = list->next) {
7259 if (list->fptr == fptr) break;
7260 }
7261 if (!list) pipe_add_fptr(fptr);
7262 }
7263 else {
7264 pipe_del_fptr(fptr);
7265 }
7266#endif
7267}
7268
7269void
7271{
7273 fptr->mode |= FMODE_SYNC;
7274}
7275
7276void
7277rb_io_unbuffered(rb_io_t *fptr)
7278{
7279 rb_io_synchronized(fptr);
7280}
7281
7282int
7283rb_pipe(int *pipes)
7284{
7285 int ret;
7286 ret = rb_cloexec_pipe(pipes);
7287 if (ret < 0) {
7288 if (rb_gc_for_fd(errno)) {
7289 ret = rb_cloexec_pipe(pipes);
7290 }
7291 }
7292 if (ret == 0) {
7293 rb_update_max_fd(pipes[0]);
7294 rb_update_max_fd(pipes[1]);
7295 }
7296 return ret;
7297}
7298
7299#ifdef _WIN32
7300#define HAVE_SPAWNV 1
7301#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7302#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7303#endif
7304
7305#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7306struct popen_arg {
7307 VALUE execarg_obj;
7308 struct rb_execarg *eargp;
7309 int modef;
7310 int pair[2];
7311 int write_pair[2];
7312};
7313#endif
7314
7315#ifdef HAVE_WORKING_FORK
7316# ifndef __EMSCRIPTEN__
7317static void
7318popen_redirect(struct popen_arg *p)
7319{
7320 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7321 close(p->write_pair[1]);
7322 if (p->write_pair[0] != 0) {
7323 dup2(p->write_pair[0], 0);
7324 close(p->write_pair[0]);
7325 }
7326 close(p->pair[0]);
7327 if (p->pair[1] != 1) {
7328 dup2(p->pair[1], 1);
7329 close(p->pair[1]);
7330 }
7331 }
7332 else if (p->modef & FMODE_READABLE) {
7333 close(p->pair[0]);
7334 if (p->pair[1] != 1) {
7335 dup2(p->pair[1], 1);
7336 close(p->pair[1]);
7337 }
7338 }
7339 else {
7340 close(p->pair[1]);
7341 if (p->pair[0] != 0) {
7342 dup2(p->pair[0], 0);
7343 close(p->pair[0]);
7344 }
7345 }
7346}
7347# endif
7348
7349#if defined(__linux__)
7350/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7351 * Since /proc may not be available, linux_get_maxfd is just a hint.
7352 * This function, linux_get_maxfd, must be async-signal-safe.
7353 * I.e. opendir() is not usable.
7354 *
7355 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7356 * However they are easy to re-implement in async-signal-safe manner.
7357 * (Also note that there is missing/memcmp.c.)
7358 */
7359static int
7360linux_get_maxfd(void)
7361{
7362 int fd;
7363 char buf[4096], *p, *np, *e;
7364 ssize_t ss;
7365 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7366 if (fd < 0) return fd;
7367 ss = read(fd, buf, sizeof(buf));
7368 if (ss < 0) goto err;
7369 p = buf;
7370 e = buf + ss;
7371 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7372 (np = memchr(p, '\n', e-p)) != NULL) {
7373 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7374 int fdsize;
7375 p += sizeof("FDSize:")-1;
7376 *np = '\0';
7377 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7378 close(fd);
7379 return fdsize;
7380 }
7381 p = np+1;
7382 }
7383 /* fall through */
7384
7385 err:
7386 close(fd);
7387 return (int)ss;
7388}
7389#endif
7390
7391/* This function should be async-signal-safe. */
7392void
7393rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7394{
7395#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7396 int fd, ret;
7397 int max = (int)max_file_descriptor;
7398# ifdef F_MAXFD
7399 /* F_MAXFD is available since NetBSD 2.0. */
7400 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7401 if (ret != -1)
7402 maxhint = max = ret;
7403# elif defined(__linux__)
7404 ret = linux_get_maxfd();
7405 if (maxhint < ret)
7406 maxhint = ret;
7407 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7408# endif
7409 if (max < maxhint)
7410 max = maxhint;
7411 for (fd = lowfd; fd <= max; fd++) {
7412 if (!NIL_P(noclose_fds) &&
7413 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7414 continue;
7415 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7416 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7417 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7418 }
7419# define CONTIGUOUS_CLOSED_FDS 20
7420 if (ret != -1) {
7421 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7422 max = fd + CONTIGUOUS_CLOSED_FDS;
7423 }
7424 }
7425#endif
7426}
7427
7428# ifndef __EMSCRIPTEN__
7429static int
7430popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7431{
7432 struct popen_arg *p = (struct popen_arg*)pp;
7433
7434 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7435}
7436# endif
7437#endif
7438
7439#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7440static VALUE
7441rb_execarg_fixup_v(VALUE execarg_obj)
7442{
7443 rb_execarg_parent_start(execarg_obj);
7444 return Qnil;
7445}
7446#else
7447char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7448#endif
7449
7450#ifndef __EMSCRIPTEN__
7451static VALUE
7452pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7453 const convconfig_t *convconfig)
7454{
7455 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7456 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7457 rb_pid_t pid = 0;
7458 rb_io_t *fptr;
7459 VALUE port;
7460 rb_io_t *write_fptr;
7461 VALUE write_port;
7462#if defined(HAVE_WORKING_FORK)
7463 int status;
7464 char errmsg[80] = { '\0' };
7465#endif
7466#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7467 int state;
7468 struct popen_arg arg;
7469#endif
7470 int e = 0;
7471#if defined(HAVE_SPAWNV)
7472# if defined(HAVE_SPAWNVE)
7473# define DO_SPAWN(cmd, args, envp) ((args) ? \
7474 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7475 spawne(P_NOWAIT, (cmd), (envp)))
7476# else
7477# define DO_SPAWN(cmd, args, envp) ((args) ? \
7478 spawnv(P_NOWAIT, (cmd), (args)) : \
7479 spawn(P_NOWAIT, (cmd)))
7480# endif
7481# if !defined(HAVE_WORKING_FORK)
7482 char **args = NULL;
7483# if defined(HAVE_SPAWNVE)
7484 char **envp = NULL;
7485# endif
7486# endif
7487#endif
7488#if !defined(HAVE_WORKING_FORK)
7489 struct rb_execarg sarg, *sargp = &sarg;
7490#endif
7491 FILE *fp = 0;
7492 int fd = -1;
7493 int write_fd = -1;
7494#if !defined(HAVE_WORKING_FORK)
7495 const char *cmd = 0;
7496
7497 if (prog)
7498 cmd = StringValueCStr(prog);
7499#endif
7500
7501#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7502 arg.execarg_obj = execarg_obj;
7503 arg.eargp = eargp;
7504 arg.modef = fmode;
7505 arg.pair[0] = arg.pair[1] = -1;
7506 arg.write_pair[0] = arg.write_pair[1] = -1;
7507# if !defined(HAVE_WORKING_FORK)
7508 if (eargp && !eargp->use_shell) {
7509 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7510 }
7511# endif
7512 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7514 if (rb_pipe(arg.write_pair) < 0)
7515 rb_sys_fail_str(prog);
7516 if (rb_pipe(arg.pair) < 0) {
7517 e = errno;
7518 close(arg.write_pair[0]);
7519 close(arg.write_pair[1]);
7520 rb_syserr_fail_str(e, prog);
7521 }
7522 if (eargp) {
7523 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7524 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7525 }
7526 break;
7527 case FMODE_READABLE:
7528 if (rb_pipe(arg.pair) < 0)
7529 rb_sys_fail_str(prog);
7530 if (eargp)
7531 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7532 break;
7533 case FMODE_WRITABLE:
7534 if (rb_pipe(arg.pair) < 0)
7535 rb_sys_fail_str(prog);
7536 if (eargp)
7537 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7538 break;
7539 default:
7540 rb_sys_fail_str(prog);
7541 }
7542 if (!NIL_P(execarg_obj)) {
7543 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7544 if (state) {
7545 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7546 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7547 if (0 <= arg.pair[0]) close(arg.pair[0]);
7548 if (0 <= arg.pair[1]) close(arg.pair[1]);
7549 rb_execarg_parent_end(execarg_obj);
7550 rb_jump_tag(state);
7551 }
7552
7553# if defined(HAVE_WORKING_FORK)
7554 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7555# else
7556 rb_execarg_run_options(eargp, sargp, NULL, 0);
7557# if defined(HAVE_SPAWNVE)
7558 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7559# endif
7560 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7561 /* exec failed */
7562 switch (e = errno) {
7563 case EAGAIN:
7564# if EWOULDBLOCK != EAGAIN
7565 case EWOULDBLOCK:
7566# endif
7567 rb_thread_sleep(1);
7568 continue;
7569 }
7570 break;
7571 }
7572 if (eargp)
7573 rb_execarg_run_options(sargp, NULL, NULL, 0);
7574# endif
7575 rb_execarg_parent_end(execarg_obj);
7576 }
7577 else {
7578# if defined(HAVE_WORKING_FORK)
7579 pid = rb_call_proc__fork();
7580 if (pid == 0) { /* child */
7581 popen_redirect(&arg);
7582 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7583 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7584 return Qnil;
7585 }
7586# else
7588# endif
7589 }
7590
7591 /* parent */
7592 if (pid < 0) {
7593# if defined(HAVE_WORKING_FORK)
7594 e = errno;
7595# endif
7596 close(arg.pair[0]);
7597 close(arg.pair[1]);
7599 close(arg.write_pair[0]);
7600 close(arg.write_pair[1]);
7601 }
7602# if defined(HAVE_WORKING_FORK)
7603 if (errmsg[0])
7604 rb_syserr_fail(e, errmsg);
7605# endif
7606 rb_syserr_fail_str(e, prog);
7607 }
7608 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7609 close(arg.pair[1]);
7610 fd = arg.pair[0];
7611 close(arg.write_pair[0]);
7612 write_fd = arg.write_pair[1];
7613 }
7614 else if (fmode & FMODE_READABLE) {
7615 close(arg.pair[1]);
7616 fd = arg.pair[0];
7617 }
7618 else {
7619 close(arg.pair[0]);
7620 fd = arg.pair[1];
7621 }
7622#else
7623 cmd = rb_execarg_commandline(eargp, &prog);
7624 if (!NIL_P(execarg_obj)) {
7625 rb_execarg_parent_start(execarg_obj);
7626 rb_execarg_run_options(eargp, sargp, NULL, 0);
7627 }
7628 fp = popen(cmd, modestr);
7629 e = errno;
7630 if (eargp) {
7631 rb_execarg_parent_end(execarg_obj);
7632 rb_execarg_run_options(sargp, NULL, NULL, 0);
7633 }
7634 if (!fp) rb_syserr_fail_path(e, prog);
7635 fd = fileno(fp);
7636#endif
7637
7638 port = io_alloc(rb_cIO);
7639 MakeOpenFile(port, fptr);
7640 fptr->fd = fd;
7641 fptr->stdio_file = fp;
7642 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7643 if (convconfig) {
7644 fptr->encs = *convconfig;
7645#if RUBY_CRLF_ENVIRONMENT
7648 }
7649#endif
7650 }
7651 else {
7652 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7654 }
7655#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7656 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7657 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7658 }
7659#endif
7660 }
7661 fptr->pid = pid;
7662
7663 if (0 <= write_fd) {
7664 write_port = io_alloc(rb_cIO);
7665 MakeOpenFile(write_port, write_fptr);
7666 write_fptr->fd = write_fd;
7667 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7668 fptr->mode &= ~FMODE_WRITABLE;
7669 fptr->tied_io_for_writing = write_port;
7670 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7671 }
7672
7673#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7674 fptr->finalize = pipe_finalize;
7675 pipe_add_fptr(fptr);
7676#endif
7677 return port;
7678}
7679#else
7680static VALUE
7681pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7682 const convconfig_t *convconfig)
7683{
7684 rb_raise(rb_eNotImpError, "popen() is not available");
7685}
7686#endif
7687
7688static int
7689is_popen_fork(VALUE prog)
7690{
7691 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7692#if !defined(HAVE_WORKING_FORK)
7694 "fork() function is unimplemented on this machine");
7695#else
7696 return TRUE;
7697#endif
7698 }
7699 return FALSE;
7700}
7701
7702static VALUE
7703pipe_open_s(VALUE prog, const char *modestr, int fmode,
7704 const convconfig_t *convconfig)
7705{
7706 int argc = 1;
7707 VALUE *argv = &prog;
7708 VALUE execarg_obj = Qnil;
7709
7710 if (!is_popen_fork(prog))
7711 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7712 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7713}
7714
7715static VALUE
7716pipe_close(VALUE io)
7717{
7718 rb_io_t *fptr = io_close_fptr(io);
7719 if (fptr) {
7720 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7721 }
7722 return Qnil;
7723}
7724
7725static VALUE popen_finish(VALUE port, VALUE klass);
7726
7727/*
7728 * call-seq:
7729 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7730 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7731 *
7732 * Executes the given command +cmd+ as a subprocess
7733 * whose $stdin and $stdout are connected to a new stream +io+.
7734 *
7735 * This method has potential security vulnerabilities if called with untrusted input;
7736 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7737 *
7738 * If no block is given, returns the new stream,
7739 * which depending on given +mode+ may be open for reading, writing, or both.
7740 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7741 *
7742 * If a block is given, the stream is passed to the block
7743 * (again, open for reading, writing, or both);
7744 * when the block exits, the stream is closed,
7745 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7746 *
7747 * Optional argument +mode+ may be any valid \IO mode.
7748 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7749 *
7750 * Required argument +cmd+ determines which of the following occurs:
7751 *
7752 * - The process forks.
7753 * - A specified program runs in a shell.
7754 * - A specified program runs with specified arguments.
7755 * - A specified program runs with specified arguments and a specified +argv0+.
7756 *
7757 * Each of these is detailed below.
7758 *
7759 * The optional hash argument +env+ specifies name/value pairs that are to be added
7760 * to the environment variables for the subprocess:
7761 *
7762 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7763 * pipe.puts 'puts ENV["FOO"]'
7764 * pipe.close_write
7765 * pipe.gets
7766 * end => "bar\n"
7767 *
7768 * Optional keyword arguments +opts+ specify:
7769 *
7770 * - {Open options}[rdoc-ref:IO@Open+Options].
7771 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7772 * - Options for Kernel#spawn.
7773 *
7774 * <b>Forked \Process</b>
7775 *
7776 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7777 * IO.popen('-') do |pipe|
7778 * if pipe
7779 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7780 * else
7781 * $stderr.puts "In child, pid is #{$$}\n"
7782 * end
7783 * end
7784 *
7785 * Output:
7786 *
7787 * In parent, child pid is 26253
7788 * In child, pid is 26253
7789 *
7790 * Note that this is not supported on all platforms.
7791 *
7792 * <b>Shell Subprocess</b>
7793 *
7794 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7795 * the program named +cmd+ is run as a shell command:
7796 *
7797 * IO.popen('uname') do |pipe|
7798 * pipe.readlines
7799 * end
7800 *
7801 * Output:
7802 *
7803 * ["Linux\n"]
7804 *
7805 * Another example:
7806 *
7807 * IO.popen('/bin/sh', 'r+') do |pipe|
7808 * pipe.puts('ls')
7809 * pipe.close_write
7810 * $stderr.puts pipe.readlines.size
7811 * end
7812 *
7813 * Output:
7814 *
7815 * 213
7816 *
7817 * <b>Program Subprocess</b>
7818 *
7819 * When argument +cmd+ is an array of strings,
7820 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7821 *
7822 * IO.popen(['du', '..', '.']) do |pipe|
7823 * $stderr.puts pipe.readlines.size
7824 * end
7825 *
7826 * Output:
7827 *
7828 * 1111
7829 *
7830 * <b>Program Subprocess with <tt>argv0</tt></b>
7831 *
7832 * When argument +cmd+ is an array whose first element is a 2-element string array
7833 * and whose remaining elements (if any) are strings:
7834 *
7835 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7836 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7837 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7838 *
7839 * Example (sets <tt>$0</tt> to 'foo'):
7840 *
7841 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7842 *
7843 * <b>Some Special Examples</b>
7844 *
7845 * # Set IO encoding.
7846 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7847 * euc_jp_string = nkf_io.read
7848 * }
7849 *
7850 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7851 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7852 * ls_result_with_error = io.read
7853 * end
7854 *
7855 * # Use mixture of spawn options and IO options.
7856 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7857 * ls_result_with_error = io.read
7858 * end
7859 *
7860 * f = IO.popen("uname")
7861 * p f.readlines
7862 * f.close
7863 * puts "Parent is #{Process.pid}"
7864 * IO.popen("date") {|f| puts f.gets }
7865 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7866 * p $?
7867 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7868 * f.puts "bar"; f.close_write; puts f.gets
7869 * }
7870 *
7871 * Output (from last section):
7872 *
7873 * ["Linux\n"]
7874 * Parent is 21346
7875 * Thu Jan 15 22:41:19 JST 2009
7876 * 21346 is here, f is #<IO:fd 3>
7877 * 21352 is here, f is nil
7878 * #<Process::Status: pid 21352 exit 0>
7879 * <foo>bar;zot;
7880 *
7881 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7882 *
7883 */
7884
7885static VALUE
7886rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7887{
7888 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7889
7890 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7891 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7892 switch (argc) {
7893 case 2:
7894 pmode = argv[1];
7895 case 1:
7896 pname = argv[0];
7897 break;
7898 default:
7899 {
7900 int ex = !NIL_P(opt);
7901 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7902 }
7903 }
7904 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7905}
7906
7907VALUE
7908rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7909{
7910 const char *modestr;
7911 VALUE tmp, execarg_obj = Qnil;
7912 int oflags, fmode;
7913 convconfig_t convconfig;
7914
7915 tmp = rb_check_array_type(pname);
7916 if (!NIL_P(tmp)) {
7917 long len = RARRAY_LEN(tmp);
7918#if SIZEOF_LONG > SIZEOF_INT
7919 if (len > INT_MAX) {
7920 rb_raise(rb_eArgError, "too many arguments");
7921 }
7922#endif
7923 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7924 RB_GC_GUARD(tmp);
7925 }
7926 else {
7927 SafeStringValue(pname);
7928 execarg_obj = Qnil;
7929 if (!is_popen_fork(pname))
7930 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7931 }
7932 if (!NIL_P(execarg_obj)) {
7933 if (!NIL_P(opt))
7934 opt = rb_execarg_extract_options(execarg_obj, opt);
7935 if (!NIL_P(env))
7936 rb_execarg_setenv(execarg_obj, env);
7937 }
7938 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
7939 modestr = rb_io_oflags_modestr(oflags);
7940
7941 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7942}
7943
7944static VALUE
7945popen_finish(VALUE port, VALUE klass)
7946{
7947 if (NIL_P(port)) {
7948 /* child */
7949 if (rb_block_given_p()) {
7950 rb_yield(Qnil);
7953 _exit(0);
7954 }
7955 return Qnil;
7956 }
7957 RBASIC_SET_CLASS(port, klass);
7958 if (rb_block_given_p()) {
7959 return rb_ensure(rb_yield, port, pipe_close, port);
7960 }
7961 return port;
7962}
7963
7964static void
7965rb_scan_open_args(int argc, const VALUE *argv,
7966 VALUE *fname_p, int *oflags_p, int *fmode_p,
7967 convconfig_t *convconfig_p, mode_t *perm_p)
7968{
7969 VALUE opt, fname, vmode, vperm;
7970 int oflags, fmode;
7971 mode_t perm;
7972
7973 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
7974 FilePathValue(fname);
7975
7976 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
7977
7978 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
7979
7980 *fname_p = fname;
7981 *oflags_p = oflags;
7982 *fmode_p = fmode;
7983 *perm_p = perm;
7984}
7985
7986static VALUE
7987rb_open_file(int argc, const VALUE *argv, VALUE io)
7988{
7989 VALUE fname;
7990 int oflags, fmode;
7991 convconfig_t convconfig;
7992 mode_t perm;
7993
7994 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
7995 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
7996
7997 return io;
7998}
7999
8000/*
8001 * Document-method: File::open
8002 *
8003 * call-seq:
8004 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8005 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8006 *
8007 * Creates a new \File object, via File.new with the given arguments.
8008 *
8009 * With no block given, returns the \File object.
8010 *
8011 * With a block given, calls the block with the \File object
8012 * and returns the block's value.
8013 *
8014 */
8015
8016/*
8017 * Document-method: IO::open
8018 *
8019 * call-seq:
8020 * IO.open(fd, mode = 'r', **opts) -> io
8021 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8022 *
8023 * Creates a new \IO object, via IO.new with the given arguments.
8024 *
8025 * With no block given, returns the \IO object.
8026 *
8027 * With a block given, calls the block with the \IO object
8028 * and returns the block's value.
8029 *
8030 */
8031
8032static VALUE
8033rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8034{
8036
8037 if (rb_block_given_p()) {
8038 return rb_ensure(rb_yield, io, io_close, io);
8039 }
8040
8041 return io;
8042}
8043
8044/*
8045 * call-seq:
8046 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8047 *
8048 * Opens the file at the given path with the given mode and permissions;
8049 * returns the integer file descriptor.
8050 *
8051 * If the file is to be readable, it must exist;
8052 * if the file is to be writable and does not exist,
8053 * it is created with the given permissions:
8054 *
8055 * File.write('t.tmp', '') # => 0
8056 * IO.sysopen('t.tmp') # => 8
8057 * IO.sysopen('t.tmp', 'w') # => 9
8058 *
8059 *
8060 */
8061
8062static VALUE
8063rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8064{
8065 VALUE fname, vmode, vperm;
8066 VALUE intmode;
8067 int oflags, fd;
8068 mode_t perm;
8069
8070 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8071 FilePathValue(fname);
8072
8073 if (NIL_P(vmode))
8074 oflags = O_RDONLY;
8075 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8076 oflags = NUM2INT(intmode);
8077 else {
8078 SafeStringValue(vmode);
8079 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8080 }
8081 if (NIL_P(vperm)) perm = 0666;
8082 else perm = NUM2MODET(vperm);
8083
8084 RB_GC_GUARD(fname) = rb_str_new4(fname);
8085 fd = rb_sysopen(fname, oflags, perm);
8086 return INT2NUM(fd);
8087}
8088
8089static VALUE
8090check_pipe_command(VALUE filename_or_command)
8091{
8092 char *s = RSTRING_PTR(filename_or_command);
8093 long l = RSTRING_LEN(filename_or_command);
8094 char *e = s + l;
8095 int chlen;
8096
8097 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8098 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8099 return cmd;
8100 }
8101 return Qnil;
8102}
8103
8104/*
8105 * call-seq:
8106 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8107 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8108 *
8109 * Creates an IO object connected to the given stream, file, or subprocess.
8110 *
8111 * Required string argument +path+ determines which of the following occurs:
8112 *
8113 * - The file at the specified +path+ is opened.
8114 * - The process forks.
8115 * - A subprocess is created.
8116 *
8117 * Each of these is detailed below.
8118 *
8119 * <b>File Opened</b>
8120
8121 * If +path+ does _not_ start with a pipe character (<tt>'|'</tt>),
8122 * a file stream is opened with <tt>File.open(path, mode, perm, **opts)</tt>.
8123 *
8124 * With no block given, file stream is returned:
8125 *
8126 * open('t.txt') # => #<File:t.txt>
8127 *
8128 * With a block given, calls the block with the open file stream,
8129 * then closes the stream:
8130 *
8131 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8132 *
8133 * Output:
8134 *
8135 * #<File:t.txt>
8136 *
8137 * See File.open for details.
8138 *
8139 * <b>Process Forked</b>
8140 *
8141 * If +path+ is the 2-character string <tt>'|-'</tt>, the process forks
8142 * and the child process is connected to the parent.
8143 *
8144 * With no block given:
8145 *
8146 * io = open('|-')
8147 * if io
8148 * $stderr.puts "In parent, child pid is #{io.pid}."
8149 * else
8150 * $stderr.puts "In child, pid is #{$$}."
8151 * end
8152 *
8153 * Output:
8154 *
8155 * In parent, child pid is 27903.
8156 * In child, pid is 27903.
8157 *
8158 * With a block given:
8159 *
8160 * open('|-') do |io|
8161 * if io
8162 * $stderr.puts "In parent, child pid is #{io.pid}."
8163 * else
8164 * $stderr.puts "In child, pid is #{$$}."
8165 * end
8166 * end
8167 *
8168 * Output:
8169 *
8170 * In parent, child pid is 28427.
8171 * In child, pid is 28427.
8172 *
8173 * <b>Subprocess Created</b>
8174 *
8175 * If +path+ is <tt>'|command'</tt> (<tt>'command' != '-'</tt>),
8176 * a new subprocess runs the command; its open stream is returned.
8177 * Note that the command may be processed by shell if it contains
8178 * shell metacharacters.
8179 *
8180 * With no block given:
8181 *
8182 * io = open('|echo "Hi!"') # => #<IO:fd 12>
8183 * print io.gets
8184 * io.close
8185 *
8186 * Output:
8187 *
8188 * "Hi!"
8189 *
8190 * With a block given, calls the block with the stream, then closes the stream:
8191 *
8192 * open('|echo "Hi!"') do |io|
8193 * print io.gets
8194 * end
8195 *
8196 * Output:
8197 *
8198 * "Hi!"
8199 *
8200 */
8201
8202static VALUE
8203rb_f_open(int argc, VALUE *argv, VALUE _)
8204{
8205 ID to_open = 0;
8206 int redirect = FALSE;
8207
8208 if (argc >= 1) {
8209 CONST_ID(to_open, "to_open");
8210 if (rb_respond_to(argv[0], to_open)) {
8211 redirect = TRUE;
8212 }
8213 else {
8214 VALUE tmp = argv[0];
8215 FilePathValue(tmp);
8216 if (NIL_P(tmp)) {
8217 redirect = TRUE;
8218 }
8219 else {
8220 VALUE cmd = check_pipe_command(tmp);
8221 if (!NIL_P(cmd)) {
8222 argv[0] = cmd;
8223 return rb_io_s_popen(argc, argv, rb_cIO);
8224 }
8225 }
8226 }
8227 }
8228 if (redirect) {
8229 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8230
8231 if (rb_block_given_p()) {
8232 return rb_ensure(rb_yield, io, io_close, io);
8233 }
8234 return io;
8235 }
8236 return rb_io_s_open(argc, argv, rb_cFile);
8237}
8238
8239static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const convconfig_t *, mode_t);
8240
8241static VALUE
8242rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8243{
8244 int oflags, fmode;
8245 convconfig_t convconfig;
8246 mode_t perm;
8247
8248 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8249 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8250 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8251}
8252
8253static VALUE
8254rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8255 const convconfig_t *convconfig, mode_t perm)
8256{
8257 VALUE cmd;
8258 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8259 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8260 }
8261 else {
8262 return rb_file_open_generic(io_alloc(klass), filename,
8263 oflags, fmode, convconfig, perm);
8264 }
8265}
8266
8267static VALUE
8268io_reopen(VALUE io, VALUE nfile)
8269{
8270 rb_io_t *fptr, *orig;
8271 int fd, fd2;
8272 rb_off_t pos = 0;
8273
8274 nfile = rb_io_get_io(nfile);
8275 GetOpenFile(io, fptr);
8276 GetOpenFile(nfile, orig);
8277
8278 if (fptr == orig) return io;
8279 if (IS_PREP_STDIO(fptr)) {
8280 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8281 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8282 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8284 "%s can't change access mode from \"%s\" to \"%s\"",
8285 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8286 rb_io_fmode_modestr(orig->mode));
8287 }
8288 }
8289 if (fptr->mode & FMODE_WRITABLE) {
8290 if (io_fflush(fptr) < 0)
8291 rb_sys_fail_on_write(fptr);
8292 }
8293 else {
8294 flush_before_seek(fptr);
8295 }
8296 if (orig->mode & FMODE_READABLE) {
8297 pos = io_tell(orig);
8298 }
8299 if (orig->mode & FMODE_WRITABLE) {
8300 if (io_fflush(orig) < 0)
8301 rb_sys_fail_on_write(fptr);
8302 }
8303
8304 /* copy rb_io_t structure */
8305 fptr->mode = orig->mode | (fptr->mode & FMODE_PREP);
8306 fptr->pid = orig->pid;
8307 fptr->lineno = orig->lineno;
8308 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8309 else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
8310 fptr_copy_finalizer(fptr, orig);
8311
8312 fd = fptr->fd;
8313 fd2 = orig->fd;
8314 if (fd != fd2) {
8315 if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->stdio_file) {
8316 /* need to keep FILE objects of stdin, stdout and stderr */
8317 if (rb_cloexec_dup2(fd2, fd) < 0)
8318 rb_sys_fail_path(orig->pathv);
8319 rb_update_max_fd(fd);
8320 }
8321 else {
8322 fclose(fptr->stdio_file);
8323 fptr->stdio_file = 0;
8324 fptr->fd = -1;
8325 if (rb_cloexec_dup2(fd2, fd) < 0)
8326 rb_sys_fail_path(orig->pathv);
8327 rb_update_max_fd(fd);
8328 fptr->fd = fd;
8329 }
8331 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8332 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8333 rb_sys_fail_path(fptr->pathv);
8334 }
8335 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8336 rb_sys_fail_path(orig->pathv);
8337 }
8338 }
8339 }
8340
8341 if (fptr->mode & FMODE_BINMODE) {
8342 rb_io_binmode(io);
8343 }
8344
8345 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8346 return io;
8347}
8348
8349#ifdef _WIN32
8350int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8351#else
8352static int
8353rb_freopen(VALUE fname, const char *mode, FILE *fp)
8354{
8355 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8356 RB_GC_GUARD(fname);
8357 return errno;
8358 }
8359 return 0;
8360}
8361#endif
8362
8363/*
8364 * call-seq:
8365 * reopen(other_io) -> self
8366 * reopen(path, mode = 'r', **opts) -> self
8367 *
8368 * Reassociates the stream with another stream,
8369 * which may be of a different class.
8370 * This method may be used to redirect an existing stream
8371 * to a new destination.
8372 *
8373 * With argument +other_io+ given, reassociates with that stream:
8374 *
8375 * # Redirect $stdin from a file.
8376 * f = File.open('t.txt')
8377 * $stdin.reopen(f)
8378 * f.close
8379 *
8380 * # Redirect $stdout to a file.
8381 * f = File.open('t.tmp', 'w')
8382 * $stdout.reopen(f)
8383 * f.close
8384 *
8385 * With argument +path+ given, reassociates with a new stream to that file path:
8386 *
8387 * $stdin.reopen('t.txt')
8388 * $stdout.reopen('t.tmp', 'w')
8389 *
8390 * Optional keyword arguments +opts+ specify:
8391 *
8392 * - {Open Options}[rdoc-ref:IO@Open+Options].
8393 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8394 *
8395 */
8396
8397static VALUE
8398rb_io_reopen(int argc, VALUE *argv, VALUE file)
8399{
8400 VALUE fname, nmode, opt;
8401 int oflags;
8402 rb_io_t *fptr;
8403
8404 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8405 VALUE tmp = rb_io_check_io(fname);
8406 if (!NIL_P(tmp)) {
8407 return io_reopen(file, tmp);
8408 }
8409 }
8410
8411 FilePathValue(fname);
8412 rb_io_taint_check(file);
8413 fptr = RFILE(file)->fptr;
8414 if (!fptr) {
8415 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8416 }
8417
8418 if (!NIL_P(nmode) || !NIL_P(opt)) {
8419 int fmode;
8420 convconfig_t convconfig;
8421
8422 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8423 if (IS_PREP_STDIO(fptr) &&
8424 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8425 (fptr->mode & FMODE_READWRITE)) {
8427 "%s can't change access mode from \"%s\" to \"%s\"",
8428 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8429 rb_io_fmode_modestr(fmode));
8430 }
8431 fptr->mode = fmode;
8432 fptr->encs = convconfig;
8433 }
8434 else {
8435 oflags = rb_io_fmode_oflags(fptr->mode);
8436 }
8437
8438 fptr->pathv = fname;
8439 if (fptr->fd < 0) {
8440 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8441 fptr->stdio_file = 0;
8442 return file;
8443 }
8444
8445 if (fptr->mode & FMODE_WRITABLE) {
8446 if (io_fflush(fptr) < 0)
8447 rb_sys_fail_on_write(fptr);
8448 }
8449 fptr->rbuf.off = fptr->rbuf.len = 0;
8450
8451 if (fptr->stdio_file) {
8452 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8453 rb_io_oflags_modestr(oflags),
8454 fptr->stdio_file);
8455 if (e) rb_syserr_fail_path(e, fptr->pathv);
8456 fptr->fd = fileno(fptr->stdio_file);
8457 rb_fd_fix_cloexec(fptr->fd);
8458#ifdef USE_SETVBUF
8459 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8460 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8461#endif
8462 if (fptr->stdio_file == stderr) {
8463 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8464 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8465 }
8466 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8467 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8468 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8469 }
8470 }
8471 else {
8472 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8473 int err = 0;
8474 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8475 err = errno;
8476 (void)close(tmpfd);
8477 if (err) {
8478 rb_syserr_fail_path(err, fptr->pathv);
8479 }
8480 }
8481
8482 return file;
8483}
8484
8485/* :nodoc: */
8486static VALUE
8487rb_io_init_copy(VALUE dest, VALUE io)
8488{
8489 rb_io_t *fptr, *orig;
8490 int fd;
8491 VALUE write_io;
8492 rb_off_t pos;
8493
8494 io = rb_io_get_io(io);
8495 if (!OBJ_INIT_COPY(dest, io)) return dest;
8496 GetOpenFile(io, orig);
8497 MakeOpenFile(dest, fptr);
8498
8499 rb_io_flush(io);
8500
8501 /* copy rb_io_t structure */
8502 fptr->mode = orig->mode & ~FMODE_PREP;
8503 fptr->encs = orig->encs;
8504 fptr->pid = orig->pid;
8505 fptr->lineno = orig->lineno;
8506 fptr->timeout = orig->timeout;
8507 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8508 fptr_copy_finalizer(fptr, orig);
8509
8510 fd = ruby_dup(orig->fd);
8511 fptr->fd = fd;
8512 pos = io_tell(orig);
8513 if (0 <= pos)
8514 io_seek(fptr, pos, SEEK_SET);
8515 if (fptr->mode & FMODE_BINMODE) {
8516 rb_io_binmode(dest);
8517 }
8518
8519 write_io = GetWriteIO(io);
8520 if (io != write_io) {
8521 write_io = rb_obj_dup(write_io);
8522 fptr->tied_io_for_writing = write_io;
8523 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8524 }
8525
8526 return dest;
8527}
8528
8529/*
8530 * call-seq:
8531 * printf(format_string, *objects) -> nil
8532 *
8533 * Formats and writes +objects+ to the stream.
8534 *
8535 * For details on +format_string+, see
8536 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8537 *
8538 */
8539
8540VALUE
8541rb_io_printf(int argc, const VALUE *argv, VALUE out)
8542{
8543 rb_io_write(out, rb_f_sprintf(argc, argv));
8544 return Qnil;
8545}
8546
8547/*
8548 * call-seq:
8549 * printf(format_string, *objects) -> nil
8550 * printf(io, format_string, *objects) -> nil
8551 *
8552 * Equivalent to:
8553 *
8554 * io.write(sprintf(format_string, *objects))
8555 *
8556 * For details on +format_string+, see
8557 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8558 *
8559 * With the single argument +format_string+, formats +objects+ into the string,
8560 * then writes the formatted string to $stdout:
8561 *
8562 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8563 *
8564 * Output (on $stdout):
8565 *
8566 * 0024 24 24.00#
8567 *
8568 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8569 * then writes the formatted string to +io+:
8570 *
8571 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8572 *
8573 * Output (on $stderr):
8574 *
8575 * 0024 24 24.00# => nil
8576 *
8577 * With no arguments, does nothing.
8578 *
8579 */
8580
8581static VALUE
8582rb_f_printf(int argc, VALUE *argv, VALUE _)
8583{
8584 VALUE out;
8585
8586 if (argc == 0) return Qnil;
8587 if (RB_TYPE_P(argv[0], T_STRING)) {
8588 out = rb_ractor_stdout();
8589 }
8590 else {
8591 out = argv[0];
8592 argv++;
8593 argc--;
8594 }
8595 rb_io_write(out, rb_f_sprintf(argc, argv));
8596
8597 return Qnil;
8598}
8599
8600static void
8601deprecated_str_setter(VALUE val, ID id, VALUE *var)
8602{
8603 rb_str_setter(val, id, &val);
8604 if (!NIL_P(val)) {
8605 rb_warn_deprecated("`%s'", NULL, rb_id2name(id));
8606 }
8607 *var = val;
8608}
8609
8610/*
8611 * call-seq:
8612 * print(*objects) -> nil
8613 *
8614 * Writes the given objects to the stream; returns +nil+.
8615 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8616 * (<tt>$\</tt>), if it is not +nil+.
8617 * See {Line IO}[rdoc-ref:IO@Line+IO].
8618 *
8619 * With argument +objects+ given, for each object:
8620 *
8621 * - Converts via its method +to_s+ if not a string.
8622 * - Writes to the stream.
8623 * - If not the last object, writes the output field separator
8624 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8625 *
8626 * With default separators:
8627 *
8628 * f = File.open('t.tmp', 'w+')
8629 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8630 * p $OUTPUT_RECORD_SEPARATOR
8631 * p $OUTPUT_FIELD_SEPARATOR
8632 * f.print(*objects)
8633 * f.rewind
8634 * p f.read
8635 * f.close
8636 *
8637 * Output:
8638 *
8639 * nil
8640 * nil
8641 * "00.00/10+0izerozero"
8642 *
8643 * With specified separators:
8644 *
8645 * $\ = "\n"
8646 * $, = ','
8647 * f.rewind
8648 * f.print(*objects)
8649 * f.rewind
8650 * p f.read
8651 *
8652 * Output:
8653 *
8654 * "0,0.0,0/1,0+0i,zero,zero\n"
8655 *
8656 * With no argument given, writes the content of <tt>$_</tt>
8657 * (which is usually the most recent user input):
8658 *
8659 * f = File.open('t.tmp', 'w+')
8660 * gets # Sets $_ to the most recent user input.
8661 * f.print
8662 * f.close
8663 *
8664 */
8665
8666VALUE
8667rb_io_print(int argc, const VALUE *argv, VALUE out)
8668{
8669 int i;
8670 VALUE line;
8671
8672 /* if no argument given, print `$_' */
8673 if (argc == 0) {
8674 argc = 1;
8675 line = rb_lastline_get();
8676 argv = &line;
8677 }
8678 if (argc > 1 && !NIL_P(rb_output_fs)) {
8679 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8680 }
8681 for (i=0; i<argc; i++) {
8682 if (!NIL_P(rb_output_fs) && i>0) {
8683 rb_io_write(out, rb_output_fs);
8684 }
8685 rb_io_write(out, argv[i]);
8686 }
8687 if (argc > 0 && !NIL_P(rb_output_rs)) {
8689 }
8690
8691 return Qnil;
8692}
8693
8694/*
8695 * call-seq:
8696 * print(*objects) -> nil
8697 *
8698 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8699 * this method is the straightforward way to write to <tt>$stdout</tt>.
8700 *
8701 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8702 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8703 * <tt>$\</tt>), if it is not +nil+.
8704 *
8705 * With argument +objects+ given, for each object:
8706 *
8707 * - Converts via its method +to_s+ if not a string.
8708 * - Writes to <tt>stdout</tt>.
8709 * - If not the last object, writes the output field separator
8710 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8711 *
8712 * With default separators:
8713 *
8714 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8715 * $OUTPUT_RECORD_SEPARATOR
8716 * $OUTPUT_FIELD_SEPARATOR
8717 * print(*objects)
8718 *
8719 * Output:
8720 *
8721 * nil
8722 * nil
8723 * 00.00/10+0izerozero
8724 *
8725 * With specified separators:
8726 *
8727 * $OUTPUT_RECORD_SEPARATOR = "\n"
8728 * $OUTPUT_FIELD_SEPARATOR = ','
8729 * print(*objects)
8730 *
8731 * Output:
8732 *
8733 * 0,0.0,0/1,0+0i,zero,zero
8734 *
8735 * With no argument given, writes the content of <tt>$_</tt>
8736 * (which is usually the most recent user input):
8737 *
8738 * gets # Sets $_ to the most recent user input.
8739 * print # Prints $_.
8740 *
8741 */
8742
8743static VALUE
8744rb_f_print(int argc, const VALUE *argv, VALUE _)
8745{
8746 rb_io_print(argc, argv, rb_ractor_stdout());
8747 return Qnil;
8748}
8749
8750/*
8751 * call-seq:
8752 * putc(object) -> object
8753 *
8754 * Writes a character to the stream.
8755 * See {Character IO}[rdoc-ref:IO@Character+IO].
8756 *
8757 * If +object+ is numeric, converts to integer if necessary,
8758 * then writes the character whose code is the
8759 * least significant byte;
8760 * if +object+ is a string, writes the first character:
8761 *
8762 * $stdout.putc "A"
8763 * $stdout.putc 65
8764 *
8765 * Output:
8766 *
8767 * AA
8768 *
8769 */
8770
8771static VALUE
8772rb_io_putc(VALUE io, VALUE ch)
8773{
8774 VALUE str;
8775 if (RB_TYPE_P(ch, T_STRING)) {
8776 str = rb_str_substr(ch, 0, 1);
8777 }
8778 else {
8779 char c = NUM2CHR(ch);
8780 str = rb_str_new(&c, 1);
8781 }
8782 rb_io_write(io, str);
8783 return ch;
8784}
8785
8786#define forward(obj, id, argc, argv) \
8787 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8788#define forward_public(obj, id, argc, argv) \
8789 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8790#define forward_current(id, argc, argv) \
8791 forward_public(ARGF.current_file, id, argc, argv)
8792
8793/*
8794 * call-seq:
8795 * putc(int) -> int
8796 *
8797 * Equivalent to:
8798 *
8799 * $stdout.putc(int)
8800 *
8801 * See IO#putc for important information regarding multi-byte characters.
8802 *
8803 */
8804
8805static VALUE
8806rb_f_putc(VALUE recv, VALUE ch)
8807{
8808 VALUE r_stdout = rb_ractor_stdout();
8809 if (recv == r_stdout) {
8810 return rb_io_putc(recv, ch);
8811 }
8812 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8813}
8814
8815
8816int
8817rb_str_end_with_asciichar(VALUE str, int c)
8818{
8819 long len = RSTRING_LEN(str);
8820 const char *ptr = RSTRING_PTR(str);
8821 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8822 int n;
8823
8824 if (len == 0) return 0;
8825 if ((n = rb_enc_mbminlen(enc)) == 1) {
8826 return ptr[len - 1] == c;
8827 }
8828 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8829}
8830
8831static VALUE
8832io_puts_ary(VALUE ary, VALUE out, int recur)
8833{
8834 VALUE tmp;
8835 long i;
8836
8837 if (recur) {
8838 tmp = rb_str_new2("[...]");
8839 rb_io_puts(1, &tmp, out);
8840 return Qtrue;
8841 }
8842 ary = rb_check_array_type(ary);
8843 if (NIL_P(ary)) return Qfalse;
8844 for (i=0; i<RARRAY_LEN(ary); i++) {
8845 tmp = RARRAY_AREF(ary, i);
8846 rb_io_puts(1, &tmp, out);
8847 }
8848 return Qtrue;
8849}
8850
8851/*
8852 * call-seq:
8853 * puts(*objects) -> nil
8854 *
8855 * Writes the given +objects+ to the stream, which must be open for writing;
8856 * returns +nil+.\
8857 * Writes a newline after each that does not already end with a newline sequence.
8858 * If called without arguments, writes a newline.
8859 * See {Line IO}[rdoc-ref:IO@Line+IO].
8860 *
8861 * Note that each added newline is the character <tt>"\n"<//tt>,
8862 * not the output record separator (<tt>$\</tt>).
8863 *
8864 * Treatment for each object:
8865 *
8866 * - \String: writes the string.
8867 * - Neither string nor array: writes <tt>object.to_s</tt>.
8868 * - \Array: writes each element of the array; arrays may be nested.
8869 *
8870 * To keep these examples brief, we define this helper method:
8871 *
8872 * def show(*objects)
8873 * # Puts objects to file.
8874 * f = File.new('t.tmp', 'w+')
8875 * f.puts(objects)
8876 * # Return file content.
8877 * f.rewind
8878 * p f.read
8879 * f.close
8880 * end
8881 *
8882 * # Strings without newlines.
8883 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8884 * # Strings, some with newlines.
8885 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8886 *
8887 * # Neither strings nor arrays:
8888 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8889 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8890 *
8891 * # Array of strings.
8892 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8893 * # Nested arrays.
8894 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8895 *
8896 */
8897
8898VALUE
8899rb_io_puts(int argc, const VALUE *argv, VALUE out)
8900{
8901 int i, n;
8902 VALUE line, args[2];
8903
8904 /* if no argument given, print newline. */
8905 if (argc == 0) {
8907 return Qnil;
8908 }
8909 for (i=0; i<argc; i++) {
8910 if (RB_TYPE_P(argv[i], T_STRING)) {
8911 line = argv[i];
8912 goto string;
8913 }
8914 if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8915 continue;
8916 }
8917 line = rb_obj_as_string(argv[i]);
8918 string:
8919 n = 0;
8920 args[n++] = line;
8921 if (RSTRING_LEN(line) == 0 ||
8922 !rb_str_end_with_asciichar(line, '\n')) {
8923 args[n++] = rb_default_rs;
8924 }
8925 rb_io_writev(out, n, args);
8926 }
8927
8928 return Qnil;
8929}
8930
8931/*
8932 * call-seq:
8933 * puts(*objects) -> nil
8934 *
8935 * Equivalent to
8936 *
8937 * $stdout.puts(objects)
8938 */
8939
8940static VALUE
8941rb_f_puts(int argc, VALUE *argv, VALUE recv)
8942{
8943 VALUE r_stdout = rb_ractor_stdout();
8944 if (recv == r_stdout) {
8945 return rb_io_puts(argc, argv, recv);
8946 }
8947 return forward(r_stdout, rb_intern("puts"), argc, argv);
8948}
8949
8950static VALUE
8951rb_p_write(VALUE str)
8952{
8953 VALUE args[2];
8954 args[0] = str;
8955 args[1] = rb_default_rs;
8956 VALUE r_stdout = rb_ractor_stdout();
8957 if (RB_TYPE_P(r_stdout, T_FILE) &&
8958 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
8959 io_writev(2, args, r_stdout);
8960 }
8961 else {
8962 rb_io_writev(r_stdout, 2, args);
8963 }
8964 return Qnil;
8965}
8966
8967void
8968rb_p(VALUE obj) /* for debug print within C code */
8969{
8970 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
8971}
8972
8973static VALUE
8974rb_p_result(int argc, const VALUE *argv)
8975{
8976 VALUE ret = Qnil;
8977
8978 if (argc == 1) {
8979 ret = argv[0];
8980 }
8981 else if (argc > 1) {
8982 ret = rb_ary_new4(argc, argv);
8983 }
8984 VALUE r_stdout = rb_ractor_stdout();
8985 if (RB_TYPE_P(r_stdout, T_FILE)) {
8986 rb_uninterruptible(rb_io_flush, r_stdout);
8987 }
8988 return ret;
8989}
8990
8991/*
8992 * call-seq:
8993 * p(object) -> obj
8994 * p(*objects) -> array of objects
8995 * p -> nil
8996 *
8997 * For each object +obj+, executes:
8998 *
8999 * $stdout.write(obj.inspect, "\n")
9000 *
9001 * With one object given, returns the object;
9002 * with multiple objects given, returns an array containing the objects;
9003 * with no object given, returns +nil+.
9004 *
9005 * Examples:
9006 *
9007 * r = Range.new(0, 4)
9008 * p r # => 0..4
9009 * p [r, r, r] # => [0..4, 0..4, 0..4]
9010 * p # => nil
9011 *
9012 * Output:
9013 *
9014 * 0..4
9015 * [0..4, 0..4, 0..4]
9016 *
9017 */
9018
9019static VALUE
9020rb_f_p(int argc, VALUE *argv, VALUE self)
9021{
9022 int i;
9023 for (i=0; i<argc; i++) {
9024 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9025 rb_uninterruptible(rb_p_write, inspected);
9026 }
9027 return rb_p_result(argc, argv);
9028}
9029
9030/*
9031 * call-seq:
9032 * display(port = $>) -> nil
9033 *
9034 * Writes +self+ on the given port:
9035 *
9036 * 1.display
9037 * "cat".display
9038 * [ 4, 5, 6 ].display
9039 * puts
9040 *
9041 * Output:
9042 *
9043 * 1cat[4, 5, 6]
9044 *
9045 */
9046
9047static VALUE
9048rb_obj_display(int argc, VALUE *argv, VALUE self)
9049{
9050 VALUE out;
9051
9052 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9053 rb_io_write(out, self);
9054
9055 return Qnil;
9056}
9057
9058static int
9059rb_stderr_to_original_p(VALUE err)
9060{
9061 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9062}
9063
9064void
9065rb_write_error2(const char *mesg, long len)
9066{
9067 VALUE out = rb_ractor_stderr();
9068 if (rb_stderr_to_original_p(out)) {
9069#ifdef _WIN32
9070 if (isatty(fileno(stderr))) {
9071 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9072 }
9073#endif
9074 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9075 /* failed to write to stderr, what can we do? */
9076 return;
9077 }
9078 }
9079 else {
9080 rb_io_write(out, rb_str_new(mesg, len));
9081 }
9082}
9083
9084void
9085rb_write_error(const char *mesg)
9086{
9087 rb_write_error2(mesg, strlen(mesg));
9088}
9089
9090void
9091rb_write_error_str(VALUE mesg)
9092{
9093 VALUE out = rb_ractor_stderr();
9094 /* a stopgap measure for the time being */
9095 if (rb_stderr_to_original_p(out)) {
9096 size_t len = (size_t)RSTRING_LEN(mesg);
9097#ifdef _WIN32
9098 if (isatty(fileno(stderr))) {
9099 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9100 }
9101#endif
9102 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9103 RB_GC_GUARD(mesg);
9104 return;
9105 }
9106 }
9107 else {
9108 /* may unlock GVL, and */
9109 rb_io_write(out, mesg);
9110 }
9111}
9112
9113int
9114rb_stderr_tty_p(void)
9115{
9116 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9117 return isatty(fileno(stderr));
9118 return 0;
9119}
9120
9121static void
9122must_respond_to(ID mid, VALUE val, ID id)
9123{
9124 if (!rb_respond_to(val, mid)) {
9125 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9126 rb_id2str(id), rb_id2str(mid),
9127 rb_obj_class(val));
9128 }
9129}
9130
9131static void
9132stdin_setter(VALUE val, ID id, VALUE *ptr)
9133{
9135}
9136
9137static VALUE
9138stdin_getter(ID id, VALUE *ptr)
9139{
9140 return rb_ractor_stdin();
9141}
9142
9143static void
9144stdout_setter(VALUE val, ID id, VALUE *ptr)
9145{
9146 must_respond_to(id_write, val, id);
9148}
9149
9150static VALUE
9151stdout_getter(ID id, VALUE *ptr)
9152{
9153 return rb_ractor_stdout();
9154}
9155
9156static void
9157stderr_setter(VALUE val, ID id, VALUE *ptr)
9158{
9159 must_respond_to(id_write, val, id);
9161}
9162
9163static VALUE
9164stderr_getter(ID id, VALUE *ptr)
9165{
9166 return rb_ractor_stderr();
9167}
9168
9169static VALUE
9170prep_io(int fd, int fmode, VALUE klass, const char *path)
9171{
9172 rb_io_t *fp;
9173 VALUE io = io_alloc(klass);
9174
9175 MakeOpenFile(io, fp);
9176 fp->self = io;
9177 fp->fd = fd;
9178 fp->mode = fmode;
9179 fp->timeout = Qnil;
9180 if (!io_check_tty(fp)) {
9181#ifdef __CYGWIN__
9182 fp->mode |= FMODE_BINMODE;
9183 setmode(fd, O_BINARY);
9184#endif
9185 }
9186 if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
9187 rb_update_max_fd(fd);
9188
9189 return io;
9190}
9191
9192VALUE
9193rb_io_fdopen(int fd, int oflags, const char *path)
9194{
9195 VALUE klass = rb_cIO;
9196
9197 if (path && strcmp(path, "-")) klass = rb_cFile;
9198 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9199}
9200
9201static VALUE
9202prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9203{
9204 rb_io_t *fptr;
9205 VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
9206
9207 GetOpenFile(io, fptr);
9209#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9210 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9211 if (fmode & FMODE_READABLE) {
9213 }
9214#endif
9215 fptr->stdio_file = f;
9216
9217 return io;
9218}
9219
9220VALUE
9221rb_io_prep_stdin(void)
9222{
9223 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9224}
9225
9226VALUE
9227rb_io_prep_stdout(void)
9228{
9229 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9230}
9231
9232VALUE
9233rb_io_prep_stderr(void)
9234{
9235 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9236}
9237
9238FILE *
9240{
9241 if (!fptr->stdio_file) {
9242 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9243 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9244 }
9245 return fptr->stdio_file;
9246}
9247
9248static inline void
9249rb_io_buffer_init(rb_io_buffer_t *buf)
9250{
9251 buf->ptr = NULL;
9252 buf->off = 0;
9253 buf->len = 0;
9254 buf->capa = 0;
9255}
9256
9257static inline rb_io_t *
9258rb_io_fptr_new(void)
9259{
9260 rb_io_t *fp = ALLOC(rb_io_t);
9261 fp->self = Qnil;
9262 fp->fd = -1;
9263 fp->stdio_file = NULL;
9264 fp->mode = 0;
9265 fp->pid = 0;
9266 fp->lineno = 0;
9267 fp->pathv = Qnil;
9268 fp->finalize = 0;
9269 rb_io_buffer_init(&fp->wbuf);
9270 rb_io_buffer_init(&fp->rbuf);
9271 rb_io_buffer_init(&fp->cbuf);
9272 fp->readconv = NULL;
9273 fp->writeconv = NULL;
9275 fp->writeconv_pre_ecflags = 0;
9277 fp->writeconv_initialized = 0;
9278 fp->tied_io_for_writing = 0;
9279 fp->encs.enc = NULL;
9280 fp->encs.enc2 = NULL;
9281 fp->encs.ecflags = 0;
9282 fp->encs.ecopts = Qnil;
9283 fp->write_lock = Qnil;
9284 fp->timeout = Qnil;
9285 return fp;
9286}
9287
9288rb_io_t *
9289rb_io_make_open_file(VALUE obj)
9290{
9291 rb_io_t *fp = 0;
9292
9293 Check_Type(obj, T_FILE);
9294 if (RFILE(obj)->fptr) {
9295 rb_io_close(obj);
9296 rb_io_fptr_finalize(RFILE(obj)->fptr);
9297 RFILE(obj)->fptr = 0;
9298 }
9299 fp = rb_io_fptr_new();
9300 fp->self = obj;
9301 RFILE(obj)->fptr = fp;
9302 return fp;
9303}
9304
9305/*
9306 * call-seq:
9307 * IO.new(fd, mode = 'r', **opts) -> io
9308 *
9309 * Creates and returns a new \IO object (file stream) from a file descriptor.
9310 *
9311 * \IO.new may be useful for interaction with low-level libraries.
9312 * For higher-level interactions, it may be simpler to create
9313 * the file stream using File.open.
9314 *
9315 * Argument +fd+ must be a valid file descriptor (integer):
9316 *
9317 * path = 't.tmp'
9318 * fd = IO.sysopen(path) # => 3
9319 * IO.new(fd) # => #<IO:fd 3>
9320 *
9321 * The new \IO object does not inherit encoding
9322 * (because the integer file descriptor does not have an encoding):
9323 *
9324 * fd = IO.sysopen('t.rus', 'rb')
9325 * io = IO.new(fd)
9326 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9327 *
9328 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9329 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9330 *
9331 * IO.new(fd, 'w') # => #<IO:fd 3>
9332 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9333 *
9334 * Optional keyword arguments +opts+ specify:
9335 *
9336 * - {Open Options}[rdoc-ref:IO@Open+Options].
9337 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9338 *
9339 * Examples:
9340 *
9341 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9342 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9343 *
9344 */
9345
9346static VALUE
9347rb_io_initialize(int argc, VALUE *argv, VALUE io)
9348{
9349 VALUE fnum, vmode;
9350 rb_io_t *fp;
9351 int fd, fmode, oflags = O_RDONLY;
9352 convconfig_t convconfig;
9353 VALUE opt;
9354#if defined(HAVE_FCNTL) && defined(F_GETFL)
9355 int ofmode;
9356#else
9357 struct stat st;
9358#endif
9359
9360
9361 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9362 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9363
9364 fd = NUM2INT(fnum);
9365 if (rb_reserved_fd_p(fd)) {
9366 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9367 }
9368#if defined(HAVE_FCNTL) && defined(F_GETFL)
9369 oflags = fcntl(fd, F_GETFL);
9370 if (oflags == -1) rb_sys_fail(0);
9371#else
9372 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9373#endif
9374 rb_update_max_fd(fd);
9375#if defined(HAVE_FCNTL) && defined(F_GETFL)
9376 ofmode = rb_io_oflags_fmode(oflags);
9377 if (NIL_P(vmode)) {
9378 fmode = ofmode;
9379 }
9380 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9381 VALUE error = INT2FIX(EINVAL);
9383 }
9384#endif
9385 VALUE path = Qnil;
9386
9387 if (!NIL_P(opt)) {
9388 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9389 fmode |= FMODE_PREP;
9390 }
9391
9392 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9393 if (!NIL_P(path)) {
9394 StringValue(path);
9395 path = rb_str_new_frozen(path);
9396 }
9397 }
9398
9399 MakeOpenFile(io, fp);
9400 fp->self = io;
9401 fp->fd = fd;
9402 fp->mode = fmode;
9403 fp->encs = convconfig;
9404 fp->pathv = path;
9405 fp->timeout = Qnil;
9406 clear_codeconv(fp);
9407 io_check_tty(fp);
9408 if (fileno(stdin) == fd)
9409 fp->stdio_file = stdin;
9410 else if (fileno(stdout) == fd)
9411 fp->stdio_file = stdout;
9412 else if (fileno(stderr) == fd)
9413 fp->stdio_file = stderr;
9414
9415 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9416 return io;
9417}
9418
9419/*
9420 * call-seq:
9421 * set_encoding_by_bom -> encoding or nil
9422 *
9423 * If the stream begins with a BOM
9424 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9425 * consumes the BOM and sets the external encoding accordingly;
9426 * returns the result encoding if found, or +nil+ otherwise:
9427 *
9428 * File.write('t.tmp', "\u{FEFF}abc")
9429 * io = File.open('t.tmp', 'rb')
9430 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9431 * io.close
9432 *
9433 * File.write('t.tmp', 'abc')
9434 * io = File.open('t.tmp', 'rb')
9435 * io.set_encoding_by_bom # => nil
9436 * io.close
9437 *
9438 * Raises an exception if the stream is not binmode
9439 * or its encoding has already been set.
9440 *
9441 */
9442
9443static VALUE
9444rb_io_set_encoding_by_bom(VALUE io)
9445{
9446 rb_io_t *fptr;
9447
9448 GetOpenFile(io, fptr);
9449 if (!(fptr->mode & FMODE_BINMODE)) {
9450 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9451 }
9452 if (fptr->encs.enc2) {
9453 rb_raise(rb_eArgError, "encoding conversion is set");
9454 }
9455 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9456 rb_raise(rb_eArgError, "encoding is set to %s already",
9457 rb_enc_name(fptr->encs.enc));
9458 }
9459 if (!io_set_encoding_by_bom(io)) return Qnil;
9460 return rb_enc_from_encoding(fptr->encs.enc);
9461}
9462
9463/*
9464 * call-seq:
9465 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9466 *
9467 * Opens the file at the given +path+ according to the given +mode+;
9468 * creates and returns a new \File object for that file.
9469 *
9470 * The new \File object is buffered mode (or non-sync mode), unless
9471 * +filename+ is a tty.
9472 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9473 *
9474 * Argument +path+ must be a valid file path:
9475 *
9476 * f = File.new('/etc/fstab')
9477 * f.close
9478 * f = File.new('t.txt')
9479 * f.close
9480 *
9481 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9482 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9483 *
9484 * f = File.new('t.tmp', 'w')
9485 * f.close
9486 * f = File.new('t.tmp', File::RDONLY)
9487 * f.close
9488 *
9489 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9490 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9491 *
9492 * f = File.new('t.tmp', File::CREAT, 0644)
9493 * f.close
9494 * f = File.new('t.tmp', File::CREAT, 0444)
9495 * f.close
9496 *
9497 * Optional keyword arguments +opts+ specify:
9498 *
9499 * - {Open Options}[rdoc-ref:IO@Open+Options].
9500 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9501 *
9502 */
9503
9504static VALUE
9505rb_file_initialize(int argc, VALUE *argv, VALUE io)
9506{
9507 if (RFILE(io)->fptr) {
9508 rb_raise(rb_eRuntimeError, "reinitializing File");
9509 }
9510 if (0 < argc && argc < 3) {
9511 VALUE fd = rb_check_to_int(argv[0]);
9512
9513 if (!NIL_P(fd)) {
9514 argv[0] = fd;
9515 return rb_io_initialize(argc, argv, io);
9516 }
9517 }
9518 rb_open_file(argc, argv, io);
9519
9520 return io;
9521}
9522
9523/* :nodoc: */
9524static VALUE
9525rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9526{
9527 if (rb_block_given_p()) {
9528 VALUE cname = rb_obj_as_string(klass);
9529
9530 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9531 cname, cname);
9532 }
9533 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9534}
9535
9536
9537/*
9538 * call-seq:
9539 * IO.for_fd(fd, mode = 'r', **opts) -> io
9540 *
9541 * Synonym for IO.new.
9542 *
9543 */
9544
9545static VALUE
9546rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9547{
9548 VALUE io = rb_obj_alloc(klass);
9549 rb_io_initialize(argc, argv, io);
9550 return io;
9551}
9552
9553/*
9554 * call-seq:
9555 * ios.autoclose? -> true or false
9556 *
9557 * Returns +true+ if the underlying file descriptor of _ios_ will be
9558 * closed automatically at its finalization, otherwise +false+.
9559 */
9560
9561static VALUE
9562rb_io_autoclose_p(VALUE io)
9563{
9564 rb_io_t *fptr = RFILE(io)->fptr;
9565 rb_io_check_closed(fptr);
9566 return RBOOL(!(fptr->mode & FMODE_PREP));
9567}
9568
9569/*
9570 * call-seq:
9571 * io.autoclose = bool -> true or false
9572 *
9573 * Sets auto-close flag.
9574 *
9575 * f = open("/dev/null")
9576 * IO.for_fd(f.fileno)
9577 * # ...
9578 * f.gets # may cause Errno::EBADF
9579 *
9580 * f = open("/dev/null")
9581 * IO.for_fd(f.fileno).autoclose = false
9582 * # ...
9583 * f.gets # won't cause Errno::EBADF
9584 */
9585
9586static VALUE
9587rb_io_set_autoclose(VALUE io, VALUE autoclose)
9588{
9589 rb_io_t *fptr;
9590 GetOpenFile(io, fptr);
9591 if (!RTEST(autoclose))
9592 fptr->mode |= FMODE_PREP;
9593 else
9594 fptr->mode &= ~FMODE_PREP;
9595 return autoclose;
9596}
9597
9598static VALUE
9599io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9600{
9601 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9602
9603 if (!RB_TEST(result)) {
9604 return Qnil;
9605 }
9606
9607 int mask = RB_NUM2INT(result);
9608
9609 if (mask & event) {
9610 if (return_io)
9611 return io;
9612 else
9613 return result;
9614 }
9615 else {
9616 return Qfalse;
9617 }
9618}
9619
9620/*
9621 * call-seq:
9622 * io.wait_readable -> truthy or falsy
9623 * io.wait_readable(timeout) -> truthy or falsy
9624 *
9625 * Waits until IO is readable and returns a truthy value, or a falsy
9626 * value when times out. Returns a truthy value immediately when
9627 * buffered data is available.
9628 */
9629
9630static VALUE
9631io_wait_readable(int argc, VALUE *argv, VALUE io)
9632{
9633 rb_io_t *fptr;
9634
9635 RB_IO_POINTER(io, fptr);
9637
9638 if (rb_io_read_pending(fptr)) return Qtrue;
9639
9640 rb_check_arity(argc, 0, 1);
9641 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9642
9643 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9644}
9645
9646/*
9647 * call-seq:
9648 * io.wait_writable -> truthy or falsy
9649 * io.wait_writable(timeout) -> truthy or falsy
9650 *
9651 * Waits until IO is writable and returns a truthy value or a falsy
9652 * value when times out.
9653 */
9654static VALUE
9655io_wait_writable(int argc, VALUE *argv, VALUE io)
9656{
9657 rb_io_t *fptr;
9658
9659 RB_IO_POINTER(io, fptr);
9661
9662 rb_check_arity(argc, 0, 1);
9663 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9664
9665 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9666}
9667
9668/*
9669 * call-seq:
9670 * io.wait_priority -> truthy or falsy
9671 * io.wait_priority(timeout) -> truthy or falsy
9672 *
9673 * Waits until IO is priority and returns a truthy value or a falsy
9674 * value when times out. Priority data is sent and received using
9675 * the Socket::MSG_OOB flag and is typically limited to streams.
9676 */
9677static VALUE
9678io_wait_priority(int argc, VALUE *argv, VALUE io)
9679{
9680 rb_io_t *fptr = NULL;
9681
9682 RB_IO_POINTER(io, fptr);
9684
9685 if (rb_io_read_pending(fptr)) return Qtrue;
9686
9687 rb_check_arity(argc, 0, 1);
9688 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9689
9690 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9691}
9692
9693static int
9694wait_mode_sym(VALUE mode)
9695{
9696 if (mode == ID2SYM(rb_intern("r"))) {
9697 return RB_WAITFD_IN;
9698 }
9699 if (mode == ID2SYM(rb_intern("read"))) {
9700 return RB_WAITFD_IN;
9701 }
9702 if (mode == ID2SYM(rb_intern("readable"))) {
9703 return RB_WAITFD_IN;
9704 }
9705 if (mode == ID2SYM(rb_intern("w"))) {
9706 return RB_WAITFD_OUT;
9707 }
9708 if (mode == ID2SYM(rb_intern("write"))) {
9709 return RB_WAITFD_OUT;
9710 }
9711 if (mode == ID2SYM(rb_intern("writable"))) {
9712 return RB_WAITFD_OUT;
9713 }
9714 if (mode == ID2SYM(rb_intern("rw"))) {
9715 return RB_WAITFD_IN|RB_WAITFD_OUT;
9716 }
9717 if (mode == ID2SYM(rb_intern("read_write"))) {
9718 return RB_WAITFD_IN|RB_WAITFD_OUT;
9719 }
9720 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9721 return RB_WAITFD_IN|RB_WAITFD_OUT;
9722 }
9723
9724 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9725}
9726
9727static inline rb_io_event_t
9728io_event_from_value(VALUE value)
9729{
9730 int events = RB_NUM2INT(value);
9731
9732 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9733
9734 return events;
9735}
9736
9737/*
9738 * call-seq:
9739 * io.wait(events, timeout) -> event mask, false or nil
9740 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9741 *
9742 * Waits until the IO becomes ready for the specified events and returns the
9743 * subset of events that become ready, or a falsy value when times out.
9744 *
9745 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9746 * +IO::PRIORITY+.
9747 *
9748 * Returns an event mask (truthy value) immediately when buffered data is available.
9749 *
9750 * Optional parameter +mode+ is one of +:read+, +:write+, or
9751 * +:read_write+.
9752 */
9753
9754static VALUE
9755io_wait(int argc, VALUE *argv, VALUE io)
9756{
9757 VALUE timeout = Qundef;
9758 rb_io_event_t events = 0;
9759 int return_io = 0;
9760
9761 // The documented signature for this method is actually incorrect.
9762 // A single timeout is allowed in any position, and multiple symbols can be given.
9763 // Whether this is intentional or not, I don't know, and as such I consider this to
9764 // be a legacy/slow path.
9765 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9766 // We'd prefer to return the actual mask, but this form would return the io itself:
9767 return_io = 1;
9768
9769 // Slow/messy path:
9770 for (int i = 0; i < argc; i += 1) {
9771 if (RB_SYMBOL_P(argv[i])) {
9772 events |= wait_mode_sym(argv[i]);
9773 }
9774 else if (UNDEF_P(timeout)) {
9775 rb_time_interval(timeout = argv[i]);
9776 }
9777 else {
9778 rb_raise(rb_eArgError, "timeout given more than once");
9779 }
9780 }
9781
9782 if (UNDEF_P(timeout)) timeout = Qnil;
9783
9784 if (events == 0) {
9785 events = RUBY_IO_READABLE;
9786 }
9787 }
9788 else /* argc == 2 and neither are symbols */ {
9789 // This is the fast path:
9790 events = io_event_from_value(argv[0]);
9791 timeout = argv[1];
9792 }
9793
9794 if (events & RUBY_IO_READABLE) {
9795 rb_io_t *fptr = NULL;
9796 RB_IO_POINTER(io, fptr);
9797
9798 if (rb_io_read_pending(fptr)) {
9799 // This was the original behaviour:
9800 if (return_io) return Qtrue;
9801 // New behaviour always returns an event mask:
9802 else return RB_INT2NUM(RUBY_IO_READABLE);
9803 }
9804 }
9805
9806 return io_wait_event(io, events, timeout, return_io);
9807}
9808
9809static void
9810argf_mark(void *ptr)
9811{
9812 struct argf *p = ptr;
9813 rb_gc_mark(p->filename);
9814 rb_gc_mark(p->current_file);
9815 rb_gc_mark(p->argv);
9816 rb_gc_mark(p->inplace);
9817 rb_gc_mark(p->encs.ecopts);
9818}
9819
9820static size_t
9821argf_memsize(const void *ptr)
9822{
9823 const struct argf *p = ptr;
9824 size_t size = sizeof(*p);
9825 return size;
9826}
9827
9828static const rb_data_type_t argf_type = {
9829 "ARGF",
9830 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9831 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9832};
9833
9834static inline void
9835argf_init(struct argf *p, VALUE v)
9836{
9837 p->filename = Qnil;
9838 p->current_file = Qnil;
9839 p->lineno = 0;
9840 p->argv = v;
9841}
9842
9843static VALUE
9844argf_alloc(VALUE klass)
9845{
9846 struct argf *p;
9847 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9848
9849 argf_init(p, Qnil);
9850 return argf;
9851}
9852
9853#undef rb_argv
9854
9855/* :nodoc: */
9856static VALUE
9857argf_initialize(VALUE argf, VALUE argv)
9858{
9859 memset(&ARGF, 0, sizeof(ARGF));
9860 argf_init(&ARGF, argv);
9861
9862 return argf;
9863}
9864
9865/* :nodoc: */
9866static VALUE
9867argf_initialize_copy(VALUE argf, VALUE orig)
9868{
9869 if (!OBJ_INIT_COPY(argf, orig)) return argf;
9870 ARGF = argf_of(orig);
9871 ARGF.argv = rb_obj_dup(ARGF.argv);
9872 return argf;
9873}
9874
9875/*
9876 * call-seq:
9877 * ARGF.lineno = integer -> integer
9878 *
9879 * Sets the line number of ARGF as a whole to the given Integer.
9880 *
9881 * ARGF sets the line number automatically as you read data, so normally
9882 * you will not need to set it explicitly. To access the current line number
9883 * use ARGF.lineno.
9884 *
9885 * For example:
9886 *
9887 * ARGF.lineno #=> 0
9888 * ARGF.readline #=> "This is line 1\n"
9889 * ARGF.lineno #=> 1
9890 * ARGF.lineno = 0 #=> 0
9891 * ARGF.lineno #=> 0
9892 */
9893static VALUE
9894argf_set_lineno(VALUE argf, VALUE val)
9895{
9896 ARGF.lineno = NUM2INT(val);
9897 ARGF.last_lineno = ARGF.lineno;
9898 return val;
9899}
9900
9901/*
9902 * call-seq:
9903 * ARGF.lineno -> integer
9904 *
9905 * Returns the current line number of ARGF as a whole. This value
9906 * can be set manually with ARGF.lineno=.
9907 *
9908 * For example:
9909 *
9910 * ARGF.lineno #=> 0
9911 * ARGF.readline #=> "This is line 1\n"
9912 * ARGF.lineno #=> 1
9913 */
9914static VALUE
9915argf_lineno(VALUE argf)
9916{
9917 return INT2FIX(ARGF.lineno);
9918}
9919
9920static VALUE
9921argf_forward(int argc, VALUE *argv, VALUE argf)
9922{
9923 return forward_current(rb_frame_this_func(), argc, argv);
9924}
9925
9926#define next_argv() argf_next_argv(argf)
9927#define ARGF_GENERIC_INPUT_P() \
9928 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
9929#define ARGF_FORWARD(argc, argv) do {\
9930 if (ARGF_GENERIC_INPUT_P())\
9931 return argf_forward((argc), (argv), argf);\
9932} while (0)
9933#define NEXT_ARGF_FORWARD(argc, argv) do {\
9934 if (!next_argv()) return Qnil;\
9935 ARGF_FORWARD((argc), (argv));\
9936} while (0)
9937
9938static void
9939argf_close(VALUE argf)
9940{
9941 VALUE file = ARGF.current_file;
9942 if (file == rb_stdin) return;
9943 if (RB_TYPE_P(file, T_FILE)) {
9944 rb_io_set_write_io(file, Qnil);
9945 }
9946 io_close(file);
9947 ARGF.init_p = -1;
9948}
9949
9950static int
9951argf_next_argv(VALUE argf)
9952{
9953 char *fn;
9954 rb_io_t *fptr;
9955 int stdout_binmode = 0;
9956 int fmode;
9957
9958 VALUE r_stdout = rb_ractor_stdout();
9959
9960 if (RB_TYPE_P(r_stdout, T_FILE)) {
9961 GetOpenFile(r_stdout, fptr);
9962 if (fptr->mode & FMODE_BINMODE)
9963 stdout_binmode = 1;
9964 }
9965
9966 if (ARGF.init_p == 0) {
9967 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
9968 ARGF.next_p = 1;
9969 }
9970 else {
9971 ARGF.next_p = -1;
9972 }
9973 ARGF.init_p = 1;
9974 }
9975 else {
9976 if (NIL_P(ARGF.argv)) {
9977 ARGF.next_p = -1;
9978 }
9979 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
9980 ARGF.next_p = 1;
9981 }
9982 }
9983
9984 if (ARGF.next_p == 1) {
9985 if (ARGF.init_p == 1) argf_close(argf);
9986 retry:
9987 if (RARRAY_LEN(ARGF.argv) > 0) {
9988 VALUE filename = rb_ary_shift(ARGF.argv);
9989 FilePathValue(filename);
9990 ARGF.filename = filename;
9991 filename = rb_str_encode_ospath(filename);
9992 fn = StringValueCStr(filename);
9993 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
9994 ARGF.current_file = rb_stdin;
9995 if (ARGF.inplace) {
9996 rb_warn("Can't do inplace edit for stdio; skipping");
9997 goto retry;
9998 }
9999 }
10000 else {
10001 VALUE write_io = Qnil;
10002 int fr = rb_sysopen(filename, O_RDONLY, 0);
10003
10004 if (ARGF.inplace) {
10005 struct stat st;
10006#ifndef NO_SAFE_RENAME
10007 struct stat st2;
10008#endif
10009 VALUE str;
10010 int fw;
10011
10012 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10013 rb_io_close(r_stdout);
10014 }
10015 fstat(fr, &st);
10016 str = filename;
10017 if (!NIL_P(ARGF.inplace)) {
10018 VALUE suffix = ARGF.inplace;
10019 str = rb_str_dup(str);
10020 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10021 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10022 rb_enc_get(suffix), 0, Qnil))) {
10023 rb_str_append(str, suffix);
10024 }
10025#ifdef NO_SAFE_RENAME
10026 (void)close(fr);
10027 (void)unlink(RSTRING_PTR(str));
10028 if (rename(fn, RSTRING_PTR(str)) < 0) {
10029 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10030 filename, str, strerror(errno));
10031 goto retry;
10032 }
10033 fr = rb_sysopen(str, O_RDONLY, 0);
10034#else
10035 if (rename(fn, RSTRING_PTR(str)) < 0) {
10036 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10037 filename, str, strerror(errno));
10038 close(fr);
10039 goto retry;
10040 }
10041#endif
10042 }
10043 else {
10044#ifdef NO_SAFE_RENAME
10045 rb_fatal("Can't do inplace edit without backup");
10046#else
10047 if (unlink(fn) < 0) {
10048 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10049 filename, strerror(errno));
10050 close(fr);
10051 goto retry;
10052 }
10053#endif
10054 }
10055 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10056#ifndef NO_SAFE_RENAME
10057 fstat(fw, &st2);
10058#ifdef HAVE_FCHMOD
10059 fchmod(fw, st.st_mode);
10060#else
10061 chmod(fn, st.st_mode);
10062#endif
10063 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10064 int err;
10065#ifdef HAVE_FCHOWN
10066 err = fchown(fw, st.st_uid, st.st_gid);
10067#else
10068 err = chown(fn, st.st_uid, st.st_gid);
10069#endif
10070 if (err && getuid() == 0 && st2.st_uid == 0) {
10071 const char *wkfn = RSTRING_PTR(filename);
10072 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10073 filename, str, strerror(errno));
10074 (void)close(fr);
10075 (void)close(fw);
10076 (void)unlink(wkfn);
10077 goto retry;
10078 }
10079 }
10080#endif
10081 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10082 rb_ractor_stdout_set(write_io);
10083 if (stdout_binmode) rb_io_binmode(rb_stdout);
10084 }
10085 fmode = FMODE_READABLE;
10086 if (!ARGF.binmode) {
10087 fmode |= DEFAULT_TEXTMODE;
10088 }
10089 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10090 if (!NIL_P(write_io)) {
10091 rb_io_set_write_io(ARGF.current_file, write_io);
10092 }
10093 RB_GC_GUARD(filename);
10094 }
10095 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10096 GetOpenFile(ARGF.current_file, fptr);
10097 if (ARGF.encs.enc) {
10098 fptr->encs = ARGF.encs;
10099 clear_codeconv(fptr);
10100 }
10101 else {
10102 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10103 if (!ARGF.binmode) {
10105#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10106 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10107#endif
10108 }
10109 }
10110 ARGF.next_p = 0;
10111 }
10112 else {
10113 ARGF.next_p = 1;
10114 return FALSE;
10115 }
10116 }
10117 else if (ARGF.next_p == -1) {
10118 ARGF.current_file = rb_stdin;
10119 ARGF.filename = rb_str_new2("-");
10120 if (ARGF.inplace) {
10121 rb_warn("Can't do inplace edit for stdio");
10122 rb_ractor_stdout_set(orig_stdout);
10123 }
10124 }
10125 if (ARGF.init_p == -1) ARGF.init_p = 1;
10126 return TRUE;
10127}
10128
10129static VALUE
10130argf_getline(int argc, VALUE *argv, VALUE argf)
10131{
10132 VALUE line;
10133 long lineno = ARGF.lineno;
10134
10135 retry:
10136 if (!next_argv()) return Qnil;
10137 if (ARGF_GENERIC_INPUT_P()) {
10138 line = forward_current(idGets, argc, argv);
10139 }
10140 else {
10141 if (argc == 0 && rb_rs == rb_default_rs) {
10142 line = rb_io_gets(ARGF.current_file);
10143 }
10144 else {
10145 line = rb_io_getline(argc, argv, ARGF.current_file);
10146 }
10147 if (NIL_P(line) && ARGF.next_p != -1) {
10148 argf_close(argf);
10149 ARGF.next_p = 1;
10150 goto retry;
10151 }
10152 }
10153 if (!NIL_P(line)) {
10154 ARGF.lineno = ++lineno;
10155 ARGF.last_lineno = ARGF.lineno;
10156 }
10157 return line;
10158}
10159
10160static VALUE
10161argf_lineno_getter(ID id, VALUE *var)
10162{
10163 VALUE argf = *var;
10164 return INT2FIX(ARGF.last_lineno);
10165}
10166
10167static void
10168argf_lineno_setter(VALUE val, ID id, VALUE *var)
10169{
10170 VALUE argf = *var;
10171 int n = NUM2INT(val);
10172 ARGF.last_lineno = ARGF.lineno = n;
10173}
10174
10175void
10176rb_reset_argf_lineno(long n)
10177{
10178 ARGF.last_lineno = ARGF.lineno = n;
10179}
10180
10181static VALUE argf_gets(int, VALUE *, VALUE);
10182
10183/*
10184 * call-seq:
10185 * gets(sep=$/ [, getline_args]) -> string or nil
10186 * gets(limit [, getline_args]) -> string or nil
10187 * gets(sep, limit [, getline_args]) -> string or nil
10188 *
10189 * Returns (and assigns to <code>$_</code>) the next line from the list
10190 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10191 * no files are present on the command line. Returns +nil+ at end of
10192 * file. The optional argument specifies the record separator. The
10193 * separator is included with the contents of each record. A separator
10194 * of +nil+ reads the entire contents, and a zero-length separator
10195 * reads the input one paragraph at a time, where paragraphs are
10196 * divided by two consecutive newlines. If the first argument is an
10197 * integer, or optional second argument is given, the returning string
10198 * would not be longer than the given value in bytes. If multiple
10199 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10200 * the contents one file at a time.
10201 *
10202 * ARGV << "testfile"
10203 * print while gets
10204 *
10205 * <em>produces:</em>
10206 *
10207 * This is line one
10208 * This is line two
10209 * This is line three
10210 * And so on...
10211 *
10212 * The style of programming using <code>$_</code> as an implicit
10213 * parameter is gradually losing favor in the Ruby community.
10214 */
10215
10216static VALUE
10217rb_f_gets(int argc, VALUE *argv, VALUE recv)
10218{
10219 if (recv == argf) {
10220 return argf_gets(argc, argv, argf);
10221 }
10222 return forward(argf, idGets, argc, argv);
10223}
10224
10225/*
10226 * call-seq:
10227 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10228 * ARGF.gets(limit [, getline_args]) -> string or nil
10229 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10230 *
10231 * Returns the next line from the current file in ARGF.
10232 *
10233 * By default lines are assumed to be separated by <code>$/</code>;
10234 * to use a different character as a separator, supply it as a String
10235 * for the _sep_ argument.
10236 *
10237 * The optional _limit_ argument specifies how many characters of each line
10238 * to return. By default all characters are returned.
10239 *
10240 * See IO.readlines for details about getline_args.
10241 *
10242 */
10243static VALUE
10244argf_gets(int argc, VALUE *argv, VALUE argf)
10245{
10246 VALUE line;
10247
10248 line = argf_getline(argc, argv, argf);
10249 rb_lastline_set(line);
10250
10251 return line;
10252}
10253
10254VALUE
10256{
10257 VALUE line;
10258
10259 if (rb_rs != rb_default_rs) {
10260 return rb_f_gets(0, 0, argf);
10261 }
10262
10263 retry:
10264 if (!next_argv()) return Qnil;
10265 line = rb_io_gets(ARGF.current_file);
10266 if (NIL_P(line) && ARGF.next_p != -1) {
10267 rb_io_close(ARGF.current_file);
10268 ARGF.next_p = 1;
10269 goto retry;
10270 }
10271 rb_lastline_set(line);
10272 if (!NIL_P(line)) {
10273 ARGF.lineno++;
10274 ARGF.last_lineno = ARGF.lineno;
10275 }
10276
10277 return line;
10278}
10279
10280static VALUE argf_readline(int, VALUE *, VALUE);
10281
10282/*
10283 * call-seq:
10284 * readline(sep = $/, chomp: false) -> string
10285 * readline(limit, chomp: false) -> string
10286 * readline(sep, limit, chomp: false) -> string
10287 *
10288 * Equivalent to method Kernel#gets, except that it raises an exception
10289 * if called at end-of-stream:
10290 *
10291 * $ cat t.txt | ruby -e "p readlines; readline"
10292 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10293 * in `readline': end of file reached (EOFError)
10294 *
10295 * Optional keyword argument +chomp+ specifies whether line separators
10296 * are to be omitted.
10297 */
10298
10299static VALUE
10300rb_f_readline(int argc, VALUE *argv, VALUE recv)
10301{
10302 if (recv == argf) {
10303 return argf_readline(argc, argv, argf);
10304 }
10305 return forward(argf, rb_intern("readline"), argc, argv);
10306}
10307
10308
10309/*
10310 * call-seq:
10311 * ARGF.readline(sep=$/) -> string
10312 * ARGF.readline(limit) -> string
10313 * ARGF.readline(sep, limit) -> string
10314 *
10315 * Returns the next line from the current file in ARGF.
10316 *
10317 * By default lines are assumed to be separated by <code>$/</code>;
10318 * to use a different character as a separator, supply it as a String
10319 * for the _sep_ argument.
10320 *
10321 * The optional _limit_ argument specifies how many characters of each line
10322 * to return. By default all characters are returned.
10323 *
10324 * An EOFError is raised at the end of the file.
10325 */
10326static VALUE
10327argf_readline(int argc, VALUE *argv, VALUE argf)
10328{
10329 VALUE line;
10330
10331 if (!next_argv()) rb_eof_error();
10332 ARGF_FORWARD(argc, argv);
10333 line = argf_gets(argc, argv, argf);
10334 if (NIL_P(line)) {
10335 rb_eof_error();
10336 }
10337
10338 return line;
10339}
10340
10341static VALUE argf_readlines(int, VALUE *, VALUE);
10342
10343/*
10344 * call-seq:
10345 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10346 * readlines(limit, chomp: false, **enc_opts) -> array
10347 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10348 *
10349 * Returns an array containing the lines returned by calling
10350 * Kernel#gets until the end-of-stream is reached;
10351 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10352 *
10353 * With only string argument +sep+ given,
10354 * returns the remaining lines as determined by line separator +sep+,
10355 * or +nil+ if none;
10356 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10357 *
10358 * # Default separator.
10359 * $ cat t.txt | ruby -e "p readlines"
10360 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10361 *
10362 * # Specified separator.
10363 * $ cat t.txt | ruby -e "p readlines 'li'"
10364 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10365 *
10366 * # Get-all separator.
10367 * $ cat t.txt | ruby -e "p readlines nil"
10368 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10369 *
10370 * # Get-paragraph separator.
10371 * $ cat t.txt | ruby -e "p readlines ''"
10372 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10373 *
10374 * With only integer argument +limit+ given,
10375 * limits the number of bytes in the line;
10376 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10377 *
10378 * $cat t.txt | ruby -e "p readlines 10"
10379 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10380 *
10381 * $cat t.txt | ruby -e "p readlines 11"
10382 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10383 *
10384 * $cat t.txt | ruby -e "p readlines 12"
10385 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10386 *
10387 * With arguments +sep+ and +limit+ given, combines the two behaviors;
10388 * see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit].
10389 *
10390 * Optional keyword argument +chomp+ specifies whether line separators
10391 * are to be omitted:
10392 *
10393 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10394 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10395 *
10396 * Optional keyword arguments +enc_opts+ specify encoding options;
10397 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10398 *
10399 */
10400
10401static VALUE
10402rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10403{
10404 if (recv == argf) {
10405 return argf_readlines(argc, argv, argf);
10406 }
10407 return forward(argf, rb_intern("readlines"), argc, argv);
10408}
10409
10410/*
10411 * call-seq:
10412 * ARGF.readlines(sep = $/) -> array
10413 * ARGF.readlines(limit) -> array
10414 * ARGF.readlines(sep, limit) -> array
10415 *
10416 * ARGF.to_a(sep = $/) -> array
10417 * ARGF.to_a(limit) -> array
10418 * ARGF.to_a(sep, limit) -> array
10419 *
10420 * Reads each file in ARGF in its entirety, returning an Array containing
10421 * lines from the files. Lines are assumed to be separated by _sep_.
10422 *
10423 * lines = ARGF.readlines
10424 * lines[0] #=> "This is line one\n"
10425 */
10426static VALUE
10427argf_readlines(int argc, VALUE *argv, VALUE argf)
10428{
10429 long lineno = ARGF.lineno;
10430 VALUE lines, ary;
10431
10432 ary = rb_ary_new();
10433 while (next_argv()) {
10434 if (ARGF_GENERIC_INPUT_P()) {
10435 lines = forward_current(rb_intern("readlines"), argc, argv);
10436 }
10437 else {
10438 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10439 argf_close(argf);
10440 }
10441 ARGF.next_p = 1;
10442 rb_ary_concat(ary, lines);
10443 ARGF.lineno = lineno + RARRAY_LEN(ary);
10444 ARGF.last_lineno = ARGF.lineno;
10445 }
10446 ARGF.init_p = 0;
10447 return ary;
10448}
10449
10450/*
10451 * call-seq:
10452 * `command` -> string
10453 *
10454 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10455 * sets global variable <tt>$?</tt> to the process status.
10456 *
10457 * This method has potential security vulnerabilities if called with untrusted input;
10458 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10459 *
10460 * Examples:
10461 *
10462 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10463 * $ `echo oops && exit 99` # => "oops\n"
10464 * $ $? # => #<Process::Status: pid 17088 exit 99>
10465 * $ $?.status # => 99>
10466 *
10467 * The built-in syntax <tt>%x{...}</tt> uses this method.
10468 *
10469 */
10470
10471static VALUE
10472rb_f_backquote(VALUE obj, VALUE str)
10473{
10474 VALUE port;
10475 VALUE result;
10476 rb_io_t *fptr;
10477
10478 SafeStringValue(str);
10479 rb_last_status_clear();
10480 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10481 if (NIL_P(port)) return rb_str_new(0,0);
10482
10483 GetOpenFile(port, fptr);
10484 result = read_all(fptr, remain_size(fptr), Qnil);
10485 rb_io_close(port);
10486 RFILE(port)->fptr = NULL;
10487 rb_io_fptr_finalize(fptr);
10488 RB_GC_GUARD(port);
10489
10490 return result;
10491}
10492
10493#ifdef HAVE_SYS_SELECT_H
10494#include <sys/select.h>
10495#endif
10496
10497static VALUE
10498select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10499{
10500 VALUE res, list;
10501 rb_fdset_t *rp, *wp, *ep;
10502 rb_io_t *fptr;
10503 long i;
10504 int max = 0, n;
10505 int pending = 0;
10506 struct timeval timerec;
10507
10508 if (!NIL_P(read)) {
10509 Check_Type(read, T_ARRAY);
10510 for (i=0; i<RARRAY_LEN(read); i++) {
10511 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10512 rb_fd_set(fptr->fd, &fds[0]);
10513 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10514 pending++;
10515 rb_fd_set(fptr->fd, &fds[3]);
10516 }
10517 if (max < fptr->fd) max = fptr->fd;
10518 }
10519 if (pending) { /* no blocking if there's buffered data */
10520 timerec.tv_sec = timerec.tv_usec = 0;
10521 tp = &timerec;
10522 }
10523 rp = &fds[0];
10524 }
10525 else
10526 rp = 0;
10527
10528 if (!NIL_P(write)) {
10529 Check_Type(write, T_ARRAY);
10530 for (i=0; i<RARRAY_LEN(write); i++) {
10531 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10532 GetOpenFile(write_io, fptr);
10533 rb_fd_set(fptr->fd, &fds[1]);
10534 if (max < fptr->fd) max = fptr->fd;
10535 }
10536 wp = &fds[1];
10537 }
10538 else
10539 wp = 0;
10540
10541 if (!NIL_P(except)) {
10542 Check_Type(except, T_ARRAY);
10543 for (i=0; i<RARRAY_LEN(except); i++) {
10544 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10545 VALUE write_io = GetWriteIO(io);
10546 GetOpenFile(io, fptr);
10547 rb_fd_set(fptr->fd, &fds[2]);
10548 if (max < fptr->fd) max = fptr->fd;
10549 if (io != write_io) {
10550 GetOpenFile(write_io, fptr);
10551 rb_fd_set(fptr->fd, &fds[2]);
10552 if (max < fptr->fd) max = fptr->fd;
10553 }
10554 }
10555 ep = &fds[2];
10556 }
10557 else {
10558 ep = 0;
10559 }
10560
10561 max++;
10562
10563 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10564 if (n < 0) {
10565 rb_sys_fail(0);
10566 }
10567 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10568
10569 res = rb_ary_new2(3);
10570 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10571 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10572 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10573
10574 if (rp) {
10575 list = RARRAY_AREF(res, 0);
10576 for (i=0; i< RARRAY_LEN(read); i++) {
10577 VALUE obj = rb_ary_entry(read, i);
10578 VALUE io = rb_io_get_io(obj);
10579 GetOpenFile(io, fptr);
10580 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10581 rb_fd_isset(fptr->fd, &fds[3])) {
10582 rb_ary_push(list, obj);
10583 }
10584 }
10585 }
10586
10587 if (wp) {
10588 list = RARRAY_AREF(res, 1);
10589 for (i=0; i< RARRAY_LEN(write); i++) {
10590 VALUE obj = rb_ary_entry(write, i);
10591 VALUE io = rb_io_get_io(obj);
10592 VALUE write_io = GetWriteIO(io);
10593 GetOpenFile(write_io, fptr);
10594 if (rb_fd_isset(fptr->fd, &fds[1])) {
10595 rb_ary_push(list, obj);
10596 }
10597 }
10598 }
10599
10600 if (ep) {
10601 list = RARRAY_AREF(res, 2);
10602 for (i=0; i< RARRAY_LEN(except); i++) {
10603 VALUE obj = rb_ary_entry(except, i);
10604 VALUE io = rb_io_get_io(obj);
10605 VALUE write_io = GetWriteIO(io);
10606 GetOpenFile(io, fptr);
10607 if (rb_fd_isset(fptr->fd, &fds[2])) {
10608 rb_ary_push(list, obj);
10609 }
10610 else if (io != write_io) {
10611 GetOpenFile(write_io, fptr);
10612 if (rb_fd_isset(fptr->fd, &fds[2])) {
10613 rb_ary_push(list, obj);
10614 }
10615 }
10616 }
10617 }
10618
10619 return res; /* returns an empty array on interrupt */
10620}
10621
10623 VALUE read, write, except;
10624 struct timeval *timeout;
10625 rb_fdset_t fdsets[4];
10626};
10627
10628static VALUE
10629select_call(VALUE arg)
10630{
10631 struct select_args *p = (struct select_args *)arg;
10632
10633 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10634}
10635
10636static VALUE
10637select_end(VALUE arg)
10638{
10639 struct select_args *p = (struct select_args *)arg;
10640 int i;
10641
10642 for (i = 0; i < numberof(p->fdsets); ++i)
10643 rb_fd_term(&p->fdsets[i]);
10644 return Qnil;
10645}
10646
10647static VALUE sym_normal, sym_sequential, sym_random,
10648 sym_willneed, sym_dontneed, sym_noreuse;
10649
10650#ifdef HAVE_POSIX_FADVISE
10651struct io_advise_struct {
10652 int fd;
10653 int advice;
10654 rb_off_t offset;
10655 rb_off_t len;
10656};
10657
10658static VALUE
10659io_advise_internal(void *arg)
10660{
10661 struct io_advise_struct *ptr = arg;
10662 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10663}
10664
10665static VALUE
10666io_advise_sym_to_const(VALUE sym)
10667{
10668#ifdef POSIX_FADV_NORMAL
10669 if (sym == sym_normal)
10670 return INT2NUM(POSIX_FADV_NORMAL);
10671#endif
10672
10673#ifdef POSIX_FADV_RANDOM
10674 if (sym == sym_random)
10675 return INT2NUM(POSIX_FADV_RANDOM);
10676#endif
10677
10678#ifdef POSIX_FADV_SEQUENTIAL
10679 if (sym == sym_sequential)
10680 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10681#endif
10682
10683#ifdef POSIX_FADV_WILLNEED
10684 if (sym == sym_willneed)
10685 return INT2NUM(POSIX_FADV_WILLNEED);
10686#endif
10687
10688#ifdef POSIX_FADV_DONTNEED
10689 if (sym == sym_dontneed)
10690 return INT2NUM(POSIX_FADV_DONTNEED);
10691#endif
10692
10693#ifdef POSIX_FADV_NOREUSE
10694 if (sym == sym_noreuse)
10695 return INT2NUM(POSIX_FADV_NOREUSE);
10696#endif
10697
10698 return Qnil;
10699}
10700
10701static VALUE
10702do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10703{
10704 int rv;
10705 struct io_advise_struct ias;
10706 VALUE num_adv;
10707
10708 num_adv = io_advise_sym_to_const(advice);
10709
10710 /*
10711 * The platform doesn't support this hint. We don't raise exception, instead
10712 * silently ignore it. Because IO::advise is only hint.
10713 */
10714 if (NIL_P(num_adv))
10715 return Qnil;
10716
10717 ias.fd = fptr->fd;
10718 ias.advice = NUM2INT(num_adv);
10719 ias.offset = offset;
10720 ias.len = len;
10721
10722 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
10723 if (rv && rv != ENOSYS) {
10724 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10725 it returns the error code. */
10726 VALUE message = rb_sprintf("%"PRIsVALUE" "
10727 "(%"PRI_OFFT_PREFIX"d, "
10728 "%"PRI_OFFT_PREFIX"d, "
10729 "%"PRIsVALUE")",
10730 fptr->pathv, offset, len, advice);
10731 rb_syserr_fail_str(rv, message);
10732 }
10733
10734 return Qnil;
10735}
10736
10737#endif /* HAVE_POSIX_FADVISE */
10738
10739static void
10740advice_arg_check(VALUE advice)
10741{
10742 if (!SYMBOL_P(advice))
10743 rb_raise(rb_eTypeError, "advice must be a Symbol");
10744
10745 if (advice != sym_normal &&
10746 advice != sym_sequential &&
10747 advice != sym_random &&
10748 advice != sym_willneed &&
10749 advice != sym_dontneed &&
10750 advice != sym_noreuse) {
10751 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10752 }
10753}
10754
10755/*
10756 * call-seq:
10757 * advise(advice, offset = 0, len = 0) -> nil
10758 *
10759 * Invokes Posix system call
10760 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10761 * which announces an intention to access data from the current file
10762 * in a particular manner.
10763 *
10764 * The arguments and results are platform-dependent.
10765 *
10766 * The relevant data is specified by:
10767 *
10768 * - +offset+: The offset of the first byte of data.
10769 * - +len+: The number of bytes to be accessed;
10770 * if +len+ is zero, or is larger than the number of bytes remaining,
10771 * all remaining bytes will be accessed.
10772 *
10773 * Argument +advice+ is one of the following symbols:
10774 *
10775 * - +:normal+: The application has no advice to give
10776 * about its access pattern for the specified data.
10777 * If no advice is given for an open file, this is the default assumption.
10778 * - +:sequential+: The application expects to access the specified data sequentially
10779 * (with lower offsets read before higher ones).
10780 * - +:random+: The specified data will be accessed in random order.
10781 * - +:noreuse+: The specified data will be accessed only once.
10782 * - +:willneed+: The specified data will be accessed in the near future.
10783 * - +:dontneed+: The specified data will not be accessed in the near future.
10784 *
10785 * Not implemented on all platforms.
10786 *
10787 */
10788static VALUE
10789rb_io_advise(int argc, VALUE *argv, VALUE io)
10790{
10791 VALUE advice, offset, len;
10792 rb_off_t off, l;
10793 rb_io_t *fptr;
10794
10795 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10796 advice_arg_check(advice);
10797
10798 io = GetWriteIO(io);
10799 GetOpenFile(io, fptr);
10800
10801 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10802 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10803
10804#ifdef HAVE_POSIX_FADVISE
10805 return do_io_advise(fptr, advice, off, l);
10806#else
10807 ((void)off, (void)l); /* Ignore all hint */
10808 return Qnil;
10809#endif
10810}
10811
10812/*
10813 * call-seq:
10814 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10815 *
10816 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10817 * which monitors multiple file descriptors,
10818 * waiting until one or more of the file descriptors
10819 * becomes ready for some class of I/O operation.
10820 *
10821 * Not implemented on all platforms.
10822 *
10823 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10824 * is an array of IO objects.
10825 *
10826 * Argument +timeout+ is an integer timeout interval in seconds.
10827 *
10828 * The method monitors the \IO objects given in all three arrays,
10829 * waiting for some to be ready;
10830 * returns a 3-element array whose elements are:
10831 *
10832 * - An array of the objects in +read_ios+ that are ready for reading.
10833 * - An array of the objects in +write_ios+ that are ready for writing.
10834 * - An array of the objects in +error_ios+ have pending exceptions.
10835 *
10836 * If no object becomes ready within the given +timeout+, +nil+ is returned.
10837 *
10838 * \IO.select peeks the buffer of \IO objects for testing readability.
10839 * If the \IO buffer is not empty, \IO.select immediately notifies
10840 * readability. This "peek" only happens for \IO objects. It does not
10841 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10842 *
10843 * The best way to use \IO.select is invoking it after non-blocking
10844 * methods such as #read_nonblock, #write_nonblock, etc. The methods
10845 * raise an exception which is extended by IO::WaitReadable or
10846 * IO::WaitWritable. The modules notify how the caller should wait
10847 * with \IO.select. If IO::WaitReadable is raised, the caller should
10848 * wait for reading. If IO::WaitWritable is raised, the caller should
10849 * wait for writing.
10850 *
10851 * So, blocking read (#readpartial) can be emulated using
10852 * #read_nonblock and \IO.select as follows:
10853 *
10854 * begin
10855 * result = io_like.read_nonblock(maxlen)
10856 * rescue IO::WaitReadable
10857 * IO.select([io_like])
10858 * retry
10859 * rescue IO::WaitWritable
10860 * IO.select(nil, [io_like])
10861 * retry
10862 * end
10863 *
10864 * Especially, the combination of non-blocking methods and \IO.select is
10865 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
10866 * has #to_io method to return underlying IO object. IO.select calls
10867 * #to_io to obtain the file descriptor to wait.
10868 *
10869 * This means that readability notified by \IO.select doesn't mean
10870 * readability from OpenSSL::SSL::SSLSocket object.
10871 *
10872 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
10873 * some data. \IO.select doesn't see the buffer. So \IO.select can
10874 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
10875 *
10876 * However, several more complicated situations exist.
10877 *
10878 * SSL is a protocol which is sequence of records.
10879 * The record consists of multiple bytes.
10880 * So, the remote side of SSL sends a partial record, IO.select
10881 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
10882 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
10883 *
10884 * Also, the remote side can request SSL renegotiation which forces
10885 * the local SSL engine to write some data.
10886 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
10887 * system call and it can block.
10888 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
10889 * IO::WaitWritable instead of blocking.
10890 * So, the caller should wait for ready for writability as above
10891 * example.
10892 *
10893 * The combination of non-blocking methods and \IO.select is also useful
10894 * for streams such as tty, pipe socket socket when multiple processes
10895 * read from a stream.
10896 *
10897 * Finally, Linux kernel developers don't guarantee that
10898 * readability of select(2) means readability of following read(2) even
10899 * for a single process;
10900 * see {select(2)}[https://linux.die.net/man/2/select]
10901 *
10902 * Invoking \IO.select before IO#readpartial works well as usual.
10903 * However it is not the best way to use \IO.select.
10904 *
10905 * The writability notified by select(2) doesn't show
10906 * how many bytes are writable.
10907 * IO#write method blocks until given whole string is written.
10908 * So, <tt>IO#write(two or more bytes)</tt> can block after
10909 * writability is notified by \IO.select. IO#write_nonblock is required
10910 * to avoid the blocking.
10911 *
10912 * Blocking write (#write) can be emulated using #write_nonblock and
10913 * IO.select as follows: IO::WaitReadable should also be rescued for
10914 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
10915 *
10916 * while 0 < string.bytesize
10917 * begin
10918 * written = io_like.write_nonblock(string)
10919 * rescue IO::WaitReadable
10920 * IO.select([io_like])
10921 * retry
10922 * rescue IO::WaitWritable
10923 * IO.select(nil, [io_like])
10924 * retry
10925 * end
10926 * string = string.byteslice(written..-1)
10927 * end
10928 *
10929 * Example:
10930 *
10931 * rp, wp = IO.pipe
10932 * mesg = "ping "
10933 * 100.times {
10934 * # IO.select follows IO#read. Not the best way to use IO.select.
10935 * rs, ws, = IO.select([rp], [wp])
10936 * if r = rs[0]
10937 * ret = r.read(5)
10938 * print ret
10939 * case ret
10940 * when /ping/
10941 * mesg = "pong\n"
10942 * when /pong/
10943 * mesg = "ping "
10944 * end
10945 * end
10946 * if w = ws[0]
10947 * w.write(mesg)
10948 * end
10949 * }
10950 *
10951 * Output:
10952 *
10953 * ping pong
10954 * ping pong
10955 * ping pong
10956 * (snipped)
10957 * ping
10958 *
10959 */
10960
10961static VALUE
10962rb_f_select(int argc, VALUE *argv, VALUE obj)
10963{
10964 VALUE scheduler = rb_fiber_scheduler_current();
10965 if (scheduler != Qnil) {
10966 // It's optionally supported.
10967 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
10968 if (!UNDEF_P(result)) return result;
10969 }
10970
10971 VALUE timeout;
10972 struct select_args args;
10973 struct timeval timerec;
10974 int i;
10975
10976 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
10977 if (NIL_P(timeout)) {
10978 args.timeout = 0;
10979 }
10980 else {
10981 timerec = rb_time_interval(timeout);
10982 args.timeout = &timerec;
10983 }
10984
10985 for (i = 0; i < numberof(args.fdsets); ++i)
10986 rb_fd_init(&args.fdsets[i]);
10987
10988 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
10989}
10990
10991#ifdef IOCTL_REQ_TYPE
10992 typedef IOCTL_REQ_TYPE ioctl_req_t;
10993#else
10994 typedef int ioctl_req_t;
10995# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
10996#endif
10997
10998#ifdef HAVE_IOCTL
10999struct ioctl_arg {
11000 int fd;
11001 ioctl_req_t cmd;
11002 long narg;
11003};
11004
11005static VALUE
11006nogvl_ioctl(void *ptr)
11007{
11008 struct ioctl_arg *arg = ptr;
11009
11010 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11011}
11012
11013static int
11014do_ioctl(int fd, ioctl_req_t cmd, long narg)
11015{
11016 int retval;
11017 struct ioctl_arg arg;
11018
11019 arg.fd = fd;
11020 arg.cmd = cmd;
11021 arg.narg = narg;
11022
11023 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
11024
11025 return retval;
11026}
11027#endif
11028
11029#define DEFAULT_IOCTL_NARG_LEN (256)
11030
11031#if defined(__linux__) && defined(_IOC_SIZE)
11032static long
11033linux_iocparm_len(ioctl_req_t cmd)
11034{
11035 long len;
11036
11037 if ((cmd & 0xFFFF0000) == 0) {
11038 /* legacy and unstructured ioctl number. */
11039 return DEFAULT_IOCTL_NARG_LEN;
11040 }
11041
11042 len = _IOC_SIZE(cmd);
11043
11044 /* paranoia check for silly drivers which don't keep ioctl convention */
11045 if (len < DEFAULT_IOCTL_NARG_LEN)
11046 len = DEFAULT_IOCTL_NARG_LEN;
11047
11048 return len;
11049}
11050#endif
11051
11052#ifdef HAVE_IOCTL
11053static long
11054ioctl_narg_len(ioctl_req_t cmd)
11055{
11056 long len;
11057
11058#ifdef IOCPARM_MASK
11059#ifndef IOCPARM_LEN
11060#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11061#endif
11062#endif
11063#ifdef IOCPARM_LEN
11064 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11065#elif defined(__linux__) && defined(_IOC_SIZE)
11066 len = linux_iocparm_len(cmd);
11067#else
11068 /* otherwise guess at what's safe */
11069 len = DEFAULT_IOCTL_NARG_LEN;
11070#endif
11071
11072 return len;
11073}
11074#endif
11075
11076#ifdef HAVE_FCNTL
11077#ifdef __linux__
11078typedef long fcntl_arg_t;
11079#else
11080/* posix */
11081typedef int fcntl_arg_t;
11082#endif
11083
11084static long
11085fcntl_narg_len(ioctl_req_t cmd)
11086{
11087 long len;
11088
11089 switch (cmd) {
11090#ifdef F_DUPFD
11091 case F_DUPFD:
11092 len = sizeof(fcntl_arg_t);
11093 break;
11094#endif
11095#ifdef F_DUP2FD /* bsd specific */
11096 case F_DUP2FD:
11097 len = sizeof(int);
11098 break;
11099#endif
11100#ifdef F_DUPFD_CLOEXEC /* linux specific */
11101 case F_DUPFD_CLOEXEC:
11102 len = sizeof(fcntl_arg_t);
11103 break;
11104#endif
11105#ifdef F_GETFD
11106 case F_GETFD:
11107 len = 1;
11108 break;
11109#endif
11110#ifdef F_SETFD
11111 case F_SETFD:
11112 len = sizeof(fcntl_arg_t);
11113 break;
11114#endif
11115#ifdef F_GETFL
11116 case F_GETFL:
11117 len = 1;
11118 break;
11119#endif
11120#ifdef F_SETFL
11121 case F_SETFL:
11122 len = sizeof(fcntl_arg_t);
11123 break;
11124#endif
11125#ifdef F_GETOWN
11126 case F_GETOWN:
11127 len = 1;
11128 break;
11129#endif
11130#ifdef F_SETOWN
11131 case F_SETOWN:
11132 len = sizeof(fcntl_arg_t);
11133 break;
11134#endif
11135#ifdef F_GETOWN_EX /* linux specific */
11136 case F_GETOWN_EX:
11137 len = sizeof(struct f_owner_ex);
11138 break;
11139#endif
11140#ifdef F_SETOWN_EX /* linux specific */
11141 case F_SETOWN_EX:
11142 len = sizeof(struct f_owner_ex);
11143 break;
11144#endif
11145#ifdef F_GETLK
11146 case F_GETLK:
11147 len = sizeof(struct flock);
11148 break;
11149#endif
11150#ifdef F_SETLK
11151 case F_SETLK:
11152 len = sizeof(struct flock);
11153 break;
11154#endif
11155#ifdef F_SETLKW
11156 case F_SETLKW:
11157 len = sizeof(struct flock);
11158 break;
11159#endif
11160#ifdef F_READAHEAD /* bsd specific */
11161 case F_READAHEAD:
11162 len = sizeof(int);
11163 break;
11164#endif
11165#ifdef F_RDAHEAD /* Darwin specific */
11166 case F_RDAHEAD:
11167 len = sizeof(int);
11168 break;
11169#endif
11170#ifdef F_GETSIG /* linux specific */
11171 case F_GETSIG:
11172 len = 1;
11173 break;
11174#endif
11175#ifdef F_SETSIG /* linux specific */
11176 case F_SETSIG:
11177 len = sizeof(fcntl_arg_t);
11178 break;
11179#endif
11180#ifdef F_GETLEASE /* linux specific */
11181 case F_GETLEASE:
11182 len = 1;
11183 break;
11184#endif
11185#ifdef F_SETLEASE /* linux specific */
11186 case F_SETLEASE:
11187 len = sizeof(fcntl_arg_t);
11188 break;
11189#endif
11190#ifdef F_NOTIFY /* linux specific */
11191 case F_NOTIFY:
11192 len = sizeof(fcntl_arg_t);
11193 break;
11194#endif
11195
11196 default:
11197 len = 256;
11198 break;
11199 }
11200
11201 return len;
11202}
11203#else /* HAVE_FCNTL */
11204static long
11205fcntl_narg_len(ioctl_req_t cmd)
11206{
11207 return 0;
11208}
11209#endif /* HAVE_FCNTL */
11210
11211#define NARG_SENTINEL 17
11212
11213static long
11214setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11215{
11216 long narg = 0;
11217 VALUE arg = *argp;
11218
11219 if (!RTEST(arg)) {
11220 narg = 0;
11221 }
11222 else if (FIXNUM_P(arg)) {
11223 narg = FIX2LONG(arg);
11224 }
11225 else if (arg == Qtrue) {
11226 narg = 1;
11227 }
11228 else {
11229 VALUE tmp = rb_check_string_type(arg);
11230
11231 if (NIL_P(tmp)) {
11232 narg = NUM2LONG(arg);
11233 }
11234 else {
11235 char *ptr;
11236 long len, slen;
11237
11238 *argp = arg = tmp;
11239 len = narg_len(cmd);
11240 rb_str_modify(arg);
11241
11242 slen = RSTRING_LEN(arg);
11243 /* expand for data + sentinel. */
11244 if (slen < len+1) {
11245 rb_str_resize(arg, len+1);
11246 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11247 slen = len+1;
11248 }
11249 /* a little sanity check here */
11250 ptr = RSTRING_PTR(arg);
11251 ptr[slen - 1] = NARG_SENTINEL;
11252 narg = (long)(SIGNED_VALUE)ptr;
11253 }
11254 }
11255
11256 return narg;
11257}
11258
11259static VALUE
11260finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11261{
11262 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11263 if (RB_TYPE_P(arg, T_STRING)) {
11264 char *ptr;
11265 long slen;
11266 RSTRING_GETMEM(arg, ptr, slen);
11267 if (ptr[slen-1] != NARG_SENTINEL)
11268 rb_raise(rb_eArgError, "return value overflowed string");
11269 ptr[slen-1] = '\0';
11270 }
11271
11272 return INT2NUM(retval);
11273}
11274
11275#ifdef HAVE_IOCTL
11276static VALUE
11277rb_ioctl(VALUE io, VALUE req, VALUE arg)
11278{
11279 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11280 rb_io_t *fptr;
11281 long narg;
11282 int retval;
11283
11284 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11285 GetOpenFile(io, fptr);
11286 retval = do_ioctl(fptr->fd, cmd, narg);
11287 return finish_narg(retval, arg, fptr);
11288}
11289
11290/*
11291 * call-seq:
11292 * ioctl(integer_cmd, argument) -> integer
11293 *
11294 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11295 * which issues a low-level command to an I/O device.
11296 *
11297 * Issues a low-level command to an I/O device.
11298 * The arguments and returned value are platform-dependent.
11299 * The effect of the call is platform-dependent.
11300 *
11301 * If argument +argument+ is an integer, it is passed directly;
11302 * if it is a string, it is interpreted as a binary sequence of bytes.
11303 *
11304 * Not implemented on all platforms.
11305 *
11306 */
11307
11308static VALUE
11309rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11310{
11311 VALUE req, arg;
11312
11313 rb_scan_args(argc, argv, "11", &req, &arg);
11314 return rb_ioctl(io, req, arg);
11315}
11316#else
11317#define rb_io_ioctl rb_f_notimplement
11318#endif
11319
11320#ifdef HAVE_FCNTL
11321struct fcntl_arg {
11322 int fd;
11323 int cmd;
11324 long narg;
11325};
11326
11327static VALUE
11328nogvl_fcntl(void *ptr)
11329{
11330 struct fcntl_arg *arg = ptr;
11331
11332#if defined(F_DUPFD)
11333 if (arg->cmd == F_DUPFD)
11334 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11335#endif
11336 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11337}
11338
11339static int
11340do_fcntl(int fd, int cmd, long narg)
11341{
11342 int retval;
11343 struct fcntl_arg arg;
11344
11345 arg.fd = fd;
11346 arg.cmd = cmd;
11347 arg.narg = narg;
11348
11349 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
11350 if (retval != -1) {
11351 switch (cmd) {
11352#if defined(F_DUPFD)
11353 case F_DUPFD:
11354#endif
11355#if defined(F_DUPFD_CLOEXEC)
11356 case F_DUPFD_CLOEXEC:
11357#endif
11358 rb_update_max_fd(retval);
11359 }
11360 }
11361
11362 return retval;
11363}
11364
11365static VALUE
11366rb_fcntl(VALUE io, VALUE req, VALUE arg)
11367{
11368 int cmd = NUM2INT(req);
11369 rb_io_t *fptr;
11370 long narg;
11371 int retval;
11372
11373 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11374 GetOpenFile(io, fptr);
11375 retval = do_fcntl(fptr->fd, cmd, narg);
11376 return finish_narg(retval, arg, fptr);
11377}
11378
11379/*
11380 * call-seq:
11381 * fcntl(integer_cmd, argument) -> integer
11382 *
11383 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11384 * which provides a mechanism for issuing low-level commands to control or query
11385 * a file-oriented I/O stream. Arguments and results are platform
11386 * dependent.
11387 *
11388 * If +argument is a number, its value is passed directly;
11389 * if it is a string, it is interpreted as a binary sequence of bytes.
11390 * (Array#pack might be a useful way to build this string.)
11391 *
11392 * Not implemented on all platforms.
11393 *
11394 */
11395
11396static VALUE
11397rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11398{
11399 VALUE req, arg;
11400
11401 rb_scan_args(argc, argv, "11", &req, &arg);
11402 return rb_fcntl(io, req, arg);
11403}
11404#else
11405#define rb_io_fcntl rb_f_notimplement
11406#endif
11407
11408#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11409/*
11410 * call-seq:
11411 * syscall(integer_callno, *arguments) -> integer
11412 *
11413 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11414 * which calls a specified function.
11415 *
11416 * Calls the operating system function identified by +integer_callno+;
11417 * returns the result of the function or raises SystemCallError if it failed.
11418 * The effect of the call is platform-dependent.
11419 * The arguments and returned value are platform-dependent.
11420 *
11421 * For each of +arguments+: if it is an integer, it is passed directly;
11422 * if it is a string, it is interpreted as a binary sequence of bytes.
11423 * There may be as many as nine such arguments.
11424 *
11425 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11426 * are platform-dependent.
11427 *
11428 * Note: Method +syscall+ is essentially unsafe and unportable.
11429 * The DL (Fiddle) library is preferred for safer and a bit
11430 * more portable programming.
11431 *
11432 * Not implemented on all platforms.
11433 *
11434 */
11435
11436static VALUE
11437rb_f_syscall(int argc, VALUE *argv, VALUE _)
11438{
11439 VALUE arg[8];
11440#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11441# define SYSCALL __syscall
11442# define NUM2SYSCALLID(x) NUM2LONG(x)
11443# define RETVAL2NUM(x) LONG2NUM(x)
11444# if SIZEOF_LONG == 8
11445 long num, retval = -1;
11446# elif SIZEOF_LONG_LONG == 8
11447 long long num, retval = -1;
11448# else
11449# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11450# endif
11451#elif defined(__linux__)
11452# define SYSCALL syscall
11453# define NUM2SYSCALLID(x) NUM2LONG(x)
11454# define RETVAL2NUM(x) LONG2NUM(x)
11455 /*
11456 * Linux man page says, syscall(2) function prototype is below.
11457 *
11458 * int syscall(int number, ...);
11459 *
11460 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11461 */
11462 long num, retval = -1;
11463#else
11464# define SYSCALL syscall
11465# define NUM2SYSCALLID(x) NUM2INT(x)
11466# define RETVAL2NUM(x) INT2NUM(x)
11467 int num, retval = -1;
11468#endif
11469 int i;
11470
11471 if (RTEST(ruby_verbose)) {
11473 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11474 }
11475
11476 if (argc == 0)
11477 rb_raise(rb_eArgError, "too few arguments for syscall");
11478 if (argc > numberof(arg))
11479 rb_raise(rb_eArgError, "too many arguments for syscall");
11480 num = NUM2SYSCALLID(argv[0]); ++argv;
11481 for (i = argc - 1; i--; ) {
11482 VALUE v = rb_check_string_type(argv[i]);
11483
11484 if (!NIL_P(v)) {
11485 SafeStringValue(v);
11486 rb_str_modify(v);
11487 arg[i] = (VALUE)StringValueCStr(v);
11488 }
11489 else {
11490 arg[i] = (VALUE)NUM2LONG(argv[i]);
11491 }
11492 }
11493
11494 switch (argc) {
11495 case 1:
11496 retval = SYSCALL(num);
11497 break;
11498 case 2:
11499 retval = SYSCALL(num, arg[0]);
11500 break;
11501 case 3:
11502 retval = SYSCALL(num, arg[0],arg[1]);
11503 break;
11504 case 4:
11505 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11506 break;
11507 case 5:
11508 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11509 break;
11510 case 6:
11511 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11512 break;
11513 case 7:
11514 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11515 break;
11516 case 8:
11517 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11518 break;
11519 }
11520
11521 if (retval == -1)
11522 rb_sys_fail(0);
11523 return RETVAL2NUM(retval);
11524#undef SYSCALL
11525#undef NUM2SYSCALLID
11526#undef RETVAL2NUM
11527}
11528#else
11529#define rb_f_syscall rb_f_notimplement
11530#endif
11531
11532static VALUE
11533io_new_instance(VALUE args)
11534{
11535 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11536}
11537
11538static rb_encoding *
11539find_encoding(VALUE v)
11540{
11541 rb_encoding *enc = rb_find_encoding(v);
11542 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11543 return enc;
11544}
11545
11546static void
11547io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11548{
11549 rb_encoding *enc, *enc2;
11550 int ecflags = fptr->encs.ecflags;
11551 VALUE ecopts, tmp;
11552
11553 if (!NIL_P(v2)) {
11554 enc2 = find_encoding(v1);
11555 tmp = rb_check_string_type(v2);
11556 if (!NIL_P(tmp)) {
11557 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11558 /* Special case - "-" => no transcoding */
11559 enc = enc2;
11560 enc2 = NULL;
11561 }
11562 else
11563 enc = find_encoding(v2);
11564 if (enc == enc2) {
11565 /* Special case - "-" => no transcoding */
11566 enc2 = NULL;
11567 }
11568 }
11569 else {
11570 enc = find_encoding(v2);
11571 if (enc == enc2) {
11572 /* Special case - "-" => no transcoding */
11573 enc2 = NULL;
11574 }
11575 }
11576 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11577 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11578 }
11579 else {
11580 if (NIL_P(v1)) {
11581 /* Set to default encodings */
11582 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11583 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11584 ecopts = Qnil;
11585 }
11586 else {
11587 tmp = rb_check_string_type(v1);
11588 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11589 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11590 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11591 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11592 }
11593 else {
11594 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11595 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11596 ecopts = Qnil;
11597 }
11598 }
11599 }
11600 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11601 fptr->encs.enc = enc;
11602 fptr->encs.enc2 = enc2;
11603 fptr->encs.ecflags = ecflags;
11604 fptr->encs.ecopts = ecopts;
11605 clear_codeconv(fptr);
11606
11607}
11608
11610 rb_io_t *fptr;
11611 VALUE v1;
11612 VALUE v2;
11613 VALUE opt;
11614};
11615
11616static VALUE
11617io_encoding_set_v(VALUE v)
11618{
11619 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11620 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11621 return Qnil;
11622}
11623
11624static VALUE
11625pipe_pair_close(VALUE rw)
11626{
11627 VALUE *rwp = (VALUE *)rw;
11628 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11629}
11630
11631/*
11632 * call-seq:
11633 * IO.pipe(**opts) -> [read_io, write_io]
11634 * IO.pipe(enc, **opts) -> [read_io, write_io]
11635 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11636 * IO.pipe(**opts) {|read_io, write_io] ...} -> object
11637 * IO.pipe(enc, **opts) {|read_io, write_io] ...} -> object
11638 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io] ...} -> object
11639 *
11640 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11641 * connected to each other.
11642 *
11643 * If argument +enc_string+ is given, it must be a string containing one of:
11644 *
11645 * - The name of the encoding to be used as the external encoding.
11646 * - The colon-separated names of two encodings to be used as the external
11647 * and internal encodings.
11648 *
11649 * If argument +int_enc+ is given, it must be an Encoding object
11650 * or encoding name string that specifies the internal encoding to be used;
11651 * if argument +ext_enc+ is also given, it must be an Encoding object
11652 * or encoding name string that specifies the external encoding to be used.
11653 *
11654 * The string read from +read_io+ is tagged with the external encoding;
11655 * if an internal encoding is also specified, the string is converted
11656 * to, and tagged with, that encoding.
11657 *
11658 * If any encoding is specified,
11659 * optional hash arguments specify the conversion option.
11660 *
11661 * Optional keyword arguments +opts+ specify:
11662 *
11663 * - {Open Options}[rdoc-ref:IO@Open+Options].
11664 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11665 *
11666 * With no block given, returns the two endpoints in an array:
11667 *
11668 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11669 *
11670 * With a block given, calls the block with the two endpoints;
11671 * closes both endpoints and returns the value of the block:
11672 *
11673 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11674 *
11675 * Output:
11676 *
11677 * #<IO:fd 6>
11678 * #<IO:fd 7>
11679 *
11680 * Not available on all platforms.
11681 *
11682 * In the example below, the two processes close the ends of the pipe
11683 * that they are not using. This is not just a cosmetic nicety. The
11684 * read end of a pipe will not generate an end of file condition if
11685 * there are any writers with the pipe still open. In the case of the
11686 * parent process, the <tt>rd.read</tt> will never return if it
11687 * does not first issue a <tt>wr.close</tt>:
11688 *
11689 * rd, wr = IO.pipe
11690 *
11691 * if fork
11692 * wr.close
11693 * puts "Parent got: <#{rd.read}>"
11694 * rd.close
11695 * Process.wait
11696 * else
11697 * rd.close
11698 * puts 'Sending message to parent'
11699 * wr.write "Hi Dad"
11700 * wr.close
11701 * end
11702 *
11703 * <em>produces:</em>
11704 *
11705 * Sending message to parent
11706 * Parent got: <Hi Dad>
11707 *
11708 */
11709
11710static VALUE
11711rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11712{
11713 int pipes[2], state;
11714 VALUE r, w, args[3], v1, v2;
11715 VALUE opt;
11716 rb_io_t *fptr, *fptr2;
11717 struct io_encoding_set_args ies_args;
11718 int fmode = 0;
11719 VALUE ret;
11720
11721 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11722 if (rb_pipe(pipes) < 0)
11723 rb_sys_fail(0);
11724
11725 args[0] = klass;
11726 args[1] = INT2NUM(pipes[0]);
11727 args[2] = INT2FIX(O_RDONLY);
11728 r = rb_protect(io_new_instance, (VALUE)args, &state);
11729 if (state) {
11730 close(pipes[0]);
11731 close(pipes[1]);
11732 rb_jump_tag(state);
11733 }
11734 GetOpenFile(r, fptr);
11735
11736 ies_args.fptr = fptr;
11737 ies_args.v1 = v1;
11738 ies_args.v2 = v2;
11739 ies_args.opt = opt;
11740 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11741 if (state) {
11742 close(pipes[1]);
11743 io_close(r);
11744 rb_jump_tag(state);
11745 }
11746
11747 args[1] = INT2NUM(pipes[1]);
11748 args[2] = INT2FIX(O_WRONLY);
11749 w = rb_protect(io_new_instance, (VALUE)args, &state);
11750 if (state) {
11751 close(pipes[1]);
11752 if (!NIL_P(r)) rb_io_close(r);
11753 rb_jump_tag(state);
11754 }
11755 GetOpenFile(w, fptr2);
11756 rb_io_synchronized(fptr2);
11757
11758 extract_binmode(opt, &fmode);
11759
11760 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11763 }
11764
11765#if DEFAULT_TEXTMODE
11766 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11767 fptr->mode &= ~FMODE_TEXTMODE;
11768 setmode(fptr->fd, O_BINARY);
11769 }
11770#if RUBY_CRLF_ENVIRONMENT
11773 }
11774#endif
11775#endif
11776 fptr->mode |= fmode;
11777#if DEFAULT_TEXTMODE
11778 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11779 fptr2->mode &= ~FMODE_TEXTMODE;
11780 setmode(fptr2->fd, O_BINARY);
11781 }
11782#endif
11783 fptr2->mode |= fmode;
11784
11785 ret = rb_assoc_new(r, w);
11786 if (rb_block_given_p()) {
11787 VALUE rw[2];
11788 rw[0] = r;
11789 rw[1] = w;
11790 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11791 }
11792 return ret;
11793}
11794
11796 int argc;
11797 VALUE *argv;
11798 VALUE io;
11799};
11800
11801static void
11802open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11803{
11804 VALUE path, v;
11805 VALUE vmode = Qnil, vperm = Qnil;
11806
11807 path = *argv++;
11808 argc--;
11809 FilePathValue(path);
11810 arg->io = 0;
11811 arg->argc = argc;
11812 arg->argv = argv;
11813 if (NIL_P(opt)) {
11814 vmode = INT2NUM(O_RDONLY);
11815 vperm = INT2FIX(0666);
11816 }
11817 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11818 int n;
11819
11820 v = rb_to_array_type(v);
11821 n = RARRAY_LENINT(v);
11822 rb_check_arity(n, 0, 3); /* rb_io_open */
11823 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11824 }
11825 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11826}
11827
11828static VALUE
11829io_s_foreach(VALUE v)
11830{
11831 struct getline_arg *arg = (void *)v;
11832 VALUE str;
11833
11834 if (arg->limit == 0)
11835 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
11836 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11837 rb_lastline_set(str);
11838 rb_yield(str);
11839 }
11841 return Qnil;
11842}
11843
11844/*
11845 * call-seq:
11846 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
11847 * IO.foreach(path, limit, **opts) {|line| block } -> nil
11848 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
11849 * IO.foreach(command, sep = $/, **opts) {|line| block } -> nil
11850 * IO.foreach(command, limit, **opts) {|line| block } -> nil
11851 * IO.foreach(command, sep, limit, **opts) {|line| block } -> nil
11852 * IO.foreach(...) -> an_enumerator
11853 *
11854 * Calls the block with each successive line read from the stream.
11855 *
11856 * When called from class \IO (but not subclasses of \IO),
11857 * this method has potential security vulnerabilities if called with untrusted input;
11858 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11859 *
11860 * The first argument must be a string that is one of the following:
11861 *
11862 * - Path: if +self+ is a subclass of \IO (\File, for example),
11863 * or if the string _does_ _not_ start with the pipe character (<tt>'|'</tt>),
11864 * the string is the path to a file.
11865 * - Command: if +self+ is the class \IO,
11866 * and if the string starts with the pipe character,
11867 * the rest of the string is a command to be executed as a subprocess.
11868 * This usage has potential security vulnerabilities if called with untrusted input;
11869 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11870 *
11871 * With only argument +path+ given, parses lines from the file at the given +path+,
11872 * as determined by the default line separator,
11873 * and calls the block with each successive line:
11874 *
11875 * File.foreach('t.txt') {|line| p line }
11876 *
11877 * Output: the same as above.
11878 *
11879 * For both forms, command and path, the remaining arguments are the same.
11880 *
11881 * With argument +sep+ given, parses lines as determined by that line separator
11882 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
11883 *
11884 * File.foreach('t.txt', 'li') {|line| p line }
11885 *
11886 * Output:
11887 *
11888 * "First li"
11889 * "ne\nSecond li"
11890 * "ne\n\nThird li"
11891 * "ne\nFourth li"
11892 * "ne\n"
11893 *
11894 * Each paragraph:
11895 *
11896 * File.foreach('t.txt', '') {|paragraph| p paragraph }
11897 *
11898 * Output:
11899 *
11900 * "First line\nSecond line\n\n"
11901 * "Third line\nFourth line\n"
11902 *
11903 * With argument +limit+ given, parses lines as determined by the default
11904 * line separator and the given line-length limit
11905 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
11906 *
11907 * File.foreach('t.txt', 7) {|line| p line }
11908 *
11909 * Output:
11910 *
11911 * "First l"
11912 * "ine\n"
11913 * "Second "
11914 * "line\n"
11915 * "\n"
11916 * "Third l"
11917 * "ine\n"
11918 * "Fourth l"
11919 * "line\n"
11920 *
11921 * With arguments +sep+ and +limit+ given,
11922 * parses lines as determined by the given
11923 * line separator and the given line-length limit
11924 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
11925 *
11926 * Optional keyword arguments +opts+ specify:
11927 *
11928 * - {Open Options}[rdoc-ref:IO@Open+Options].
11929 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11930 * - {Line Options}[rdoc-ref:IO@Line+Options].
11931 *
11932 * Returns an Enumerator if no block is given.
11933 *
11934 */
11935
11936static VALUE
11937rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
11938{
11939 VALUE opt;
11940 int orig_argc = argc;
11941 struct foreach_arg arg;
11942 struct getline_arg garg;
11943
11944 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
11945 RETURN_ENUMERATOR(self, orig_argc, argv);
11946 extract_getline_args(argc-1, argv+1, &garg);
11947 open_key_args(self, argc, argv, opt, &arg);
11948 if (NIL_P(arg.io)) return Qnil;
11949 extract_getline_opts(opt, &garg);
11950 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
11951 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
11952}
11953
11954static VALUE
11955io_s_readlines(VALUE v)
11956{
11957 struct getline_arg *arg = (void *)v;
11958 return io_readlines(arg, arg->io);
11959}
11960
11961/*
11962 * call-seq:
11963 * IO.readlines(command, sep = $/, **opts) -> array
11964 * IO.readlines(command, limit, **opts) -> array
11965 * IO.readlines(command, sep, limit, **opts) -> array
11966 * IO.readlines(path, sep = $/, **opts) -> array
11967 * IO.readlines(path, limit, **opts) -> array
11968 * IO.readlines(path, sep, limit, **opts) -> array
11969 *
11970 * Returns an array of all lines read from the stream.
11971 *
11972 * When called from class \IO (but not subclasses of \IO),
11973 * this method has potential security vulnerabilities if called with untrusted input;
11974 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11975 *
11976 * The first argument must be a string;
11977 * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
11978 *
11979 * - If so (and if +self+ is \IO),
11980 * the rest of the string is a command to be executed as a subprocess.
11981 * - Otherwise, the string is the path to a file.
11982 *
11983 * With only argument +command+ given, executes the command in a shell,
11984 * parses its $stdout into lines, as determined by the default line separator,
11985 * and returns those lines in an array:
11986 *
11987 * IO.readlines('| cat t.txt')
11988 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
11989 *
11990 * With only argument +path+ given, parses lines from the file at the given +path+,
11991 * as determined by the default line separator,
11992 * and returns those lines in an array:
11993 *
11994 * IO.readlines('t.txt')
11995 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
11996 *
11997 * For both forms, command and path, the remaining arguments are the same.
11998 *
11999 * With argument +sep+ given, parses lines as determined by that line separator
12000 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12001 *
12002 * # Ordinary separator.
12003 * IO.readlines('t.txt', 'li')
12004 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12005 * # Get-paragraphs separator.
12006 * IO.readlines('t.txt', '')
12007 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12008 * # Get-all separator.
12009 * IO.readlines('t.txt', nil)
12010 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12011 *
12012 * With argument +limit+ given, parses lines as determined by the default
12013 * line separator and the given line-length limit
12014 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
12015 *
12016 * IO.readlines('t.txt', 7)
12017 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12018 *
12019 * With arguments +sep+ and +limit+ given,
12020 * parses lines as determined by the given
12021 * line separator and the given line-length limit
12022 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
12023 *
12024 * Optional keyword arguments +opts+ specify:
12025 *
12026 * - {Open Options}[rdoc-ref:IO@Open+Options].
12027 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12028 * - {Line Options}[rdoc-ref:IO@Line+Options].
12029 *
12030 */
12031
12032static VALUE
12033rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12034{
12035 VALUE opt;
12036 struct foreach_arg arg;
12037 struct getline_arg garg;
12038
12039 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12040 extract_getline_args(argc-1, argv+1, &garg);
12041 open_key_args(io, argc, argv, opt, &arg);
12042 if (NIL_P(arg.io)) return Qnil;
12043 extract_getline_opts(opt, &garg);
12044 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12045 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12046}
12047
12048static VALUE
12049io_s_read(VALUE v)
12050{
12051 struct foreach_arg *arg = (void *)v;
12052 return io_read(arg->argc, arg->argv, arg->io);
12053}
12054
12055struct seek_arg {
12056 VALUE io;
12057 VALUE offset;
12058 int mode;
12059};
12060
12061static VALUE
12062seek_before_access(VALUE argp)
12063{
12064 struct seek_arg *arg = (struct seek_arg *)argp;
12065 rb_io_binmode(arg->io);
12066 return rb_io_seek(arg->io, arg->offset, arg->mode);
12067}
12068
12069/*
12070 * call-seq:
12071 * IO.read(command, length = nil, offset = 0, **opts) -> string or nil
12072 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12073 *
12074 * Opens the stream, reads and returns some or all of its content,
12075 * and closes the stream; returns +nil+ if no bytes were read.
12076 *
12077 * When called from class \IO (but not subclasses of \IO),
12078 * this method has potential security vulnerabilities if called with untrusted input;
12079 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12080 *
12081 * The first argument must be a string;
12082 * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
12083 *
12084 * - If so (and if +self+ is \IO),
12085 * the rest of the string is a command to be executed as a subprocess.
12086 * - Otherwise, the string is the path to a file.
12087 *
12088 * With only argument +command+ given, executes the command in a shell,
12089 * returns its entire $stdout:
12090 *
12091 * IO.read('| cat t.txt')
12092 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12093 *
12094 * With only argument +path+ given, reads in text mode and returns the entire content
12095 * of the file at the given path:
12096 *
12097 * IO.read('t.txt')
12098 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12099 *
12100 * On Windows, text mode can terminate reading and leave bytes in the file
12101 * unread when encountering certain special bytes. Consider using
12102 * IO.binread if all bytes in the file should be read.
12103 *
12104 * For both forms, command and path, the remaining arguments are the same.
12105 *
12106 * With argument +length+, returns +length+ bytes if available:
12107 *
12108 * IO.read('t.txt', 7) # => "First l"
12109 * IO.read('t.txt', 700)
12110 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12111 *
12112 * With arguments +length+ and +offset+, returns +length+ bytes
12113 * if available, beginning at the given +offset+:
12114 *
12115 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12116 * IO.read('t.txt', 10, 200) # => nil
12117 *
12118 * Optional keyword arguments +opts+ specify:
12119 *
12120 * - {Open Options}[rdoc-ref:IO@Open+Options].
12121 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12122 *
12123 */
12124
12125static VALUE
12126rb_io_s_read(int argc, VALUE *argv, VALUE io)
12127{
12128 VALUE opt, offset;
12129 struct foreach_arg arg;
12130
12131 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12132 open_key_args(io, argc, argv, opt, &arg);
12133 if (NIL_P(arg.io)) return Qnil;
12134 if (!NIL_P(offset)) {
12135 struct seek_arg sarg;
12136 int state = 0;
12137 sarg.io = arg.io;
12138 sarg.offset = offset;
12139 sarg.mode = SEEK_SET;
12140 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12141 if (state) {
12142 rb_io_close(arg.io);
12143 rb_jump_tag(state);
12144 }
12145 if (arg.argc == 2) arg.argc = 1;
12146 }
12147 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12148}
12149
12150/*
12151 * call-seq:
12152 * IO.binread(command, length = nil, offset = 0) -> string or nil
12153 * IO.binread(path, length = nil, offset = 0) -> string or nil
12154 *
12155 * Behaves like IO.read, except that the stream is opened in binary mode
12156 * with ASCII-8BIT encoding.
12157 *
12158 * When called from class \IO (but not subclasses of \IO),
12159 * this method has potential security vulnerabilities if called with untrusted input;
12160 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12161 *
12162 */
12163
12164static VALUE
12165rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12166{
12167 VALUE offset;
12168 struct foreach_arg arg;
12169 enum {
12171 oflags = O_RDONLY
12172#ifdef O_BINARY
12173 |O_BINARY
12174#endif
12175 };
12176 convconfig_t convconfig = {NULL, NULL, 0, Qnil};
12177
12178 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12179 FilePathValue(argv[0]);
12180 convconfig.enc = rb_ascii8bit_encoding();
12181 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12182 if (NIL_P(arg.io)) return Qnil;
12183 arg.argv = argv+1;
12184 arg.argc = (argc > 1) ? 1 : 0;
12185 if (!NIL_P(offset)) {
12186 struct seek_arg sarg;
12187 int state = 0;
12188 sarg.io = arg.io;
12189 sarg.offset = offset;
12190 sarg.mode = SEEK_SET;
12191 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12192 if (state) {
12193 rb_io_close(arg.io);
12194 rb_jump_tag(state);
12195 }
12196 }
12197 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12198}
12199
12200static VALUE
12201io_s_write0(VALUE v)
12202{
12203 struct write_arg *arg = (void *)v;
12204 return io_write(arg->io,arg->str,arg->nosync);
12205}
12206
12207static VALUE
12208io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12209{
12210 VALUE string, offset, opt;
12211 struct foreach_arg arg;
12212 struct write_arg warg;
12213
12214 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12215
12216 if (NIL_P(opt)) opt = rb_hash_new();
12217 else opt = rb_hash_dup(opt);
12218
12219
12220 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12221 int mode = O_WRONLY|O_CREAT;
12222#ifdef O_BINARY
12223 if (binary) mode |= O_BINARY;
12224#endif
12225 if (NIL_P(offset)) mode |= O_TRUNC;
12226 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12227 }
12228 open_key_args(klass, argc, argv, opt, &arg);
12229
12230#ifndef O_BINARY
12231 if (binary) rb_io_binmode_m(arg.io);
12232#endif
12233
12234 if (NIL_P(arg.io)) return Qnil;
12235 if (!NIL_P(offset)) {
12236 struct seek_arg sarg;
12237 int state = 0;
12238 sarg.io = arg.io;
12239 sarg.offset = offset;
12240 sarg.mode = SEEK_SET;
12241 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12242 if (state) {
12243 rb_io_close(arg.io);
12244 rb_jump_tag(state);
12245 }
12246 }
12247
12248 warg.io = arg.io;
12249 warg.str = string;
12250 warg.nosync = 0;
12251
12252 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12253}
12254
12255/*
12256 * call-seq:
12257 * IO.write(command, data, **opts) -> integer
12258 * IO.write(path, data, offset = 0, **opts) -> integer
12259 *
12260 * Opens the stream, writes the given +data+ to it,
12261 * and closes the stream; returns the number of bytes written.
12262 *
12263 * When called from class \IO (but not subclasses of \IO),
12264 * this method has potential security vulnerabilities if called with untrusted input;
12265 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12266 *
12267 * The first argument must be a string;
12268 * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
12269 *
12270 * - If so (and if +self+ is \IO),
12271 * the rest of the string is a command to be executed as a subprocess.
12272 * - Otherwise, the string is the path to a file.
12273 *
12274 * With argument +command+ given, executes the command in a shell,
12275 * passes +data+ through standard input, writes its output to $stdout,
12276 * and returns the length of the given +data+:
12277 *
12278 * IO.write('| cat', 'Hello World!') # => 12
12279 *
12280 * Output:
12281 *
12282 * Hello World!
12283 *
12284 * With argument +path+ given, writes the given +data+ to the file
12285 * at that path:
12286 *
12287 * IO.write('t.tmp', 'abc') # => 3
12288 * File.read('t.tmp') # => "abc"
12289 *
12290 * If +offset+ is zero (the default), the file is overwritten:
12291 *
12292 * IO.write('t.tmp', 'A') # => 1
12293 * File.read('t.tmp') # => "A"
12294 *
12295 * If +offset+ in within the file content, the file is partly overwritten:
12296 *
12297 * IO.write('t.tmp', 'abcdef') # => 3
12298 * File.read('t.tmp') # => "abcdef"
12299 * # Offset within content.
12300 * IO.write('t.tmp', '012', 2) # => 3
12301 * File.read('t.tmp') # => "ab012f"
12302 *
12303 * If +offset+ is outside the file content,
12304 * the file is padded with null characters <tt>"\u0000"</tt>:
12305 *
12306 * IO.write('t.tmp', 'xyz', 10) # => 3
12307 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12308 *
12309 * Optional keyword arguments +opts+ specify:
12310 *
12311 * - {Open Options}[rdoc-ref:IO@Open+Options].
12312 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12313 *
12314 */
12315
12316static VALUE
12317rb_io_s_write(int argc, VALUE *argv, VALUE io)
12318{
12319 return io_s_write(argc, argv, io, 0);
12320}
12321
12322/*
12323 * call-seq:
12324 * IO.binwrite(command, string, offset = 0) -> integer
12325 * IO.binwrite(path, string, offset = 0) -> integer
12326 *
12327 * Behaves like IO.write, except that the stream is opened in binary mode
12328 * with ASCII-8BIT encoding.
12329 *
12330 * When called from class \IO (but not subclasses of \IO),
12331 * this method has potential security vulnerabilities if called with untrusted input;
12332 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12333 *
12334 */
12335
12336static VALUE
12337rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12338{
12339 return io_s_write(argc, argv, io, 1);
12340}
12341
12343 VALUE src;
12344 VALUE dst;
12345 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12346 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12347
12348 rb_io_t *src_fptr;
12349 rb_io_t *dst_fptr;
12350 unsigned close_src : 1;
12351 unsigned close_dst : 1;
12352 int error_no;
12353 rb_off_t total;
12354 const char *syserr;
12355 const char *notimp;
12356 VALUE th;
12357 struct stat src_stat;
12358 struct stat dst_stat;
12359#ifdef HAVE_FCOPYFILE
12360 copyfile_state_t copyfile_state;
12361#endif
12362};
12363
12364static void *
12365exec_interrupts(void *arg)
12366{
12367 VALUE th = (VALUE)arg;
12368 rb_thread_execute_interrupts(th);
12369 return NULL;
12370}
12371
12372/*
12373 * returns TRUE if the preceding system call was interrupted
12374 * so we can continue. If the thread was interrupted, we
12375 * reacquire the GVL to execute interrupts before continuing.
12376 */
12377static int
12378maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12379{
12380 switch (errno) {
12381 case EINTR:
12382#if defined(ERESTART)
12383 case ERESTART:
12384#endif
12385 if (rb_thread_interrupted(stp->th)) {
12386 if (has_gvl)
12387 rb_thread_execute_interrupts(stp->th);
12388 else
12389 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12390 }
12391 return TRUE;
12392 }
12393 return FALSE;
12394}
12395
12397 VALUE scheduler;
12398
12399 rb_io_t *fptr;
12400 short events;
12401
12402 VALUE result;
12403};
12404
12405static void *
12406fiber_scheduler_wait_for(void * _arguments)
12407{
12408 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12409
12410 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12411
12412 return NULL;
12413}
12414
12415#if USE_POLL
12416# define IOWAIT_SYSCALL "poll"
12417STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12418STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12419static int
12420nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12421{
12423 if (scheduler != Qnil) {
12424 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12425 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12426 return RTEST(args.result);
12427 }
12428
12429 int fd = fptr->fd;
12430 if (fd == -1) return 0;
12431
12432 struct pollfd fds;
12433
12434 fds.fd = fd;
12435 fds.events = events;
12436
12437 int timeout_milliseconds = -1;
12438
12439 if (timeout) {
12440 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12441 }
12442
12443 return poll(&fds, 1, timeout_milliseconds);
12444}
12445#else /* !USE_POLL */
12446# define IOWAIT_SYSCALL "select"
12447static int
12448nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12449{
12451 if (scheduler != Qnil) {
12452 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12453 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12454 return RTEST(args.result);
12455 }
12456
12457 int fd = fptr->fd;
12458
12459 if (fd == -1) {
12460 errno = EBADF;
12461 return -1;
12462 }
12463
12464 rb_fdset_t fds;
12465 int ret;
12466
12467 rb_fd_init(&fds);
12468 rb_fd_set(fd, &fds);
12469
12470 switch (events) {
12471 case RB_WAITFD_IN:
12472 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12473 break;
12474 case RB_WAITFD_OUT:
12475 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12476 break;
12477 default:
12478 VM_UNREACHABLE(nogvl_wait_for);
12479 }
12480
12481 rb_fd_term(&fds);
12482
12483 // On timeout, this returns 0.
12484 return ret;
12485}
12486#endif /* !USE_POLL */
12487
12488static int
12489maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12490{
12491 int ret;
12492
12493 do {
12494 if (has_gvl) {
12496 }
12497 else {
12498 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12499 }
12500 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12501
12502 if (ret < 0) {
12503 stp->syserr = IOWAIT_SYSCALL;
12504 stp->error_no = errno;
12505 return ret;
12506 }
12507 return 0;
12508}
12509
12510static int
12511nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12512{
12513 int ret;
12514
12515 do {
12516 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12517 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12518
12519 if (ret < 0) {
12520 stp->syserr = IOWAIT_SYSCALL;
12521 stp->error_no = errno;
12522 return ret;
12523 }
12524 return 0;
12525}
12526
12527#ifdef USE_COPY_FILE_RANGE
12528
12529static ssize_t
12530simple_copy_file_range(int in_fd, rb_off_t *in_offset, int out_fd, rb_off_t *out_offset, size_t count, unsigned int flags)
12531{
12532#ifdef HAVE_COPY_FILE_RANGE
12533 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12534#else
12535 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12536#endif
12537}
12538
12539static int
12540nogvl_copy_file_range(struct copy_stream_struct *stp)
12541{
12542 ssize_t ss;
12543 rb_off_t src_size;
12544 rb_off_t copy_length, src_offset, *src_offset_ptr;
12545
12546 if (!S_ISREG(stp->src_stat.st_mode))
12547 return 0;
12548
12549 src_size = stp->src_stat.st_size;
12550 src_offset = stp->src_offset;
12551 if (src_offset >= (rb_off_t)0) {
12552 src_offset_ptr = &src_offset;
12553 }
12554 else {
12555 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12556 }
12557
12558 copy_length = stp->copy_length;
12559 if (copy_length < (rb_off_t)0) {
12560 if (src_offset < (rb_off_t)0) {
12561 rb_off_t current_offset;
12562 errno = 0;
12563 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12564 if (current_offset < (rb_off_t)0 && errno) {
12565 stp->syserr = "lseek";
12566 stp->error_no = errno;
12567 return (int)current_offset;
12568 }
12569 copy_length = src_size - current_offset;
12570 }
12571 else {
12572 copy_length = src_size - src_offset;
12573 }
12574 }
12575
12576 retry_copy_file_range:
12577# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12578 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12579 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12580# else
12581 ss = (ssize_t)copy_length;
12582# endif
12583 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12584 if (0 < ss) {
12585 stp->total += ss;
12586 copy_length -= ss;
12587 if (0 < copy_length) {
12588 goto retry_copy_file_range;
12589 }
12590 }
12591 if (ss < 0) {
12592 if (maygvl_copy_stream_continue_p(0, stp)) {
12593 goto retry_copy_file_range;
12594 }
12595 switch (errno) {
12596 case EINVAL:
12597 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12598 docker container) */
12599#ifdef ENOSYS
12600 case ENOSYS:
12601#endif
12602#ifdef EXDEV
12603 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12604#endif
12605 return 0;
12606 case EAGAIN:
12607#if EWOULDBLOCK != EAGAIN
12608 case EWOULDBLOCK:
12609#endif
12610 {
12611 int ret = nogvl_copy_stream_wait_write(stp);
12612 if (ret < 0) return ret;
12613 }
12614 goto retry_copy_file_range;
12615 case EBADF:
12616 {
12617 int e = errno;
12618 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12619
12620 if (flags != -1 && flags & O_APPEND) {
12621 return 0;
12622 }
12623 errno = e;
12624 }
12625 }
12626 stp->syserr = "copy_file_range";
12627 stp->error_no = errno;
12628 return (int)ss;
12629 }
12630 return 1;
12631}
12632#endif
12633
12634#ifdef HAVE_FCOPYFILE
12635static int
12636nogvl_fcopyfile(struct copy_stream_struct *stp)
12637{
12638 rb_off_t cur, ss = 0;
12639 const rb_off_t src_offset = stp->src_offset;
12640 int ret;
12641
12642 if (stp->copy_length >= (rb_off_t)0) {
12643 /* copy_length can't be specified in fcopyfile(3) */
12644 return 0;
12645 }
12646
12647 if (!S_ISREG(stp->src_stat.st_mode))
12648 return 0;
12649
12650 if (!S_ISREG(stp->dst_stat.st_mode))
12651 return 0;
12652 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12653 return 0;
12654 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12655 /* fcopyfile(3) appends src IO to dst IO and then truncates
12656 * dst IO to src IO's original size. */
12657 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12658 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12659 if (end > (rb_off_t)0) return 0;
12660 }
12661
12662 if (src_offset > (rb_off_t)0) {
12663 rb_off_t r;
12664
12665 /* get current offset */
12666 errno = 0;
12667 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12668 if (cur < (rb_off_t)0 && errno) {
12669 stp->error_no = errno;
12670 return 1;
12671 }
12672
12673 errno = 0;
12674 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12675 if (r < (rb_off_t)0 && errno) {
12676 stp->error_no = errno;
12677 return 1;
12678 }
12679 }
12680
12681 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12682 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12683 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12684
12685 if (ret == 0) { /* success */
12686 stp->total = ss;
12687 if (src_offset > (rb_off_t)0) {
12688 rb_off_t r;
12689 errno = 0;
12690 /* reset offset */
12691 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12692 if (r < (rb_off_t)0 && errno) {
12693 stp->error_no = errno;
12694 return 1;
12695 }
12696 }
12697 }
12698 else {
12699 switch (errno) {
12700 case ENOTSUP:
12701 case EPERM:
12702 case EINVAL:
12703 return 0;
12704 }
12705 stp->syserr = "fcopyfile";
12706 stp->error_no = errno;
12707 return (int)ret;
12708 }
12709 return 1;
12710}
12711#endif
12712
12713#ifdef HAVE_SENDFILE
12714
12715# ifdef __linux__
12716# define USE_SENDFILE
12717
12718# ifdef HAVE_SYS_SENDFILE_H
12719# include <sys/sendfile.h>
12720# endif
12721
12722static ssize_t
12723simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12724{
12725 return sendfile(out_fd, in_fd, offset, (size_t)count);
12726}
12727
12728# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12729/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12730 * without cpuset -l 0.
12731 */
12732# define USE_SENDFILE
12733
12734static ssize_t
12735simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12736{
12737 int r;
12738 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12739 rb_off_t sbytes;
12740# ifdef __APPLE__
12741 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12742 sbytes = count;
12743# else
12744 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12745# endif
12746 if (r != 0 && sbytes == 0) return r;
12747 if (offset) {
12748 *offset += sbytes;
12749 }
12750 else {
12751 lseek(in_fd, sbytes, SEEK_CUR);
12752 }
12753 return (ssize_t)sbytes;
12754}
12755
12756# endif
12757
12758#endif
12759
12760#ifdef USE_SENDFILE
12761static int
12762nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12763{
12764 ssize_t ss;
12765 rb_off_t src_size;
12766 rb_off_t copy_length;
12767 rb_off_t src_offset;
12768 int use_pread;
12769
12770 if (!S_ISREG(stp->src_stat.st_mode))
12771 return 0;
12772
12773 src_size = stp->src_stat.st_size;
12774#ifndef __linux__
12775 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12776 return 0;
12777#endif
12778
12779 src_offset = stp->src_offset;
12780 use_pread = src_offset >= (rb_off_t)0;
12781
12782 copy_length = stp->copy_length;
12783 if (copy_length < (rb_off_t)0) {
12784 if (use_pread)
12785 copy_length = src_size - src_offset;
12786 else {
12787 rb_off_t cur;
12788 errno = 0;
12789 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12790 if (cur < (rb_off_t)0 && errno) {
12791 stp->syserr = "lseek";
12792 stp->error_no = errno;
12793 return (int)cur;
12794 }
12795 copy_length = src_size - cur;
12796 }
12797 }
12798
12799 retry_sendfile:
12800# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12801 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12802 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12803# else
12804 ss = (ssize_t)copy_length;
12805# endif
12806 if (use_pread) {
12807 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12808 }
12809 else {
12810 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12811 }
12812 if (0 < ss) {
12813 stp->total += ss;
12814 copy_length -= ss;
12815 if (0 < copy_length) {
12816 goto retry_sendfile;
12817 }
12818 }
12819 if (ss < 0) {
12820 if (maygvl_copy_stream_continue_p(0, stp))
12821 goto retry_sendfile;
12822 switch (errno) {
12823 case EINVAL:
12824#ifdef ENOSYS
12825 case ENOSYS:
12826#endif
12827#ifdef EOPNOTSUP
12828 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12829 see also: [Feature #16965] */
12830 case EOPNOTSUP:
12831#endif
12832 return 0;
12833 case EAGAIN:
12834#if EWOULDBLOCK != EAGAIN
12835 case EWOULDBLOCK:
12836#endif
12837 {
12838 int ret;
12839#ifndef __linux__
12840 /*
12841 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12842 * select() reports regular files to always be "ready", so
12843 * there is no need to select() on it.
12844 * Other OSes may have the same limitation for sendfile() which
12845 * allow us to bypass maygvl_copy_stream_wait_read()...
12846 */
12847 ret = maygvl_copy_stream_wait_read(0, stp);
12848 if (ret < 0) return ret;
12849#endif
12850 ret = nogvl_copy_stream_wait_write(stp);
12851 if (ret < 0) return ret;
12852 }
12853 goto retry_sendfile;
12854 }
12855 stp->syserr = "sendfile";
12856 stp->error_no = errno;
12857 return (int)ss;
12858 }
12859 return 1;
12860}
12861#endif
12862
12863static ssize_t
12864maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12865{
12866 if (has_gvl)
12867 return rb_io_read_memory(fptr, buf, count);
12868 else
12869 return read(fptr->fd, buf, count);
12870}
12871
12872static ssize_t
12873maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12874{
12875 ssize_t ss;
12876 retry_read:
12877 if (offset < (rb_off_t)0) {
12878 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12879 }
12880 else {
12881#ifdef HAVE_PREAD
12882 ss = pread(stp->src_fptr->fd, buf, len, offset);
12883#else
12884 stp->notimp = "pread";
12885 return -1;
12886#endif
12887 }
12888 if (ss == 0) {
12889 return 0;
12890 }
12891 if (ss < 0) {
12892 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12893 goto retry_read;
12894 switch (errno) {
12895 case EAGAIN:
12896#if EWOULDBLOCK != EAGAIN
12897 case EWOULDBLOCK:
12898#endif
12899 {
12900 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12901 if (ret < 0) return ret;
12902 }
12903 goto retry_read;
12904#ifdef ENOSYS
12905 case ENOSYS:
12906 stp->notimp = "pread";
12907 return ss;
12908#endif
12909 }
12910 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
12911 stp->error_no = errno;
12912 }
12913 return ss;
12914}
12915
12916static int
12917nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
12918{
12919 ssize_t ss;
12920 int off = 0;
12921 while (len) {
12922 ss = write(stp->dst_fptr->fd, buf+off, len);
12923 if (ss < 0) {
12924 if (maygvl_copy_stream_continue_p(0, stp))
12925 continue;
12926 if (io_again_p(errno)) {
12927 int ret = nogvl_copy_stream_wait_write(stp);
12928 if (ret < 0) return ret;
12929 continue;
12930 }
12931 stp->syserr = "write";
12932 stp->error_no = errno;
12933 return (int)ss;
12934 }
12935 off += (int)ss;
12936 len -= (int)ss;
12937 stp->total += ss;
12938 }
12939 return 0;
12940}
12941
12942static void
12943nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
12944{
12945 char buf[1024*16];
12946 size_t len;
12947 ssize_t ss;
12948 int ret;
12949 rb_off_t copy_length;
12950 rb_off_t src_offset;
12951 int use_eof;
12952 int use_pread;
12953
12954 copy_length = stp->copy_length;
12955 use_eof = copy_length < (rb_off_t)0;
12956 src_offset = stp->src_offset;
12957 use_pread = src_offset >= (rb_off_t)0;
12958
12959 if (use_pread && stp->close_src) {
12960 rb_off_t r;
12961 errno = 0;
12962 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12963 if (r < (rb_off_t)0 && errno) {
12964 stp->syserr = "lseek";
12965 stp->error_no = errno;
12966 return;
12967 }
12968 src_offset = (rb_off_t)-1;
12969 use_pread = 0;
12970 }
12971
12972 while (use_eof || 0 < copy_length) {
12973 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
12974 len = (size_t)copy_length;
12975 }
12976 else {
12977 len = sizeof(buf);
12978 }
12979 if (use_pread) {
12980 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
12981 if (0 < ss)
12982 src_offset += ss;
12983 }
12984 else {
12985 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
12986 }
12987 if (ss <= 0) /* EOF or error */
12988 return;
12989
12990 ret = nogvl_copy_stream_write(stp, buf, ss);
12991 if (ret < 0)
12992 return;
12993
12994 if (!use_eof)
12995 copy_length -= ss;
12996 }
12997}
12998
12999static void *
13000nogvl_copy_stream_func(void *arg)
13001{
13002 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13003#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13004 int ret;
13005#endif
13006
13007#ifdef USE_COPY_FILE_RANGE
13008 ret = nogvl_copy_file_range(stp);
13009 if (ret != 0)
13010 goto finish; /* error or success */
13011#endif
13012
13013#ifdef HAVE_FCOPYFILE
13014 ret = nogvl_fcopyfile(stp);
13015 if (ret != 0)
13016 goto finish; /* error or success */
13017#endif
13018
13019#ifdef USE_SENDFILE
13020 ret = nogvl_copy_stream_sendfile(stp);
13021 if (ret != 0)
13022 goto finish; /* error or success */
13023#endif
13024
13025 nogvl_copy_stream_read_write(stp);
13026
13027#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13028 finish:
13029#endif
13030 return 0;
13031}
13032
13033static VALUE
13034copy_stream_fallback_body(VALUE arg)
13035{
13036 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13037 const int buflen = 16*1024;
13038 VALUE n;
13039 VALUE buf = rb_str_buf_new(buflen);
13040 rb_off_t rest = stp->copy_length;
13041 rb_off_t off = stp->src_offset;
13042 ID read_method = id_readpartial;
13043
13044 if (!stp->src_fptr) {
13045 if (!rb_respond_to(stp->src, read_method)) {
13046 read_method = id_read;
13047 }
13048 }
13049
13050 while (1) {
13051 long numwrote;
13052 long l;
13053 if (stp->copy_length < (rb_off_t)0) {
13054 l = buflen;
13055 }
13056 else {
13057 if (rest == 0) {
13058 rb_str_resize(buf, 0);
13059 break;
13060 }
13061 l = buflen < rest ? buflen : (long)rest;
13062 }
13063 if (!stp->src_fptr) {
13064 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13065
13066 if (read_method == id_read && NIL_P(rc))
13067 break;
13068 }
13069 else {
13070 ssize_t ss;
13071 rb_str_resize(buf, buflen);
13072 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13073 rb_str_resize(buf, ss > 0 ? ss : 0);
13074 if (ss < 0)
13075 return Qnil;
13076 if (ss == 0)
13077 rb_eof_error();
13078 if (off >= (rb_off_t)0)
13079 off += ss;
13080 }
13081 n = rb_io_write(stp->dst, buf);
13082 numwrote = NUM2LONG(n);
13083 stp->total += numwrote;
13084 rest -= numwrote;
13085 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13086 break;
13087 }
13088 }
13089
13090 return Qnil;
13091}
13092
13093static VALUE
13094copy_stream_fallback(struct copy_stream_struct *stp)
13095{
13096 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13097 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13098 }
13099 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13100 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13101 rb_eEOFError, (VALUE)0);
13102 return Qnil;
13103}
13104
13105static VALUE
13106copy_stream_body(VALUE arg)
13107{
13108 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13109 VALUE src_io = stp->src, dst_io = stp->dst;
13110 const int common_oflags = 0
13111#ifdef O_NOCTTY
13112 | O_NOCTTY
13113#endif
13114 ;
13115
13116 stp->th = rb_thread_current();
13117
13118 stp->total = 0;
13119
13120 if (src_io == argf ||
13121 !(RB_TYPE_P(src_io, T_FILE) ||
13122 RB_TYPE_P(src_io, T_STRING) ||
13123 rb_respond_to(src_io, rb_intern("to_path")))) {
13124 stp->src_fptr = NULL;
13125 }
13126 else {
13127 int stat_ret;
13128 VALUE tmp_io = rb_io_check_io(src_io);
13129 if (!NIL_P(tmp_io)) {
13130 src_io = tmp_io;
13131 }
13132 else if (!RB_TYPE_P(src_io, T_FILE)) {
13133 VALUE args[2];
13134 FilePathValue(src_io);
13135 args[0] = src_io;
13136 args[1] = INT2NUM(O_RDONLY|common_oflags);
13137 src_io = rb_class_new_instance(2, args, rb_cFile);
13138 stp->src = src_io;
13139 stp->close_src = 1;
13140 }
13141 RB_IO_POINTER(src_io, stp->src_fptr);
13142 rb_io_check_byte_readable(stp->src_fptr);
13143
13144 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13145 if (stat_ret < 0) {
13146 stp->syserr = "fstat";
13147 stp->error_no = errno;
13148 return Qnil;
13149 }
13150 }
13151
13152 if (dst_io == argf ||
13153 !(RB_TYPE_P(dst_io, T_FILE) ||
13154 RB_TYPE_P(dst_io, T_STRING) ||
13155 rb_respond_to(dst_io, rb_intern("to_path")))) {
13156 stp->dst_fptr = NULL;
13157 }
13158 else {
13159 int stat_ret;
13160 VALUE tmp_io = rb_io_check_io(dst_io);
13161 if (!NIL_P(tmp_io)) {
13162 dst_io = GetWriteIO(tmp_io);
13163 }
13164 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13165 VALUE args[3];
13166 FilePathValue(dst_io);
13167 args[0] = dst_io;
13168 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13169 args[2] = INT2FIX(0666);
13170 dst_io = rb_class_new_instance(3, args, rb_cFile);
13171 stp->dst = dst_io;
13172 stp->close_dst = 1;
13173 }
13174 else {
13175 dst_io = GetWriteIO(dst_io);
13176 stp->dst = dst_io;
13177 }
13178 RB_IO_POINTER(dst_io, stp->dst_fptr);
13179 rb_io_check_writable(stp->dst_fptr);
13180
13181 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13182 if (stat_ret < 0) {
13183 stp->syserr = "fstat";
13184 stp->error_no = errno;
13185 return Qnil;
13186 }
13187 }
13188
13189#ifdef O_BINARY
13190 if (stp->src_fptr)
13191 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13192#endif
13193 if (stp->dst_fptr)
13194 io_ascii8bit_binmode(stp->dst_fptr);
13195
13196 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13197 size_t len = stp->src_fptr->rbuf.len;
13198 VALUE str;
13199 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13200 len = (size_t)stp->copy_length;
13201 }
13202 str = rb_str_buf_new(len);
13203 rb_str_resize(str,len);
13204 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13205 if (stp->dst_fptr) { /* IO or filename */
13206 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13207 rb_sys_fail_on_write(stp->dst_fptr);
13208 }
13209 else /* others such as StringIO */
13210 rb_io_write(dst_io, str);
13211 rb_str_resize(str, 0);
13212 stp->total += len;
13213 if (stp->copy_length >= (rb_off_t)0)
13214 stp->copy_length -= len;
13215 }
13216
13217 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13218 rb_raise(rb_eIOError, "flush failed");
13219 }
13220
13221 if (stp->copy_length == 0)
13222 return Qnil;
13223
13224 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13225 return copy_stream_fallback(stp);
13226 }
13227
13228 rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
13229 return Qnil;
13230}
13231
13232static VALUE
13233copy_stream_finalize(VALUE arg)
13234{
13235 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13236
13237#ifdef HAVE_FCOPYFILE
13238 if (stp->copyfile_state) {
13239 copyfile_state_free(stp->copyfile_state);
13240 }
13241#endif
13242
13243 if (stp->close_src) {
13244 rb_io_close_m(stp->src);
13245 }
13246 if (stp->close_dst) {
13247 rb_io_close_m(stp->dst);
13248 }
13249 if (stp->syserr) {
13250 rb_syserr_fail(stp->error_no, stp->syserr);
13251 }
13252 if (stp->notimp) {
13253 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13254 }
13255 return Qnil;
13256}
13257
13258/*
13259 * call-seq:
13260 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13261 *
13262 * Copies from the given +src+ to the given +dst+,
13263 * returning the number of bytes copied.
13264 *
13265 * - The given +src+ must be one of the following:
13266 *
13267 * - The path to a readable file, from which source data is to be read.
13268 * - An \IO-like object, opened for reading and capable of responding
13269 * to method +:readpartial+ or method +:read+.
13270 *
13271 * - The given +dst+ must be one of the following:
13272 *
13273 * - The path to a writable file, to which data is to be written.
13274 * - An \IO-like object, opened for writing and capable of responding
13275 * to method +:write+.
13276 *
13277 * The examples here use file <tt>t.txt</tt> as source:
13278 *
13279 * File.read('t.txt')
13280 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13281 * File.read('t.txt').size # => 47
13282 *
13283 * If only arguments +src+ and +dst+ are given,
13284 * the entire source stream is copied:
13285 *
13286 * # Paths.
13287 * IO.copy_stream('t.txt', 't.tmp') # => 47
13288 *
13289 * # IOs (recall that a File is also an IO).
13290 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13291 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13292 * IO.copy_stream(src_io, dst_io) # => 47
13293 * src_io.close
13294 * dst_io.close
13295 *
13296 * With argument +src_length+ a non-negative integer,
13297 * no more than that many bytes are copied:
13298 *
13299 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13300 * File.read('t.tmp') # => "First line"
13301 *
13302 * With argument +src_offset+ also given,
13303 * the source stream is read beginning at that offset:
13304 *
13305 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13306 * IO.read('t.tmp') # => "Second line"
13307 *
13308 */
13309static VALUE
13310rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13311{
13312 VALUE src, dst, length, src_offset;
13313 struct copy_stream_struct st;
13314
13315 MEMZERO(&st, struct copy_stream_struct, 1);
13316
13317 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13318
13319 st.src = src;
13320 st.dst = dst;
13321
13322 st.src_fptr = NULL;
13323 st.dst_fptr = NULL;
13324
13325 if (NIL_P(length))
13326 st.copy_length = (rb_off_t)-1;
13327 else
13328 st.copy_length = NUM2OFFT(length);
13329
13330 if (NIL_P(src_offset))
13331 st.src_offset = (rb_off_t)-1;
13332 else
13333 st.src_offset = NUM2OFFT(src_offset);
13334
13335 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13336
13337 return OFFT2NUM(st.total);
13338}
13339
13340/*
13341 * call-seq:
13342 * external_encoding -> encoding or nil
13343 *
13344 * Returns the Encoding object that represents the encoding of the stream,
13345 * or +nil+ if the stream is in write mode and no encoding is specified.
13346 *
13347 * See {Encodings}[rdoc-ref:File@Encodings].
13348 *
13349 */
13350
13351static VALUE
13352rb_io_external_encoding(VALUE io)
13353{
13354 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13355
13356 if (fptr->encs.enc2) {
13357 return rb_enc_from_encoding(fptr->encs.enc2);
13358 }
13359 if (fptr->mode & FMODE_WRITABLE) {
13360 if (fptr->encs.enc)
13361 return rb_enc_from_encoding(fptr->encs.enc);
13362 return Qnil;
13363 }
13364 return rb_enc_from_encoding(io_read_encoding(fptr));
13365}
13366
13367/*
13368 * call-seq:
13369 * internal_encoding -> encoding or nil
13370 *
13371 * Returns the Encoding object that represents the encoding of the internal string,
13372 * if conversion is specified,
13373 * or +nil+ otherwise.
13374 *
13375 * See {Encodings}[rdoc-ref:File@Encodings].
13376 *
13377 */
13378
13379static VALUE
13380rb_io_internal_encoding(VALUE io)
13381{
13382 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13383
13384 if (!fptr->encs.enc2) return Qnil;
13385 return rb_enc_from_encoding(io_read_encoding(fptr));
13386}
13387
13388/*
13389 * call-seq:
13390 * set_encoding(ext_enc) -> self
13391 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13392 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13393 *
13394 * See {Encodings}[rdoc-ref:File@Encodings].
13395 *
13396 * Argument +ext_enc+, if given, must be an Encoding object;
13397 * it is assigned as the encoding for the stream.
13398 *
13399 * Argument +int_enc+, if given, must be an Encoding object;
13400 * it is assigned as the encoding for the internal string.
13401 *
13402 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13403 * containing two colon-separated encoding names;
13404 * corresponding Encoding objects are assigned as the external
13405 * and internal encodings for the stream.
13406 *
13407 * Optional keyword arguments +enc_opts+ specify
13408 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13409 *
13410 */
13411
13412static VALUE
13413rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13414{
13415 rb_io_t *fptr;
13416 VALUE v1, v2, opt;
13417
13418 if (!RB_TYPE_P(io, T_FILE)) {
13419 return forward(io, id_set_encoding, argc, argv);
13420 }
13421
13422 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13423 GetOpenFile(io, fptr);
13424 io_encoding_set(fptr, v1, v2, opt);
13425 return io;
13426}
13427
13428void
13429rb_stdio_set_default_encoding(void)
13430{
13431 VALUE val = Qnil;
13432
13433#ifdef _WIN32
13434 if (isatty(fileno(stdin))) {
13435 rb_encoding *external = rb_locale_encoding();
13436 rb_encoding *internal = rb_default_internal_encoding();
13437 if (!internal) internal = rb_default_external_encoding();
13438 io_encoding_set(RFILE(rb_stdin)->fptr,
13439 rb_enc_from_encoding(external),
13440 rb_enc_from_encoding(internal),
13441 Qnil);
13442 }
13443 else
13444#endif
13445 rb_io_set_encoding(1, &val, rb_stdin);
13446 rb_io_set_encoding(1, &val, rb_stdout);
13447 rb_io_set_encoding(1, &val, rb_stderr);
13448}
13449
13450static inline int
13451global_argf_p(VALUE arg)
13452{
13453 return arg == argf;
13454}
13455
13456typedef VALUE (*argf_encoding_func)(VALUE io);
13457
13458static VALUE
13459argf_encoding(VALUE argf, argf_encoding_func func)
13460{
13461 if (!RTEST(ARGF.current_file)) {
13462 return rb_enc_default_external();
13463 }
13464 return func(rb_io_check_io(ARGF.current_file));
13465}
13466
13467/*
13468 * call-seq:
13469 * ARGF.external_encoding -> encoding
13470 *
13471 * Returns the external encoding for files read from ARGF as an Encoding
13472 * object. The external encoding is the encoding of the text as stored in a
13473 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13474 * represent this text within Ruby.
13475 *
13476 * To set the external encoding use ARGF.set_encoding.
13477 *
13478 * For example:
13479 *
13480 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13481 *
13482 */
13483static VALUE
13484argf_external_encoding(VALUE argf)
13485{
13486 return argf_encoding(argf, rb_io_external_encoding);
13487}
13488
13489/*
13490 * call-seq:
13491 * ARGF.internal_encoding -> encoding
13492 *
13493 * Returns the internal encoding for strings read from ARGF as an
13494 * Encoding object.
13495 *
13496 * If ARGF.set_encoding has been called with two encoding names, the second
13497 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13498 * value is returned. Failing that, if a default external encoding was
13499 * specified on the command-line, that value is used. If the encoding is
13500 * unknown, +nil+ is returned.
13501 */
13502static VALUE
13503argf_internal_encoding(VALUE argf)
13504{
13505 return argf_encoding(argf, rb_io_internal_encoding);
13506}
13507
13508/*
13509 * call-seq:
13510 * ARGF.set_encoding(ext_enc) -> ARGF
13511 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13512 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13513 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13514 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13515 *
13516 * If single argument is specified, strings read from ARGF are tagged with
13517 * the encoding specified.
13518 *
13519 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13520 * the read string is converted from the first encoding (external encoding)
13521 * to the second encoding (internal encoding), then tagged with the second
13522 * encoding.
13523 *
13524 * If two arguments are specified, they must be encoding objects or encoding
13525 * names. Again, the first specifies the external encoding; the second
13526 * specifies the internal encoding.
13527 *
13528 * If the external encoding and the internal encoding are specified, the
13529 * optional Hash argument can be used to adjust the conversion process. The
13530 * structure of this hash is explained in the String#encode documentation.
13531 *
13532 * For example:
13533 *
13534 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13535 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13536 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13537 * # to UTF-8.
13538 */
13539static VALUE
13540argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13541{
13542 rb_io_t *fptr;
13543
13544 if (!next_argv()) {
13545 rb_raise(rb_eArgError, "no stream to set encoding");
13546 }
13547 rb_io_set_encoding(argc, argv, ARGF.current_file);
13548 GetOpenFile(ARGF.current_file, fptr);
13549 ARGF.encs = fptr->encs;
13550 return argf;
13551}
13552
13553/*
13554 * call-seq:
13555 * ARGF.tell -> Integer
13556 * ARGF.pos -> Integer
13557 *
13558 * Returns the current offset (in bytes) of the current file in ARGF.
13559 *
13560 * ARGF.pos #=> 0
13561 * ARGF.gets #=> "This is line one\n"
13562 * ARGF.pos #=> 17
13563 *
13564 */
13565static VALUE
13566argf_tell(VALUE argf)
13567{
13568 if (!next_argv()) {
13569 rb_raise(rb_eArgError, "no stream to tell");
13570 }
13571 ARGF_FORWARD(0, 0);
13572 return rb_io_tell(ARGF.current_file);
13573}
13574
13575/*
13576 * call-seq:
13577 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13578 *
13579 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13580 * the value of _whence_. See IO#seek for further details.
13581 */
13582static VALUE
13583argf_seek_m(int argc, VALUE *argv, VALUE argf)
13584{
13585 if (!next_argv()) {
13586 rb_raise(rb_eArgError, "no stream to seek");
13587 }
13588 ARGF_FORWARD(argc, argv);
13589 return rb_io_seek_m(argc, argv, ARGF.current_file);
13590}
13591
13592/*
13593 * call-seq:
13594 * ARGF.pos = position -> Integer
13595 *
13596 * Seeks to the position given by _position_ (in bytes) in ARGF.
13597 *
13598 * For example:
13599 *
13600 * ARGF.pos = 17
13601 * ARGF.gets #=> "This is line two\n"
13602 */
13603static VALUE
13604argf_set_pos(VALUE argf, VALUE offset)
13605{
13606 if (!next_argv()) {
13607 rb_raise(rb_eArgError, "no stream to set position");
13608 }
13609 ARGF_FORWARD(1, &offset);
13610 return rb_io_set_pos(ARGF.current_file, offset);
13611}
13612
13613/*
13614 * call-seq:
13615 * ARGF.rewind -> 0
13616 *
13617 * Positions the current file to the beginning of input, resetting
13618 * ARGF.lineno to zero.
13619 *
13620 * ARGF.readline #=> "This is line one\n"
13621 * ARGF.rewind #=> 0
13622 * ARGF.lineno #=> 0
13623 * ARGF.readline #=> "This is line one\n"
13624 */
13625static VALUE
13626argf_rewind(VALUE argf)
13627{
13628 VALUE ret;
13629 int old_lineno;
13630
13631 if (!next_argv()) {
13632 rb_raise(rb_eArgError, "no stream to rewind");
13633 }
13634 ARGF_FORWARD(0, 0);
13635 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13636 ret = rb_io_rewind(ARGF.current_file);
13637 if (!global_argf_p(argf)) {
13638 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13639 }
13640 return ret;
13641}
13642
13643/*
13644 * call-seq:
13645 * ARGF.fileno -> integer
13646 * ARGF.to_i -> integer
13647 *
13648 * Returns an integer representing the numeric file descriptor for
13649 * the current file. Raises an ArgumentError if there isn't a current file.
13650 *
13651 * ARGF.fileno #=> 3
13652 */
13653static VALUE
13654argf_fileno(VALUE argf)
13655{
13656 if (!next_argv()) {
13657 rb_raise(rb_eArgError, "no stream");
13658 }
13659 ARGF_FORWARD(0, 0);
13660 return rb_io_fileno(ARGF.current_file);
13661}
13662
13663/*
13664 * call-seq:
13665 * ARGF.to_io -> IO
13666 *
13667 * Returns an IO object representing the current file. This will be a
13668 * File object unless the current file is a stream such as STDIN.
13669 *
13670 * For example:
13671 *
13672 * ARGF.to_io #=> #<File:glark.txt>
13673 * ARGF.to_io #=> #<IO:<STDIN>>
13674 */
13675static VALUE
13676argf_to_io(VALUE argf)
13677{
13678 next_argv();
13679 ARGF_FORWARD(0, 0);
13680 return ARGF.current_file;
13681}
13682
13683/*
13684 * call-seq:
13685 * ARGF.eof? -> true or false
13686 * ARGF.eof -> true or false
13687 *
13688 * Returns true if the current file in ARGF is at end of file, i.e. it has
13689 * no data to read. The stream must be opened for reading or an IOError
13690 * will be raised.
13691 *
13692 * $ echo "eof" | ruby argf.rb
13693 *
13694 * ARGF.eof? #=> false
13695 * 3.times { ARGF.readchar }
13696 * ARGF.eof? #=> false
13697 * ARGF.readchar #=> "\n"
13698 * ARGF.eof? #=> true
13699 */
13700
13701static VALUE
13702argf_eof(VALUE argf)
13703{
13704 next_argv();
13705 if (RTEST(ARGF.current_file)) {
13706 if (ARGF.init_p == 0) return Qtrue;
13707 next_argv();
13708 ARGF_FORWARD(0, 0);
13709 if (rb_io_eof(ARGF.current_file)) {
13710 return Qtrue;
13711 }
13712 }
13713 return Qfalse;
13714}
13715
13716/*
13717 * call-seq:
13718 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13719 *
13720 * Reads _length_ bytes from ARGF. The files named on the command line
13721 * are concatenated and treated as a single file by this method, so when
13722 * called without arguments the contents of this pseudo file are returned in
13723 * their entirety.
13724 *
13725 * _length_ must be a non-negative integer or +nil+.
13726 *
13727 * If _length_ is a positive integer, +read+ tries to read
13728 * _length_ bytes without any conversion (binary mode).
13729 * It returns +nil+ if an EOF is encountered before anything can be read.
13730 * Fewer than _length_ bytes are returned if an EOF is encountered during
13731 * the read.
13732 * In the case of an integer _length_, the resulting string is always
13733 * in ASCII-8BIT encoding.
13734 *
13735 * If _length_ is omitted or is +nil+, it reads until EOF
13736 * and the encoding conversion is applied, if applicable.
13737 * A string is returned even if EOF is encountered before any data is read.
13738 *
13739 * If _length_ is zero, it returns an empty string (<code>""</code>).
13740 *
13741 * If the optional _outbuf_ argument is present,
13742 * it must reference a String, which will receive the data.
13743 * The _outbuf_ will contain only the received data after the method call
13744 * even if it is not empty at the beginning.
13745 *
13746 * For example:
13747 *
13748 * $ echo "small" > small.txt
13749 * $ echo "large" > large.txt
13750 * $ ./glark.rb small.txt large.txt
13751 *
13752 * ARGF.read #=> "small\nlarge"
13753 * ARGF.read(200) #=> "small\nlarge"
13754 * ARGF.read(2) #=> "sm"
13755 * ARGF.read(0) #=> ""
13756 *
13757 * Note that this method behaves like the fread() function in C.
13758 * This means it retries to invoke read(2) system calls to read data
13759 * with the specified length.
13760 * If you need the behavior like a single read(2) system call,
13761 * consider ARGF#readpartial or ARGF#read_nonblock.
13762 */
13763
13764static VALUE
13765argf_read(int argc, VALUE *argv, VALUE argf)
13766{
13767 VALUE tmp, str, length;
13768 long len = 0;
13769
13770 rb_scan_args(argc, argv, "02", &length, &str);
13771 if (!NIL_P(length)) {
13772 len = NUM2LONG(argv[0]);
13773 }
13774 if (!NIL_P(str)) {
13775 StringValue(str);
13776 rb_str_resize(str,0);
13777 argv[1] = Qnil;
13778 }
13779
13780 retry:
13781 if (!next_argv()) {
13782 return str;
13783 }
13784 if (ARGF_GENERIC_INPUT_P()) {
13785 tmp = argf_forward(argc, argv, argf);
13786 }
13787 else {
13788 tmp = io_read(argc, argv, ARGF.current_file);
13789 }
13790 if (NIL_P(str)) str = tmp;
13791 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13792 if (NIL_P(tmp) || NIL_P(length)) {
13793 if (ARGF.next_p != -1) {
13794 argf_close(argf);
13795 ARGF.next_p = 1;
13796 goto retry;
13797 }
13798 }
13799 else if (argc >= 1) {
13800 long slen = RSTRING_LEN(str);
13801 if (slen < len) {
13802 argv[0] = LONG2NUM(len - slen);
13803 goto retry;
13804 }
13805 }
13806 return str;
13807}
13808
13810 int argc;
13811 VALUE *argv;
13812 VALUE argf;
13813};
13814
13815static VALUE
13816argf_forward_call(VALUE arg)
13817{
13818 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13819 argf_forward(p->argc, p->argv, p->argf);
13820 return Qnil;
13821}
13822
13823static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13824 int nonblock);
13825
13826/*
13827 * call-seq:
13828 * ARGF.readpartial(maxlen) -> string
13829 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13830 *
13831 * Reads at most _maxlen_ bytes from the ARGF stream.
13832 *
13833 * If the optional _outbuf_ argument is present,
13834 * it must reference a String, which will receive the data.
13835 * The _outbuf_ will contain only the received data after the method call
13836 * even if it is not empty at the beginning.
13837 *
13838 * It raises EOFError on end of ARGF stream.
13839 * Since ARGF stream is a concatenation of multiple files,
13840 * internally EOF is occur for each file.
13841 * ARGF.readpartial returns empty strings for EOFs except the last one and
13842 * raises EOFError for the last one.
13843 *
13844 */
13845
13846static VALUE
13847argf_readpartial(int argc, VALUE *argv, VALUE argf)
13848{
13849 return argf_getpartial(argc, argv, argf, Qnil, 0);
13850}
13851
13852/*
13853 * call-seq:
13854 * ARGF.read_nonblock(maxlen[, options]) -> string
13855 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13856 *
13857 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13858 */
13859
13860static VALUE
13861argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13862{
13863 VALUE opts;
13864
13865 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13866
13867 if (!NIL_P(opts))
13868 argc--;
13869
13870 return argf_getpartial(argc, argv, argf, opts, 1);
13871}
13872
13873static VALUE
13874argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13875{
13876 VALUE tmp, str, length;
13877 int no_exception;
13878
13879 rb_scan_args(argc, argv, "11", &length, &str);
13880 if (!NIL_P(str)) {
13881 StringValue(str);
13882 argv[1] = str;
13883 }
13884 no_exception = no_exception_p(opts);
13885
13886 if (!next_argv()) {
13887 if (!NIL_P(str)) {
13888 rb_str_resize(str, 0);
13889 }
13890 rb_eof_error();
13891 }
13892 if (ARGF_GENERIC_INPUT_P()) {
13893 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13894 struct argf_call_arg arg;
13895 arg.argc = argc;
13896 arg.argv = argv;
13897 arg.argf = argf;
13898 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
13899 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
13900 }
13901 else {
13902 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13903 }
13904 if (NIL_P(tmp)) {
13905 if (ARGF.next_p == -1) {
13906 return io_nonblock_eof(no_exception);
13907 }
13908 argf_close(argf);
13909 ARGF.next_p = 1;
13910 if (RARRAY_LEN(ARGF.argv) == 0) {
13911 return io_nonblock_eof(no_exception);
13912 }
13913 if (NIL_P(str))
13914 str = rb_str_new(NULL, 0);
13915 return str;
13916 }
13917 return tmp;
13918}
13919
13920/*
13921 * call-seq:
13922 * ARGF.getc -> String or nil
13923 *
13924 * Reads the next character from ARGF and returns it as a String. Returns
13925 * +nil+ at the end of the stream.
13926 *
13927 * ARGF treats the files named on the command line as a single file created
13928 * by concatenating their contents. After returning the last character of the
13929 * first file, it returns the first character of the second file, and so on.
13930 *
13931 * For example:
13932 *
13933 * $ echo "foo" > file
13934 * $ ruby argf.rb file
13935 *
13936 * ARGF.getc #=> "f"
13937 * ARGF.getc #=> "o"
13938 * ARGF.getc #=> "o"
13939 * ARGF.getc #=> "\n"
13940 * ARGF.getc #=> nil
13941 * ARGF.getc #=> nil
13942 */
13943static VALUE
13944argf_getc(VALUE argf)
13945{
13946 VALUE ch;
13947
13948 retry:
13949 if (!next_argv()) return Qnil;
13950 if (ARGF_GENERIC_INPUT_P()) {
13951 ch = forward_current(rb_intern("getc"), 0, 0);
13952 }
13953 else {
13954 ch = rb_io_getc(ARGF.current_file);
13955 }
13956 if (NIL_P(ch) && ARGF.next_p != -1) {
13957 argf_close(argf);
13958 ARGF.next_p = 1;
13959 goto retry;
13960 }
13961
13962 return ch;
13963}
13964
13965/*
13966 * call-seq:
13967 * ARGF.getbyte -> Integer or nil
13968 *
13969 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
13970 * the end of the stream.
13971 *
13972 * For example:
13973 *
13974 * $ echo "foo" > file
13975 * $ ruby argf.rb file
13976 *
13977 * ARGF.getbyte #=> 102
13978 * ARGF.getbyte #=> 111
13979 * ARGF.getbyte #=> 111
13980 * ARGF.getbyte #=> 10
13981 * ARGF.getbyte #=> nil
13982 */
13983static VALUE
13984argf_getbyte(VALUE argf)
13985{
13986 VALUE ch;
13987
13988 retry:
13989 if (!next_argv()) return Qnil;
13990 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
13991 ch = forward_current(rb_intern("getbyte"), 0, 0);
13992 }
13993 else {
13994 ch = rb_io_getbyte(ARGF.current_file);
13995 }
13996 if (NIL_P(ch) && ARGF.next_p != -1) {
13997 argf_close(argf);
13998 ARGF.next_p = 1;
13999 goto retry;
14000 }
14001
14002 return ch;
14003}
14004
14005/*
14006 * call-seq:
14007 * ARGF.readchar -> String or nil
14008 *
14009 * Reads the next character from ARGF and returns it as a String. Raises
14010 * an EOFError after the last character of the last file has been read.
14011 *
14012 * For example:
14013 *
14014 * $ echo "foo" > file
14015 * $ ruby argf.rb file
14016 *
14017 * ARGF.readchar #=> "f"
14018 * ARGF.readchar #=> "o"
14019 * ARGF.readchar #=> "o"
14020 * ARGF.readchar #=> "\n"
14021 * ARGF.readchar #=> end of file reached (EOFError)
14022 */
14023static VALUE
14024argf_readchar(VALUE argf)
14025{
14026 VALUE ch;
14027
14028 retry:
14029 if (!next_argv()) rb_eof_error();
14030 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14031 ch = forward_current(rb_intern("getc"), 0, 0);
14032 }
14033 else {
14034 ch = rb_io_getc(ARGF.current_file);
14035 }
14036 if (NIL_P(ch) && ARGF.next_p != -1) {
14037 argf_close(argf);
14038 ARGF.next_p = 1;
14039 goto retry;
14040 }
14041
14042 return ch;
14043}
14044
14045/*
14046 * call-seq:
14047 * ARGF.readbyte -> Integer
14048 *
14049 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14050 * an EOFError after the last byte of the last file has been read.
14051 *
14052 * For example:
14053 *
14054 * $ echo "foo" > file
14055 * $ ruby argf.rb file
14056 *
14057 * ARGF.readbyte #=> 102
14058 * ARGF.readbyte #=> 111
14059 * ARGF.readbyte #=> 111
14060 * ARGF.readbyte #=> 10
14061 * ARGF.readbyte #=> end of file reached (EOFError)
14062 */
14063static VALUE
14064argf_readbyte(VALUE argf)
14065{
14066 VALUE c;
14067
14068 NEXT_ARGF_FORWARD(0, 0);
14069 c = argf_getbyte(argf);
14070 if (NIL_P(c)) {
14071 rb_eof_error();
14072 }
14073 return c;
14074}
14075
14076#define FOREACH_ARGF() while (next_argv())
14077
14078static VALUE
14079argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14080{
14081 const VALUE current = ARGF.current_file;
14082 rb_yield_values2(argc, argv);
14083 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14085 }
14086 return Qnil;
14087}
14088
14089#define ARGF_block_call(mid, argc, argv, func, argf) \
14090 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14091 func, argf, rb_keyword_given_p())
14092
14093static void
14094argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14095{
14096 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14097 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14098}
14099
14100static VALUE
14101argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14102{
14103 if (!global_argf_p(argf)) {
14104 ARGF.last_lineno = ++ARGF.lineno;
14105 }
14106 return argf_block_call_i(i, argf, argc, argv, blockarg);
14107}
14108
14109static void
14110argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14111{
14112 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14113 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14114}
14115
14116/*
14117 * call-seq:
14118 * ARGF.each(sep=$/) {|line| block } -> ARGF
14119 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14120 * ARGF.each(...) -> an_enumerator
14121 *
14122 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14123 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14124 * ARGF.each_line(...) -> an_enumerator
14125 *
14126 * Returns an enumerator which iterates over each line (separated by _sep_,
14127 * which defaults to your platform's newline character) of each file in
14128 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14129 * block, otherwise an enumerator is returned.
14130 * The optional _limit_ argument is an Integer specifying the maximum
14131 * length of each line; longer lines will be split according to this limit.
14132 *
14133 * This method allows you to treat the files supplied on the command line as
14134 * a single file consisting of the concatenation of each named file. After
14135 * the last line of the first file has been returned, the first line of the
14136 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14137 * used to determine the filename of the current line and line number of the
14138 * whole input, respectively.
14139 *
14140 * For example, the following code prints out each line of each named file
14141 * prefixed with its line number, displaying the filename once per file:
14142 *
14143 * ARGF.each_line do |line|
14144 * puts ARGF.filename if ARGF.file.lineno == 1
14145 * puts "#{ARGF.file.lineno}: #{line}"
14146 * end
14147 *
14148 * While the following code prints only the first file's name at first, and
14149 * the contents with line number counted through all named files.
14150 *
14151 * ARGF.each_line do |line|
14152 * puts ARGF.filename if ARGF.lineno == 1
14153 * puts "#{ARGF.lineno}: #{line}"
14154 * end
14155 */
14156static VALUE
14157argf_each_line(int argc, VALUE *argv, VALUE argf)
14158{
14159 RETURN_ENUMERATOR(argf, argc, argv);
14160 FOREACH_ARGF() {
14161 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14162 }
14163 return argf;
14164}
14165
14166/*
14167 * call-seq:
14168 * ARGF.each_byte {|byte| block } -> ARGF
14169 * ARGF.each_byte -> an_enumerator
14170 *
14171 * Iterates over each byte of each file in +ARGV+.
14172 * A byte is returned as an Integer in the range 0..255.
14173 *
14174 * This method allows you to treat the files supplied on the command line as
14175 * a single file consisting of the concatenation of each named file. After
14176 * the last byte of the first file has been returned, the first byte of the
14177 * second file is returned. The ARGF.filename method can be used to
14178 * determine the filename of the current byte.
14179 *
14180 * If no block is given, an enumerator is returned instead.
14181 *
14182 * For example:
14183 *
14184 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14185 *
14186 */
14187static VALUE
14188argf_each_byte(VALUE argf)
14189{
14190 RETURN_ENUMERATOR(argf, 0, 0);
14191 FOREACH_ARGF() {
14192 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14193 }
14194 return argf;
14195}
14196
14197/*
14198 * call-seq:
14199 * ARGF.each_char {|char| block } -> ARGF
14200 * ARGF.each_char -> an_enumerator
14201 *
14202 * Iterates over each character of each file in ARGF.
14203 *
14204 * This method allows you to treat the files supplied on the command line as
14205 * a single file consisting of the concatenation of each named file. After
14206 * the last character of the first file has been returned, the first
14207 * character of the second file is returned. The ARGF.filename method can
14208 * be used to determine the name of the file in which the current character
14209 * appears.
14210 *
14211 * If no block is given, an enumerator is returned instead.
14212 */
14213static VALUE
14214argf_each_char(VALUE argf)
14215{
14216 RETURN_ENUMERATOR(argf, 0, 0);
14217 FOREACH_ARGF() {
14218 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14219 }
14220 return argf;
14221}
14222
14223/*
14224 * call-seq:
14225 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14226 * ARGF.each_codepoint -> an_enumerator
14227 *
14228 * Iterates over each codepoint of each file in ARGF.
14229 *
14230 * This method allows you to treat the files supplied on the command line as
14231 * a single file consisting of the concatenation of each named file. After
14232 * the last codepoint of the first file has been returned, the first
14233 * codepoint of the second file is returned. The ARGF.filename method can
14234 * be used to determine the name of the file in which the current codepoint
14235 * appears.
14236 *
14237 * If no block is given, an enumerator is returned instead.
14238 */
14239static VALUE
14240argf_each_codepoint(VALUE argf)
14241{
14242 RETURN_ENUMERATOR(argf, 0, 0);
14243 FOREACH_ARGF() {
14244 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14245 }
14246 return argf;
14247}
14248
14249/*
14250 * call-seq:
14251 * ARGF.filename -> String
14252 * ARGF.path -> String
14253 *
14254 * Returns the current filename. "-" is returned when the current file is
14255 * STDIN.
14256 *
14257 * For example:
14258 *
14259 * $ echo "foo" > foo
14260 * $ echo "bar" > bar
14261 * $ echo "glark" > glark
14262 *
14263 * $ ruby argf.rb foo bar glark
14264 *
14265 * ARGF.filename #=> "foo"
14266 * ARGF.read(5) #=> "foo\nb"
14267 * ARGF.filename #=> "bar"
14268 * ARGF.skip
14269 * ARGF.filename #=> "glark"
14270 */
14271static VALUE
14272argf_filename(VALUE argf)
14273{
14274 next_argv();
14275 return ARGF.filename;
14276}
14277
14278static VALUE
14279argf_filename_getter(ID id, VALUE *var)
14280{
14281 return argf_filename(*var);
14282}
14283
14284/*
14285 * call-seq:
14286 * ARGF.file -> IO or File object
14287 *
14288 * Returns the current file as an IO or File object.
14289 * <code>$stdin</code> is returned when the current file is STDIN.
14290 *
14291 * For example:
14292 *
14293 * $ echo "foo" > foo
14294 * $ echo "bar" > bar
14295 *
14296 * $ ruby argf.rb foo bar
14297 *
14298 * ARGF.file #=> #<File:foo>
14299 * ARGF.read(5) #=> "foo\nb"
14300 * ARGF.file #=> #<File:bar>
14301 */
14302static VALUE
14303argf_file(VALUE argf)
14304{
14305 next_argv();
14306 return ARGF.current_file;
14307}
14308
14309/*
14310 * call-seq:
14311 * ARGF.binmode -> ARGF
14312 *
14313 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14314 * be reset to non-binary mode. This option has the following effects:
14315 *
14316 * * Newline conversion is disabled.
14317 * * Encoding conversion is disabled.
14318 * * Content is treated as ASCII-8BIT.
14319 */
14320static VALUE
14321argf_binmode_m(VALUE argf)
14322{
14323 ARGF.binmode = 1;
14324 next_argv();
14325 ARGF_FORWARD(0, 0);
14326 rb_io_ascii8bit_binmode(ARGF.current_file);
14327 return argf;
14328}
14329
14330/*
14331 * call-seq:
14332 * ARGF.binmode? -> true or false
14333 *
14334 * Returns true if ARGF is being read in binary mode; false otherwise.
14335 * To enable binary mode use ARGF.binmode.
14336 *
14337 * For example:
14338 *
14339 * ARGF.binmode? #=> false
14340 * ARGF.binmode
14341 * ARGF.binmode? #=> true
14342 */
14343static VALUE
14344argf_binmode_p(VALUE argf)
14345{
14346 return RBOOL(ARGF.binmode);
14347}
14348
14349/*
14350 * call-seq:
14351 * ARGF.skip -> ARGF
14352 *
14353 * Sets the current file to the next file in ARGV. If there aren't any more
14354 * files it has no effect.
14355 *
14356 * For example:
14357 *
14358 * $ ruby argf.rb foo bar
14359 * ARGF.filename #=> "foo"
14360 * ARGF.skip
14361 * ARGF.filename #=> "bar"
14362 */
14363static VALUE
14364argf_skip(VALUE argf)
14365{
14366 if (ARGF.init_p && ARGF.next_p == 0) {
14367 argf_close(argf);
14368 ARGF.next_p = 1;
14369 }
14370 return argf;
14371}
14372
14373/*
14374 * call-seq:
14375 * ARGF.close -> ARGF
14376 *
14377 * Closes the current file and skips to the next file in ARGV. If there are
14378 * no more files to open, just closes the current file. STDIN will not be
14379 * closed.
14380 *
14381 * For example:
14382 *
14383 * $ ruby argf.rb foo bar
14384 *
14385 * ARGF.filename #=> "foo"
14386 * ARGF.close
14387 * ARGF.filename #=> "bar"
14388 * ARGF.close
14389 */
14390static VALUE
14391argf_close_m(VALUE argf)
14392{
14393 next_argv();
14394 argf_close(argf);
14395 if (ARGF.next_p != -1) {
14396 ARGF.next_p = 1;
14397 }
14398 ARGF.lineno = 0;
14399 return argf;
14400}
14401
14402/*
14403 * call-seq:
14404 * ARGF.closed? -> true or false
14405 *
14406 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14407 * ARGF.close to actually close the current file.
14408 */
14409static VALUE
14410argf_closed(VALUE argf)
14411{
14412 next_argv();
14413 ARGF_FORWARD(0, 0);
14414 return rb_io_closed(ARGF.current_file);
14415}
14416
14417/*
14418 * call-seq:
14419 * ARGF.to_s -> String
14420 *
14421 * Returns "ARGF".
14422 */
14423static VALUE
14424argf_to_s(VALUE argf)
14425{
14426 return rb_str_new2("ARGF");
14427}
14428
14429/*
14430 * call-seq:
14431 * ARGF.inplace_mode -> String
14432 *
14433 * Returns the file extension appended to the names of backup copies of
14434 * modified files under in-place edit mode. This value can be set using
14435 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14436 */
14437static VALUE
14438argf_inplace_mode_get(VALUE argf)
14439{
14440 if (!ARGF.inplace) return Qnil;
14441 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14442 return rb_str_dup(ARGF.inplace);
14443}
14444
14445static VALUE
14446opt_i_get(ID id, VALUE *var)
14447{
14448 return argf_inplace_mode_get(*var);
14449}
14450
14451/*
14452 * call-seq:
14453 * ARGF.inplace_mode = ext -> ARGF
14454 *
14455 * Sets the filename extension for in-place editing mode to the given String.
14456 * The backup copy of each file being edited has this value appended to its
14457 * filename.
14458 *
14459 * For example:
14460 *
14461 * $ ruby argf.rb file.txt
14462 *
14463 * ARGF.inplace_mode = '.bak'
14464 * ARGF.each_line do |line|
14465 * print line.sub("foo","bar")
14466 * end
14467 *
14468 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14469 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14470 * "bar".
14471 */
14472static VALUE
14473argf_inplace_mode_set(VALUE argf, VALUE val)
14474{
14475 if (!RTEST(val)) {
14476 ARGF.inplace = Qfalse;
14477 }
14478 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14479 ARGF.inplace = Qnil;
14480 }
14481 else {
14482 ARGF.inplace = rb_str_new_frozen(val);
14483 }
14484 return argf;
14485}
14486
14487static void
14488opt_i_set(VALUE val, ID id, VALUE *var)
14489{
14490 argf_inplace_mode_set(*var, val);
14491}
14492
14493void
14494ruby_set_inplace_mode(const char *suffix)
14495{
14496 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14497}
14498
14499/*
14500 * call-seq:
14501 * ARGF.argv -> ARGV
14502 *
14503 * Returns the +ARGV+ array, which contains the arguments passed to your
14504 * script, one per element.
14505 *
14506 * For example:
14507 *
14508 * $ ruby argf.rb -v glark.txt
14509 *
14510 * ARGF.argv #=> ["-v", "glark.txt"]
14511 *
14512 */
14513static VALUE
14514argf_argv(VALUE argf)
14515{
14516 return ARGF.argv;
14517}
14518
14519static VALUE
14520argf_argv_getter(ID id, VALUE *var)
14521{
14522 return argf_argv(*var);
14523}
14524
14525VALUE
14527{
14528 return ARGF.argv;
14529}
14530
14531/*
14532 * call-seq:
14533 * ARGF.to_write_io -> io
14534 *
14535 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14536 * enabled.
14537 */
14538static VALUE
14539argf_write_io(VALUE argf)
14540{
14541 if (!RTEST(ARGF.current_file)) {
14542 rb_raise(rb_eIOError, "not opened for writing");
14543 }
14544 return GetWriteIO(ARGF.current_file);
14545}
14546
14547/*
14548 * call-seq:
14549 * ARGF.write(string) -> integer
14550 *
14551 * Writes _string_ if inplace mode.
14552 */
14553static VALUE
14554argf_write(VALUE argf, VALUE str)
14555{
14556 return rb_io_write(argf_write_io(argf), str);
14557}
14558
14559void
14560rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14561{
14562 rb_readwrite_syserr_fail(waiting, errno, mesg);
14563}
14564
14565void
14566rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14567{
14568 VALUE arg, c = Qnil;
14569 arg = mesg ? rb_str_new2(mesg) : Qnil;
14570 switch (waiting) {
14571 case RB_IO_WAIT_WRITABLE:
14572 switch (n) {
14573 case EAGAIN:
14574 c = rb_eEAGAINWaitWritable;
14575 break;
14576#if EAGAIN != EWOULDBLOCK
14577 case EWOULDBLOCK:
14578 c = rb_eEWOULDBLOCKWaitWritable;
14579 break;
14580#endif
14581 case EINPROGRESS:
14582 c = rb_eEINPROGRESSWaitWritable;
14583 break;
14584 default:
14586 }
14587 break;
14588 case RB_IO_WAIT_READABLE:
14589 switch (n) {
14590 case EAGAIN:
14591 c = rb_eEAGAINWaitReadable;
14592 break;
14593#if EAGAIN != EWOULDBLOCK
14594 case EWOULDBLOCK:
14595 c = rb_eEWOULDBLOCKWaitReadable;
14596 break;
14597#endif
14598 case EINPROGRESS:
14599 c = rb_eEINPROGRESSWaitReadable;
14600 break;
14601 default:
14603 }
14604 break;
14605 default:
14606 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14607 }
14609}
14610
14611static VALUE
14612get_LAST_READ_LINE(ID _x, VALUE *_y)
14613{
14614 return rb_lastline_get();
14615}
14616
14617static void
14618set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14619{
14620 rb_lastline_set(val);
14621}
14622
14623/*
14624 * Document-class: IOError
14625 *
14626 * Raised when an IO operation fails.
14627 *
14628 * File.open("/etc/hosts") {|f| f << "example"}
14629 * #=> IOError: not opened for writing
14630 *
14631 * File.open("/etc/hosts") {|f| f.close; f.read }
14632 * #=> IOError: closed stream
14633 *
14634 * Note that some IO failures raise <code>SystemCallError</code>s
14635 * and these are not subclasses of IOError:
14636 *
14637 * File.open("does/not/exist")
14638 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14639 */
14640
14641/*
14642 * Document-class: EOFError
14643 *
14644 * Raised by some IO operations when reaching the end of file. Many IO
14645 * methods exist in two forms,
14646 *
14647 * one that returns +nil+ when the end of file is reached, the other
14648 * raises EOFError.
14649 *
14650 * EOFError is a subclass of IOError.
14651 *
14652 * file = File.open("/etc/hosts")
14653 * file.read
14654 * file.gets #=> nil
14655 * file.readline #=> EOFError: end of file reached
14656 * file.close
14657 */
14658
14659/*
14660 * Document-class: ARGF
14661 *
14662 * ARGF is a stream designed for use in scripts that process files given as
14663 * command-line arguments or passed in via STDIN.
14664 *
14665 * The arguments passed to your script are stored in the +ARGV+ Array, one
14666 * argument per element. ARGF assumes that any arguments that aren't
14667 * filenames have been removed from +ARGV+. For example:
14668 *
14669 * $ ruby argf.rb --verbose file1 file2
14670 *
14671 * ARGV #=> ["--verbose", "file1", "file2"]
14672 * option = ARGV.shift #=> "--verbose"
14673 * ARGV #=> ["file1", "file2"]
14674 *
14675 * You can now use ARGF to work with a concatenation of each of these named
14676 * files. For instance, ARGF.read will return the contents of _file1_
14677 * followed by the contents of _file2_.
14678 *
14679 * After a file in +ARGV+ has been read ARGF removes it from the Array.
14680 * Thus, after all files have been read +ARGV+ will be empty.
14681 *
14682 * You can manipulate +ARGV+ yourself to control what ARGF operates on. If
14683 * you remove a file from +ARGV+, it is ignored by ARGF; if you add files to
14684 * +ARGV+, they are treated as if they were named on the command line. For
14685 * example:
14686 *
14687 * ARGV.replace ["file1"]
14688 * ARGF.readlines # Returns the contents of file1 as an Array
14689 * ARGV #=> []
14690 * ARGV.replace ["file2", "file3"]
14691 * ARGF.read # Returns the contents of file2 and file3
14692 *
14693 * If +ARGV+ is empty, ARGF acts as if it contained STDIN, i.e. the data
14694 * piped to your script. For example:
14695 *
14696 * $ echo "glark" | ruby -e 'p ARGF.read'
14697 * "glark\n"
14698 */
14699
14700/*
14701 * An instance of class \IO (commonly called a _stream_)
14702 * represents an input/output stream in the underlying operating system.
14703 * \Class \IO is the basis for input and output in Ruby.
14704 *
14705 * \Class File is the only class in the Ruby core that is a subclass of \IO.
14706 * Some classes in the Ruby standard library are also subclasses of \IO;
14707 * these include TCPSocket and UDPSocket.
14708 *
14709 * The global constant ARGF (also accessible as <tt>$<</tt>)
14710 * provides an IO-like stream that allows access to all file paths
14711 * found in ARGV (or found in STDIN if ARGV is empty).
14712 * ARGF is not itself a subclass of \IO.
14713 *
14714 * \Class StringIO provides an IO-like stream that handles a String.
14715 * \StringIO is not itself a subclass of \IO.
14716 *
14717 * Important objects based on \IO include:
14718 *
14719 * - $stdin.
14720 * - $stdout.
14721 * - $stderr.
14722 * - Instances of class File.
14723 *
14724 * An instance of \IO may be created using:
14725 *
14726 * - IO.new: returns a new \IO object for the given integer file descriptor.
14727 * - IO.open: passes a new \IO object to the given block.
14728 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
14729 * of a newly-launched subprocess.
14730 * - Kernel#open: Returns a new \IO object connected to a given source:
14731 * stream, file, or subprocess.
14732 *
14733 * Like a \File stream, an \IO stream has:
14734 *
14735 * - A read/write mode, which may be read-only, write-only, or read/write;
14736 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
14737 * - A data mode, which may be text-only or binary;
14738 * see {Data Mode}[rdoc-ref:File@Data+Mode].
14739 * - Internal and external encodings;
14740 * see {Encodings}[rdoc-ref:File@Encodings].
14741 *
14742 * And like other \IO streams, it has:
14743 *
14744 * - A position, which determines where in the stream the next
14745 * read or write is to occur;
14746 * see {Position}[rdoc-ref:IO@Position].
14747 * - A line number, which is a special, line-oriented, "position"
14748 * (different from the position mentioned above);
14749 * see {Line Number}[rdoc-ref:IO@Line+Number].
14750 *
14751 * == Extension <tt>io/console</tt>
14752 *
14753 * Extension <tt>io/console</tt> provides numerous methods
14754 * for interacting with the console;
14755 * requiring it adds numerous methods to class \IO.
14756 *
14757 * == Example Files
14758 *
14759 * Many examples here use these variables:
14760 *
14761 * :include: doc/examples/files.rdoc
14762 *
14763 * == Open Options
14764 *
14765 * A number of \IO methods accept optional keyword arguments
14766 * that determine how a new stream is to be opened:
14767 *
14768 * - +:mode+: Stream mode.
14769 * - +:flags+: \Integer file open flags;
14770 * If +mode+ is also given, the two are bitwise-ORed.
14771 * - +:external_encoding+: External encoding for the stream.
14772 * - +:internal_encoding+: Internal encoding for the stream.
14773 * <tt>'-'</tt> is a synonym for the default internal encoding.
14774 * If the value is +nil+ no conversion occurs.
14775 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
14776 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
14777 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
14778 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
14779 * when the stream closes; otherwise it remains open.
14780 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
14781 * #path method.
14782 *
14783 * Also available are the options offered in String#encode,
14784 * which may control conversion between external internal encoding.
14785 *
14786 * == Basic \IO
14787 *
14788 * You can perform basic stream \IO with these methods,
14789 * which typically operate on multi-byte strings:
14790 *
14791 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
14792 * - IO#write: Writes zero or more strings to the stream;
14793 * each given object that is not already a string is converted via +to_s+.
14794 *
14795 * === Position
14796 *
14797 * An \IO stream has a nonnegative integer _position_,
14798 * which is the byte offset at which the next read or write is to occur.
14799 * A new stream has position zero (and line number zero);
14800 * method +rewind+ resets the position (and line number) to zero.
14801 *
14802 * The relevant methods:
14803 *
14804 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
14805 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
14806 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
14807 * relative to a given position +whence+
14808 * (indicating the beginning, end, or current position).
14809 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
14810 *
14811 * === Open and Closed Streams
14812 *
14813 * A new \IO stream may be open for reading, open for writing, or both.
14814 *
14815 * A stream is automatically closed when claimed by the garbage collector.
14816 *
14817 * Attempted reading or writing on a closed stream raises an exception.
14818 *
14819 * The relevant methods:
14820 *
14821 * - IO#close: Closes the stream for both reading and writing.
14822 * - IO#close_read: Closes the stream for reading.
14823 * - IO#close_write: Closes the stream for writing.
14824 * - IO#closed?: Returns whether the stream is closed.
14825 *
14826 * === End-of-Stream
14827 *
14828 * You can query whether a stream is positioned at its end:
14829 *
14830 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
14831 *
14832 * You can reposition to end-of-stream by using method IO#seek:
14833 *
14834 * f = File.new('t.txt')
14835 * f.eof? # => false
14836 * f.seek(0, :END)
14837 * f.eof? # => true
14838 * f.close
14839 *
14840 * Or by reading all stream content (which is slower than using IO#seek):
14841 *
14842 * f.rewind
14843 * f.eof? # => false
14844 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14845 * f.eof? # => true
14846 *
14847 * == Line \IO
14848 *
14849 * You can read an \IO stream line-by-line using these methods:
14850 *
14851 * - IO#each_line: Reads each remaining line, passing it to the given block.
14852 * - IO#gets: Returns the next line.
14853 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
14854 * - IO#readlines: Returns all remaining lines in an array.
14855 *
14856 * Each of these reader methods accepts:
14857 *
14858 * - An optional line separator, +sep+;
14859 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
14860 * - An optional line-size limit, +limit+;
14861 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
14862 *
14863 * For each of these reader methods, reading may begin mid-line,
14864 * depending on the stream's position;
14865 * see {Position}[rdoc-ref:IO@Position]:
14866 *
14867 * f = File.new('t.txt')
14868 * f.pos = 27
14869 * f.each_line {|line| p line }
14870 * f.close
14871 *
14872 * Output:
14873 *
14874 * "rth line\n"
14875 * "Fifth line\n"
14876 *
14877 * You can write to an \IO stream line-by-line using this method:
14878 *
14879 * - IO#puts: Writes objects to the stream.
14880 *
14881 * === Line Separator
14882 *
14883 * Each of these methods uses a <i>line separator</i>,
14884 * which is the string that delimits lines:
14885 *
14886 * - IO.foreach.
14887 * - IO.readlines.
14888 * - IO#each_line.
14889 * - IO#gets.
14890 * - IO#readline.
14891 * - IO#readlines.
14892 *
14893 * The default line separator is the given by the global variable <tt>$/</tt>,
14894 * whose value is by default <tt>"\n"</tt>.
14895 * The line to be read next is all data from the current position
14896 * to the next line separator:
14897 *
14898 * f = File.new('t.txt')
14899 * f.gets # => "First line\n"
14900 * f.gets # => "Second line\n"
14901 * f.gets # => "\n"
14902 * f.gets # => "Fourth line\n"
14903 * f.gets # => "Fifth line\n"
14904 * f.close
14905 *
14906 * You can specify a different line separator:
14907 *
14908 * f = File.new('t.txt')
14909 * f.gets('l') # => "First l"
14910 * f.gets('li') # => "ine\nSecond li"
14911 * f.gets('lin') # => "ne\n\nFourth lin"
14912 * f.gets # => "e\n"
14913 * f.close
14914 *
14915 * There are two special line separators:
14916 *
14917 * - +nil+: The entire stream is read into a single string:
14918 *
14919 * f = File.new('t.txt')
14920 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14921 * f.close
14922 *
14923 * - <tt>''</tt> (the empty string): The next "paragraph" is read
14924 * (paragraphs being separated by two consecutive line separators):
14925 *
14926 * f = File.new('t.txt')
14927 * f.gets('') # => "First line\nSecond line\n\n"
14928 * f.gets('') # => "Fourth line\nFifth line\n"
14929 * f.close
14930 *
14931 * === Line Limit
14932 *
14933 * Each of these methods uses a <i>line limit</i>,
14934 * which specifies that the number of bytes returned may not be (much) longer
14935 * than the given +limit+;
14936 *
14937 * - IO.foreach.
14938 * - IO.readlines.
14939 * - IO#each_line.
14940 * - IO#gets.
14941 * - IO#readline.
14942 * - IO#readlines.
14943 *
14944 * A multi-byte character will not be split, and so a line may be slightly longer
14945 * than the given limit.
14946 *
14947 * If +limit+ is not given, the line is determined only by +sep+.
14948 *
14949 * # Text with 1-byte characters.
14950 * File.open('t.txt') {|f| f.gets(1) } # => "F"
14951 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
14952 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
14953 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
14954 * # No more than one line.
14955 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
14956 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
14957 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
14958 *
14959 * # Text with 2-byte characters, which will not be split.
14960 * File.open('t.rus') {|f| f.gets(1).size } # => 1
14961 * File.open('t.rus') {|f| f.gets(2).size } # => 1
14962 * File.open('t.rus') {|f| f.gets(3).size } # => 2
14963 * File.open('t.rus') {|f| f.gets(4).size } # => 2
14964 *
14965 * === Line Separator and Line Limit
14966 *
14967 * With arguments +sep+ and +limit+ given,
14968 * combines the two behaviors:
14969 *
14970 * - Returns the next line as determined by line separator +sep+.
14971 * - But returns no more bytes than are allowed by the limit.
14972 *
14973 * Example:
14974 *
14975 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
14976 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
14977 *
14978 * === Line Number
14979 *
14980 * A readable \IO stream has a non-negative integer <i>line number</i>.
14981 *
14982 * The relevant methods:
14983 *
14984 * - IO#lineno: Returns the line number.
14985 * - IO#lineno=: Resets and returns the line number.
14986 *
14987 * Unless modified by a call to method IO#lineno=,
14988 * the line number is the number of lines read
14989 * by certain line-oriented methods,
14990 * according to the given line separator +sep+:
14991 *
14992 * - IO.foreach: Increments the line number on each call to the block.
14993 * - IO#each_line: Increments the line number on each call to the block.
14994 * - IO#gets: Increments the line number.
14995 * - IO#readline: Increments the line number.
14996 * - IO#readlines: Increments the line number for each line read.
14997 *
14998 * A new stream is initially has line number zero (and position zero);
14999 * method +rewind+ resets the line number (and position) to zero:
15000 *
15001 * f = File.new('t.txt')
15002 * f.lineno # => 0
15003 * f.gets # => "First line\n"
15004 * f.lineno # => 1
15005 * f.rewind
15006 * f.lineno # => 0
15007 * f.close
15008 *
15009 * Reading lines from a stream usually changes its line number:
15010 *
15011 * f = File.new('t.txt', 'r')
15012 * f.lineno # => 0
15013 * f.readline # => "This is line one.\n"
15014 * f.lineno # => 1
15015 * f.readline # => "This is the second line.\n"
15016 * f.lineno # => 2
15017 * f.readline # => "Here's the third line.\n"
15018 * f.lineno # => 3
15019 * f.eof? # => true
15020 * f.close
15021 *
15022 * Iterating over lines in a stream usually changes its line number:
15023 *
15024 * File.open('t.txt') do |f|
15025 * f.each_line do |line|
15026 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15027 * end
15028 * end
15029 *
15030 * Output:
15031 *
15032 * "position=11 eof?=false lineno=1"
15033 * "position=23 eof?=false lineno=2"
15034 * "position=24 eof?=false lineno=3"
15035 * "position=36 eof?=false lineno=4"
15036 * "position=47 eof?=true lineno=5"
15037 *
15038 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15039 * the line number does not affect where the next read or write will occur:
15040 *
15041 * f = File.new('t.txt')
15042 * f.lineno = 1000
15043 * f.lineno # => 1000
15044 * f.gets # => "First line\n"
15045 * f.lineno # => 1001
15046 * f.close
15047 *
15048 * Associated with the line number is the global variable <tt>$.</tt>:
15049 *
15050 * - When a stream is opened, <tt>$.</tt> is not set;
15051 * its value is left over from previous activity in the process:
15052 *
15053 * $. = 41
15054 * f = File.new('t.txt')
15055 * $. = 41
15056 * # => 41
15057 * f.close
15058 *
15059 * - When a stream is read, <tt>#.</tt> is set to the line number for that stream:
15060 *
15061 * f0 = File.new('t.txt')
15062 * f1 = File.new('t.dat')
15063 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15064 * $. # => 5
15065 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15066 * $. # => 1
15067 * f0.close
15068 * f1.close
15069 *
15070 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15071 *
15072 * f = File.new('t.txt')
15073 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15074 * $. # => 5
15075 * f.rewind
15076 * f.seek(0, :SET)
15077 * $. # => 5
15078 * f.close
15079 *
15080 * == Character \IO
15081 *
15082 * You can process an \IO stream character-by-character using these methods:
15083 *
15084 * - IO#getc: Reads and returns the next character from the stream.
15085 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15086 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15087 * - IO#putc: Writes a character to the stream.
15088 * - IO#each_char: Reads each remaining character in the stream,
15089 * passing the character to the given block.
15090 * == Byte \IO
15091 *
15092 * You can process an \IO stream byte-by-byte using these methods:
15093 *
15094 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15095 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15096 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15097 * - IO#each_byte: Reads each remaining byte in the stream,
15098 * passing the byte to the given block.
15099 *
15100 * == Codepoint \IO
15101 *
15102 * You can process an \IO stream codepoint-by-codepoint:
15103 *
15104 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15105 *
15106 * == What's Here
15107 *
15108 * First, what's elsewhere. \Class \IO:
15109 *
15110 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15111 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15112 * which provides dozens of additional methods.
15113 *
15114 * Here, class \IO provides methods that are useful for:
15115 *
15116 * - {Creating}[rdoc-ref:IO@Creating]
15117 * - {Reading}[rdoc-ref:IO@Reading]
15118 * - {Writing}[rdoc-ref:IO@Writing]
15119 * - {Positioning}[rdoc-ref:IO@Positioning]
15120 * - {Iterating}[rdoc-ref:IO@Iterating]
15121 * - {Settings}[rdoc-ref:IO@Settings]
15122 * - {Querying}[rdoc-ref:IO@Querying]
15123 * - {Buffering}[rdoc-ref:IO@Buffering]
15124 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15125 * - {Other}[rdoc-ref:IO@Other]
15126 *
15127 * === Creating
15128 *
15129 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15130 * integer file descriptor.
15131 * - ::open: Creates a new \IO object.
15132 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15133 * - ::popen: Creates an \IO object to interact with a subprocess.
15134 * - ::select: Selects which given \IO instances are ready for reading,
15135 * writing, or have pending exceptions.
15136 *
15137 * === Reading
15138 *
15139 * - ::binread: Returns a binary string with all or a subset of bytes
15140 * from the given file.
15141 * - ::read: Returns a string with all or a subset of bytes from the given file.
15142 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15143 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15144 * - #getc: Returns the next character read from +self+ as a string.
15145 * - #gets: Returns the line read from +self+.
15146 * - #pread: Returns all or the next _n_ bytes read from +self+,
15147 * not updating the receiver's offset.
15148 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15149 * for a given _n_.
15150 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15151 * in non-block mode.
15152 * - #readbyte: Returns the next byte read from +self+;
15153 * same as #getbyte, but raises an exception on end-of-stream.
15154 * - #readchar: Returns the next character read from +self+;
15155 * same as #getc, but raises an exception on end-of-stream.
15156 * - #readline: Returns the next line read from +self+;
15157 * same as #getline, but raises an exception of end-of-stream.
15158 * - #readlines: Returns an array of all lines read read from +self+.
15159 * - #readpartial: Returns up to the given number of bytes from +self+.
15160 *
15161 * === Writing
15162 *
15163 * - ::binwrite: Writes the given string to the file at the given filepath,
15164 * in binary mode.
15165 * - ::write: Writes the given string to +self+.
15166 * - #<<: Appends the given string to +self+.
15167 * - #print: Prints last read line or given objects to +self+.
15168 * - #printf: Writes to +self+ based on the given format string and objects.
15169 * - #putc: Writes a character to +self+.
15170 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15171 * - #pwrite: Writes the given string at the given offset,
15172 * not updating the receiver's offset.
15173 * - #write: Writes one or more given strings to +self+.
15174 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15175 *
15176 * === Positioning
15177 *
15178 * - #lineno: Returns the current line number in +self+.
15179 * - #lineno=: Sets the line number is +self+.
15180 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15181 * - #pos=: Sets the byte offset in +self+.
15182 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15183 * - #rewind: Positions +self+ to the beginning of input.
15184 * - #seek: Sets the offset for +self+ relative to given position.
15185 *
15186 * === Iterating
15187 *
15188 * - ::foreach: Yields each line of given file to the block.
15189 * - #each (aliased as #each_line): Calls the given block
15190 * with each successive line in +self+.
15191 * - #each_byte: Calls the given block with each successive byte in +self+
15192 * as an integer.
15193 * - #each_char: Calls the given block with each successive character in +self+
15194 * as a string.
15195 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15196 * as an integer.
15197 *
15198 * === Settings
15199 *
15200 * - #autoclose=: Sets whether +self+ auto-closes.
15201 * - #binmode: Sets +self+ to binary mode.
15202 * - #close: Closes +self+.
15203 * - #close_on_exec=: Sets the close-on-exec flag.
15204 * - #close_read: Closes +self+ for reading.
15205 * - #close_write: Closes +self+ for writing.
15206 * - #set_encoding: Sets the encoding for +self+.
15207 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15208 * Unicode byte-order-mark.
15209 * - #sync=: Sets the sync-mode to the given value.
15210 *
15211 * === Querying
15212 *
15213 * - #autoclose?: Returns whether +self+ auto-closes.
15214 * - #binmode?: Returns whether +self+ is in binary mode.
15215 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15216 * - #closed?: Returns whether +self+ is closed.
15217 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15218 * - #external_encoding: Returns the external encoding object for +self+.
15219 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15220 * - #internal_encoding: Returns the internal encoding object for +self+.
15221 * - #pid: Returns the process ID of a child process associated with +self+,
15222 * if +self+ was created by ::popen.
15223 * - #stat: Returns the File::Stat object containing status information for +self+.
15224 * - #sync: Returns whether +self+ is in sync-mode.
15225 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15226 *
15227 * === Buffering
15228 *
15229 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15230 * - #flush: Flushes any buffered data within +self+ to the underlying
15231 * operating system.
15232 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15233 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15234 * - #ungetc: Prepends buffer for +self+ with given string.
15235 *
15236 * === Low-Level Access
15237 *
15238 * - ::sysopen: Opens the file given by its path,
15239 * returning the integer file descriptor.
15240 * - #advise: Announces the intention to access data from +self+ in a specific way.
15241 * - #fcntl: Passes a low-level command to the file specified
15242 * by the given file descriptor.
15243 * - #ioctl: Passes a low-level command to the device specified
15244 * by the given file descriptor.
15245 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15246 * - #sysseek: Sets the offset for +self+.
15247 * - #syswrite: Writes the given string to +self+ using a low-level write.
15248 *
15249 * === Other
15250 *
15251 * - ::copy_stream: Copies data from a source to a destination,
15252 * each of which is a filepath or an \IO-like object.
15253 * - ::try_convert: Returns a new \IO object resulting from converting
15254 * the given object.
15255 * - #inspect: Returns the string representation of +self+.
15256 *
15257 */
15258
15259void
15260Init_IO(void)
15261{
15262 VALUE rb_cARGF;
15263#ifdef __CYGWIN__
15264#include <sys/cygwin.h>
15265 static struct __cygwin_perfile pf[] =
15266 {
15267 {"", O_RDONLY | O_BINARY},
15268 {"", O_WRONLY | O_BINARY},
15269 {"", O_RDWR | O_BINARY},
15270 {"", O_APPEND | O_BINARY},
15271 {NULL, 0}
15272 };
15273 cygwin_internal(CW_PERFILE, pf);
15274#endif
15275
15278
15279 id_write = rb_intern_const("write");
15280 id_read = rb_intern_const("read");
15281 id_getc = rb_intern_const("getc");
15282 id_flush = rb_intern_const("flush");
15283 id_readpartial = rb_intern_const("readpartial");
15284 id_set_encoding = rb_intern_const("set_encoding");
15285 id_fileno = rb_intern_const("fileno");
15286
15287 rb_define_global_function("syscall", rb_f_syscall, -1);
15288
15289 rb_define_global_function("open", rb_f_open, -1);
15290 rb_define_global_function("printf", rb_f_printf, -1);
15291 rb_define_global_function("print", rb_f_print, -1);
15292 rb_define_global_function("putc", rb_f_putc, 1);
15293 rb_define_global_function("puts", rb_f_puts, -1);
15294 rb_define_global_function("gets", rb_f_gets, -1);
15295 rb_define_global_function("readline", rb_f_readline, -1);
15296 rb_define_global_function("select", rb_f_select, -1);
15297
15298 rb_define_global_function("readlines", rb_f_readlines, -1);
15299
15300 rb_define_global_function("`", rb_f_backquote, 1);
15301
15302 rb_define_global_function("p", rb_f_p, -1);
15303 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15304
15305 rb_cIO = rb_define_class("IO", rb_cObject);
15307
15309
15313
15314 /* exception to wait for reading. see IO.select. */
15316 /* exception to wait for writing. see IO.select. */
15318 /* exception to wait for reading by EAGAIN. see IO.select. */
15319 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15320 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15321 /* exception to wait for writing by EAGAIN. see IO.select. */
15322 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15323 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15324#if EAGAIN == EWOULDBLOCK
15325 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15326 /* same as IO::EAGAINWaitReadable */
15327 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15328 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15329 /* same as IO::EAGAINWaitWritable */
15330 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15331#else
15332 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15333 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15334 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15335 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15336 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15337 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15338#endif
15339 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15340 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15341 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15342 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15343 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15344 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15345
15346#if 0
15347 /* This is necessary only for forcing rdoc handle File::open */
15348 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15349#endif
15350
15351 rb_define_alloc_func(rb_cIO, io_alloc);
15352 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15353 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15354 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15355 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15356 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15357 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15358 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15359 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15360 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15361 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15362 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15363 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15364 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15365 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15366 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15367
15368 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15369
15370 rb_output_fs = Qnil;
15371 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15372
15373 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15374 rb_gc_register_mark_object(rb_default_rs);
15375 rb_rs = rb_default_rs;
15377 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15378 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15379 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15380
15381 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15382 rb_gvar_ractor_local("$_");
15383
15384 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15385 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15386
15387 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15388 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15389 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15390 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15391
15392 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15393 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15394 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15395 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15396 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15397
15398 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15399 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15400
15401 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15402 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15403
15404 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15405 rb_define_alias(rb_cIO, "to_i", "fileno");
15406 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15407
15408 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15409 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15410
15411 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15412 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15413 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15414 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15415
15416 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15417 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15418
15419 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15420
15421 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15422 rb_define_method(rb_cIO, "read", io_read, -1);
15423 rb_define_method(rb_cIO, "write", io_write_m, -1);
15424 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15425 rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
15426 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15427 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15428 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15429 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15430 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15431 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15433 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15434 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15435 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15436 /* Set I/O position from the beginning */
15437 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15438 /* Set I/O position from the current position */
15439 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15440 /* Set I/O position from the end */
15441 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15442#ifdef SEEK_DATA
15443 /* Set I/O position to the next location containing data */
15444 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15445#endif
15446#ifdef SEEK_HOLE
15447 /* Set I/O position to the next hole */
15448 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15449#endif
15450 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15451 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15452 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15453 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15454 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15455
15456 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15457 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15458
15459 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15460 rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
15461 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15462 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15463
15464 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15465 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15466 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15467 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15468 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15469 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15470
15471 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15472 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15473 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15474
15475 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15476 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15477
15478 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15479
15480 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15481 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15482 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15483 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15484
15485 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15486 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15487
15488 rb_define_method(rb_cIO, "wait", io_wait, -1);
15489
15490 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15491 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15492 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15493
15494 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15495 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15496 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15497 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15498
15499 rb_gvar_ractor_local("$stdin");
15500 rb_gvar_ractor_local("$stdout");
15501 rb_gvar_ractor_local("$>");
15502 rb_gvar_ractor_local("$stderr");
15503
15504 rb_stdin = rb_io_prep_stdin();
15505 rb_stdout = rb_io_prep_stdout();
15506 rb_stderr = rb_io_prep_stderr();
15507
15511
15512 orig_stdout = rb_stdout;
15513 orig_stderr = rb_stderr;
15514
15515 /* Holds the original stdin */
15517 /* Holds the original stdout */
15519 /* Holds the original stderr */
15521
15522#if 0
15523 /* Hack to get rdoc to regard ARGF as a class: */
15524 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15525#endif
15526
15527 rb_cARGF = rb_class_new(rb_cObject);
15528 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15529 rb_define_alloc_func(rb_cARGF, argf_alloc);
15530
15532
15533 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15534 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15535 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15536 rb_define_alias(rb_cARGF, "inspect", "to_s");
15537 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15538
15539 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15540 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15541 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15542 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15543 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15544 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15545 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15546 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15547 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15548
15549 rb_define_method(rb_cARGF, "read", argf_read, -1);
15550 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15551 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15552 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15553 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15554 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15555 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15556 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15557 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15558 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15559 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15560 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15561 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15562 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15563 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15564 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15565 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15566 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15567 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15568 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15569
15570 rb_define_method(rb_cARGF, "write", argf_write, 1);
15571 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15572 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15573 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15574 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15575
15576 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15577 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15578 rb_define_method(rb_cARGF, "file", argf_file, 0);
15579 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15580 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15581 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15582
15583 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15584 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15585
15586 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15587 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15588
15589 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15590 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15591 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15592
15593 argf = rb_class_new_instance(0, 0, rb_cARGF);
15594
15596 /*
15597 * ARGF is a stream designed for use in scripts that process files given
15598 * as command-line arguments or passed in via STDIN.
15599 *
15600 * See ARGF (the class) for more details.
15601 */
15603
15604 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15605 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15606 ARGF.filename = rb_str_new2("-");
15607
15608 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15609 rb_gvar_ractor_local("$-i");
15610
15611 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15612
15613#if defined (_WIN32) || defined(__CYGWIN__)
15614 atexit(pipe_atexit);
15615#endif
15616
15617 Init_File();
15618
15619 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15620
15621 sym_mode = ID2SYM(rb_intern_const("mode"));
15622 sym_perm = ID2SYM(rb_intern_const("perm"));
15623 sym_flags = ID2SYM(rb_intern_const("flags"));
15624 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15625 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15626 sym_encoding = ID2SYM(rb_id_encoding());
15627 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15628 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15629 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15630 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15631 sym_normal = ID2SYM(rb_intern_const("normal"));
15632 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15633 sym_random = ID2SYM(rb_intern_const("random"));
15634 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15635 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15636 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15637 sym_SET = ID2SYM(rb_intern_const("SET"));
15638 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15639 sym_END = ID2SYM(rb_intern_const("END"));
15640#ifdef SEEK_DATA
15641 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15642#endif
15643#ifdef SEEK_HOLE
15644 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15645#endif
15646 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15647 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15648}
15649
15650#include "io.rbinc"
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:133
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1090
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:888
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:325
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:920
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1022
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2249
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:864
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2328
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:107
#define NEWOBJ_OF
Old name of RB_NEWOBJ_OF.
Definition newobj.h:61
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
Definition fl_type.h:58
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:394
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:143
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:396
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:653
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:110
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:536
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:108
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:393
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:533
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:534
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:535
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:532
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:139
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:651
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1677
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:400
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3191
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports always regardless of runtime -W flag.
Definition error.c:421
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition error.c:3148
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:453
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1101
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:684
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3260
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition error.c:794
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
Definition error.c:3272
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
Definition io.c:14566
VALUE rb_eIOError
IOError exception.
Definition io.c:182
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1088
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3348
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3266
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:459
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1091
VALUE rb_eEOFError
EOFError exception.
Definition io.c:181
void rb_fatal(const char *fmt,...)
Raises the unsung "fatal" exception.
Definition error.c:3199
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14560
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:1907
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:57
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1089
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
Definition error.c:411
VALUE rb_eArgError
ArgumentError exception.
Definition error.c:1092
void rb_sys_fail_str(VALUE mesg)
Identical to rb_sys_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3278
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1111
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:51
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3028
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:589
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:1939
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:1980
VALUE rb_cIO
IO class.
Definition io.c:180
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
Definition object.c:1968
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:194
VALUE rb_stderr
STDERR constant.
Definition io.c:194
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:190
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:487
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:600
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:184
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:185
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1182
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
Definition object.c:3009
VALUE rb_cFile
File class.
Definition file.c:176
VALUE rb_stdout
STDOUT constant.
Definition io.c:194
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3022
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3747
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:719
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2579
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2076
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1453
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1749
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1793
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1910
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2630
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:1975
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2884
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4245
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4251
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1709
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1760
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1070
Defines RBIMPL_HAS_BUILTIN.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:239
#define rb_check_frozen
Just another name of rb_check_frozen.
Definition error.h:264
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8541
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4216
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:409
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8667
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2312
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9085
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
Definition io.c:5081
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:4987
VALUE rb_io_puts(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8899
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:356
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
Definition io.c:9193
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:230
VALUE rb_io_write(VALUE io, VALUE str)
Writes the given string to the given IO.
Definition io.c:2264
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:310
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:199
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2663
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9065
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
Definition io.c:280
VALUE rb_io_flush(VALUE io)
Flushes any buffered data within the passed IO to the underlying operating system.
Definition io.c:2368
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6278
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6232
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5145
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7283
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10255
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:443
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
Definition io.c:7166
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:349
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7173
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5668
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:200
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:1680
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1674
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
Definition proc.c:2901
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1424
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:686
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3324
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1532
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:871
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1382
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1834
void rb_str_modify(VALUE str)
Declares that the string is about to be modified.
Definition string.c:2437
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3150
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3020
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
Definition string.c:3268
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2640
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:2921
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3003
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3037
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2445
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1532
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1682
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1436
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
Definition io.c:1565
#define RUBY_UBF_IO
A special UBF for blocking IO operations.
Definition thread.h:382
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
Definition thread.c:2510
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1419
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:2788
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1559
void rb_thread_schedule(void)
Tries to switch to another thread.
Definition thread.c:1467
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1442
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2838
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
Definition variable.c:1226
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:251
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1606
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:310
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:2823
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:665
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
const char * rb_id2name(ID id)
Retrieves the name mapped to the given id.
Definition symbol.c:959
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:3452
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:604
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition variable.c:3440
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:251
int rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6364
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:797
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:843
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:767
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1051
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
Definition io.c:6497
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
Definition io.h:340
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:257
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:362
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:997
#define FMODE_TTY
The IO is a TTY.
Definition io.h:281
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:304
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1006
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:6646
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition io.c:1553
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
Definition io.c:6967
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2866
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:254
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
Definition io.c:9239
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:296
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:385
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:289
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:268
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1612
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:356
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1571
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:183
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:275
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:774
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
Definition io.h:312
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:332
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
Definition io.c:803
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:869
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:1977
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:978
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:318
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:809
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3376
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:6773
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1510
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:820
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1030
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
Definition io.c:1625
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:782
rb_io_event_t
Type of events that an IO can wait.
Definition io.h:81
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:82
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:84
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:83
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1476
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7270
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1415
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
Definition ractor.c:2148
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:2124
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
Definition ractor.c:2184
VALUE rb_ractor_stdout(void)
Queries the standard output of the current Ractor that is calling this function.
Definition ractor.c:2136
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
Definition ractor.c:2172
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
Definition ractor.c:2160
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:1756
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:208
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition sprintf.c:1219
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
Definition sprintf.c:1242
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1392
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1358
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:354
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:378
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:68
#define RARRAY_AREF(a, i)
Definition rarray.h:583
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:69
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define SafeStringValue(v)
Definition rstring.h:104
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:72
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:574
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:95
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:79
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:489
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14526
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:8968
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:91
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:203
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:246
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:419
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:413
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:70
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:449
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:208
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:425
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *buffer, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:582
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *buffer, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:569
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
Definition thread.c:4181
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:218
Definition win32.h:216
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
IO buffers.
Definition io.h:104
int len
Length of the buffer.
Definition io.h:104
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:104
int off
Offset inside of ptr.
Definition io.h:104
int capa
Designed capacity of the buffer.
Definition io.h:104
Decomposed encoding flags (e.g.
Definition io.h:116
int ecflags
Flags.
Definition io.h:126
rb_encoding * enc2
External encoding.
Definition io.h:120
VALUE ecopts
Flags as Ruby hash.
Definition io.h:134
rb_encoding * enc
Internal encoding.
Definition io.h:118
Ruby's IO, metadata and buffers.
Definition io.h:138
int fd
file descriptor.
Definition io.h:147
int lineno
number of lines read
Definition io.h:156
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:192
rb_pid_t pid
child's pid (for pipes)
Definition io.h:153
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:165
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:183
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:200
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:144
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:203
VALUE pathv
pathname for file
Definition io.h:159
int mode
mode flags: FMODE_XXXs
Definition io.h:150
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:209
struct rb_io_enc_t encs
Decomposed encoding flags.
Definition io.h:180
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:224
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:189
VALUE self
The IO's Ruby level counterpart.
Definition io.h:141
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:215
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:178
void(* finalize)(struct rb_io_t *, int)
finalize proc
Definition io.h:162
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:229
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:171
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52