Ruby: io.c Source File

Ruby 3.3.7p123 (2025-01-15 revision be31f993d7fa0219d85f7b3c694d454da4ecc10b)

io.c
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
16#include "ruby/fiber/scheduler.h"
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107#endif
108
109#include "ruby/internal/stdbool.h"
110#include "ccan/list/list.h"
111#include "dln.h"
112#include "encindex.h"
113#include "id.h"
114#include "internal.h"
115#include "internal/encoding.h"
116#include "internal/error.h"
117#include "internal/inits.h"
118#include "internal/io.h"
119#include "internal/numeric.h"
120#include "internal/object.h"
121#include "internal/process.h"
122#include "internal/thread.h"
123#include "internal/transcode.h"
124#include "internal/variable.h"
125#include "ruby/io.h"
126#include "ruby/io/buffer.h"
127#include "ruby/missing.h"
128#include "ruby/thread.h"
129#include "ruby/util.h"
130#include "ruby_atomic.h"
131#include "ruby/ractor.h"
132
133#if !USE_POLL
134# include "vm_core.h"
135#endif
136
137#include "builtin.h"
138
139#ifndef O_ACCMODE
140#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
141#endif
142
143#ifndef PIPE_BUF
144# ifdef _POSIX_PIPE_BUF
145# define PIPE_BUF _POSIX_PIPE_BUF
146# else
147# define PIPE_BUF 512 /* is this ok? */
148# endif
149#endif
150
151#ifndef EWOULDBLOCK
152# define EWOULDBLOCK EAGAIN
153#endif
154
155#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
156/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
157off_t __syscall(quad_t number, ...);
158#endif
159
160#define IO_RBUF_CAPA_MIN 8192
161#define IO_CBUF_CAPA_MIN (128*1024)
162#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
163#define IO_WBUF_CAPA_MIN 8192
164
165#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
166
167/* define system APIs */
168#ifdef _WIN32
169#undef open
170#define open rb_w32_uopen
171#undef rename
172#define rename(f, t) rb_w32_urename((f), (t))
173#include "win32/file.h"
174#endif
175
176 VALUE rb_cIO;
177 VALUE rb_eEOFError;
178 VALUE rb_eIOError;
179 VALUE rb_eIOTimeoutError;
180 VALUE rb_mWaitReadable;
181 VALUE rb_mWaitWritable;
182
183static VALUE rb_eEAGAINWaitReadable;
184static VALUE rb_eEAGAINWaitWritable;
185static VALUE rb_eEWOULDBLOCKWaitReadable;
186static VALUE rb_eEWOULDBLOCKWaitWritable;
187static VALUE rb_eEINPROGRESSWaitWritable;
188static VALUE rb_eEINPROGRESSWaitReadable;
189
190 VALUE rb_stdin, rb_stdout, rb_stderr;
191static VALUE orig_stdout, orig_stderr;
192
193 VALUE rb_output_fs;
194 VALUE rb_rs;
195 VALUE rb_output_rs;
196 VALUE rb_default_rs;
197
198static VALUE argf;
199
200static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
201static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
202static VALUE sym_textmode, sym_binmode, sym_autoclose;
203static VALUE sym_SET, sym_CUR, sym_END;
204static VALUE sym_wait_readable, sym_wait_writable;
205#ifdef SEEK_DATA
206static VALUE sym_DATA;
207#endif
208#ifdef SEEK_HOLE
209static VALUE sym_HOLE;
210#endif
211
212static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
213
214 struct argf {
215 VALUE filename, current_file;
216 long last_lineno; /* $. */
217 long lineno;
218 VALUE argv;
219 VALUE inplace;
220 struct rb_io_encoding encs;
221 int8_t init_p, next_p, binmode;
222};
223
224static rb_atomic_t max_file_descriptor = NOFILE;
225void
226rb_update_max_fd(int fd)
227{
228 rb_atomic_t afd = (rb_atomic_t)fd;
229 rb_atomic_t max_fd = max_file_descriptor;
230 int err;
231
232 if (fd < 0 || afd <= max_fd)
233 return;
234
235#if defined(HAVE_FCNTL) && defined(F_GETFL)
236 err = fcntl(fd, F_GETFL) == -1;
237#else
238 {
239 struct stat buf;
240 err = fstat(fd, &buf) != 0;
241 }
242#endif
243 if (err && errno == EBADF) {
244 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
245 }
246
247 while (max_fd < afd) {
248 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
249 }
250}
251
252void
253rb_maygvl_fd_fix_cloexec(int fd)
254{
255 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
256#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
257 int flags, flags2, ret;
258 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
259 if (flags == -1) {
260 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
261 }
262 if (fd <= 2)
263 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
264 else
265 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
266 if (flags != flags2) {
267 ret = fcntl(fd, F_SETFD, flags2);
268 if (ret != 0) {
269 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
270 }
271 }
272#endif
273}
274
275void
276rb_fd_fix_cloexec(int fd)
277{
278 rb_maygvl_fd_fix_cloexec(fd);
279 rb_update_max_fd(fd);
280}
281
282/* this is only called once */
283static int
284rb_fix_detect_o_cloexec(int fd)
285{
286#if defined(O_CLOEXEC) && defined(F_GETFD)
287 int flags = fcntl(fd, F_GETFD);
288
289 if (flags == -1)
290 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
291
292 if (flags & FD_CLOEXEC)
293 return 1;
294#endif /* fall through if O_CLOEXEC does not work: */
295 rb_maygvl_fd_fix_cloexec(fd);
296 return 0;
297}
298
299static inline bool
300io_again_p(int e)
301{
302 return (e == EWOULDBLOCK) || (e == EAGAIN);
303}
304
305int
306rb_cloexec_open(const char *pathname, int flags, mode_t mode)
307{
308 int ret;
309 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
310
311 static const int retry_interval = 0;
312 static const int retry_max_count = 10000;
313
314 int retry_count = 0;
315
316#ifdef O_CLOEXEC
317 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
318 flags |= O_CLOEXEC;
319#elif defined O_NOINHERIT
320 flags |= O_NOINHERIT;
321#endif
322
323 while ((ret = open(pathname, flags, mode)) == -1) {
324 int e = errno;
325 if (!io_again_p(e)) break;
326 if (retry_count++ >= retry_max_count) break;
327
328 sleep(retry_interval);
329 }
330
331 if (ret < 0) return ret;
332 if (ret <= 2 || o_cloexec_state == 0) {
333 rb_maygvl_fd_fix_cloexec(ret);
334 }
335 else if (o_cloexec_state > 0) {
336 return ret;
337 }
338 else {
339 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
340 }
341 return ret;
342}
343
344int
345rb_cloexec_dup(int oldfd)
346{
347 /* Don't allocate standard file descriptors: 0, 1, 2 */
348 return rb_cloexec_fcntl_dupfd(oldfd, 3);
349}
350
351int
352rb_cloexec_dup2(int oldfd, int newfd)
353{
354 int ret;
355
356 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
357 * rb_cloexec_dup2 succeeds as dup2. */
358 if (oldfd == newfd) {
359 ret = newfd;
360 }
361 else {
362#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
363 static int try_dup3 = 1;
364 if (2 < newfd && try_dup3) {
365 ret = dup3(oldfd, newfd, O_CLOEXEC);
366 if (ret != -1)
367 return ret;
368 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
369 if (errno == ENOSYS) {
370 try_dup3 = 0;
371 ret = dup2(oldfd, newfd);
372 }
373 }
374 else {
375 ret = dup2(oldfd, newfd);
376 }
377#else
378 ret = dup2(oldfd, newfd);
379#endif
380 if (ret < 0) return ret;
381 }
382 rb_maygvl_fd_fix_cloexec(ret);
383 return ret;
384}
385
386static int
387rb_fd_set_nonblock(int fd)
388{
389#ifdef _WIN32
390 return rb_w32_set_nonblock(fd);
391#elif defined(F_GETFL)
392 int oflags = fcntl(fd, F_GETFL);
393
394 if (oflags == -1)
395 return -1;
396 if (oflags & O_NONBLOCK)
397 return 0;
398 oflags |= O_NONBLOCK;
399 return fcntl(fd, F_SETFL, oflags);
400#endif
401 return 0;
402}
403
404int
405rb_cloexec_pipe(int descriptors[2])
406{
407#ifdef HAVE_PIPE2
408 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
409#else
410 int result = pipe(descriptors);
411#endif
412
413 if (result < 0)
414 return result;
415
416#ifdef __CYGWIN__
417 if (result == 0 && descriptors[1] == -1) {
418 close(descriptors[0]);
419 descriptors[0] = -1;
420 errno = ENFILE;
421 return -1;
422 }
423#endif
424
425#ifndef HAVE_PIPE2
426 rb_maygvl_fd_fix_cloexec(descriptors[0]);
427 rb_maygvl_fd_fix_cloexec(descriptors[1]);
428
429#ifndef _WIN32
430 rb_fd_set_nonblock(descriptors[0]);
431 rb_fd_set_nonblock(descriptors[1]);
432#endif
433#endif
434
435 return result;
436}
437
438int
439rb_cloexec_fcntl_dupfd(int fd, int minfd)
440{
441 int ret;
442
443#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
444 static int try_dupfd_cloexec = 1;
445 if (try_dupfd_cloexec) {
446 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
447 if (ret != -1) {
448 if (ret <= 2)
449 rb_maygvl_fd_fix_cloexec(ret);
450 return ret;
451 }
452 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
453 if (errno == EINVAL) {
454 ret = fcntl(fd, F_DUPFD, minfd);
455 if (ret != -1) {
456 try_dupfd_cloexec = 0;
457 }
458 }
459 }
460 else {
461 ret = fcntl(fd, F_DUPFD, minfd);
462 }
463#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
464 ret = fcntl(fd, F_DUPFD, minfd);
465#else
466 ret = dup(fd);
467 if (ret >= 0 && ret < minfd) {
468 const int prev_fd = ret;
469 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
470 close(prev_fd);
471 }
472 return ret;
473#endif
474 if (ret < 0) return ret;
475 rb_maygvl_fd_fix_cloexec(ret);
476 return ret;
477}
478
479#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
480#define ARGF argf_of(argf)
481
482#define GetWriteIO(io) rb_io_get_write_io(io)
483
484#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
485#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
486#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
487#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
488
489#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
490#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
491#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
492
493#if defined(_WIN32)
494#define WAIT_FD_IN_WIN32(fptr) \
495 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
496#else
497#define WAIT_FD_IN_WIN32(fptr)
498#endif
499
500#define READ_CHECK(fptr) do {\
501 if (!READ_DATA_PENDING(fptr)) {\
502 WAIT_FD_IN_WIN32(fptr);\
503 rb_io_check_closed(fptr);\
504 }\
505} while(0)
506
507#ifndef S_ISSOCK
508# ifdef _S_ISSOCK
509# define S_ISSOCK(m) _S_ISSOCK(m)
510# else
511# ifdef _S_IFSOCK
512# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
513# else
514# ifdef S_IFSOCK
515# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
516# endif
517# endif
518# endif
519#endif
520
521static int io_fflush(rb_io_t *);
522static rb_io_t *flush_before_seek(rb_io_t *fptr);
523
524#define FMODE_SIGNAL_ON_EPIPE (1<<17)
525
526#define fptr_signal_on_epipe(fptr) \
527 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
528
529#define fptr_set_signal_on_epipe(fptr, flag) \
530 ((flag) ? \
531 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
532 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
533
534extern ID ruby_static_id_signo;
535
536NORETURN(static void raise_on_write(rb_io_t *fptr, int e, VALUE errinfo));
537static void
538raise_on_write(rb_io_t *fptr, int e, VALUE errinfo)
539{
540#if defined EPIPE
541 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
542 const VALUE sig =
543# if defined SIGPIPE
544 INT2FIX(SIGPIPE) - INT2FIX(0) +
545# endif
546 INT2FIX(0);
547 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
548 }
549#endif
550 rb_exc_raise(errinfo);
551}
552
553#define rb_sys_fail_on_write(fptr) \
554 do { \
555 int e = errno; \
556 raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
557 } while (0)
558
559#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
560#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
561#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
562# define RUBY_CRLF_ENVIRONMENT 1
563#else
564# define RUBY_CRLF_ENVIRONMENT 0
565#endif
566
567#if RUBY_CRLF_ENVIRONMENT
568/* Windows */
569# define DEFAULT_TEXTMODE FMODE_TEXTMODE
570# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
571/*
572 * CRLF newline is set as default newline decorator.
573 * If only CRLF newline conversion is needed, we use binary IO process
574 * with OS's text mode for IO performance improvement.
575 * If encoding conversion is needed or a user sets text mode, we use encoding
576 * conversion IO process and universal newline decorator by default.
577 */
578#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
579#define WRITECONV_MASK ( \
580 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
581 ECONV_STATEFUL_DECORATOR_MASK|\
582 0)
583#define NEED_WRITECONV(fptr) ( \
584 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
585 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
586 0)
587#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
588
589#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
590 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
591 if (((fptr)->mode & FMODE_READABLE) &&\
592 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
593 setmode((fptr)->fd, O_BINARY);\
594 }\
595 else {\
596 setmode((fptr)->fd, O_TEXT);\
597 }\
598 }\
599} while(0)
600
601#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
602 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
603 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
604 }\
605} while(0)
606
607/*
608 * IO unread with taking care of removed '\r' in text mode.
609 */
610static void
611io_unread(rb_io_t *fptr)
612{
613 rb_off_t r, pos;
614 ssize_t read_size;
615 long i;
616 long newlines = 0;
617 long extra_max;
618 char *p;
619 char *buf;
620
621 rb_io_check_closed(fptr);
622 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
623 return;
624 }
625
626 errno = 0;
627 if (!rb_w32_fd_is_text(fptr->fd)) {
628 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
629 if (r < 0 && errno) {
630 if (errno == ESPIPE)
631 fptr->mode |= FMODE_DUPLEX;
632 return;
633 }
634
635 fptr->rbuf.off = 0;
636 fptr->rbuf.len = 0;
637 return;
638 }
639
640 pos = lseek(fptr->fd, 0, SEEK_CUR);
641 if (pos < 0 && errno) {
642 if (errno == ESPIPE)
643 fptr->mode |= FMODE_DUPLEX;
644 return;
645 }
646
647 /* add extra offset for removed '\r' in rbuf */
648 extra_max = (long)(pos - fptr->rbuf.len);
649 p = fptr->rbuf.ptr + fptr->rbuf.off;
650
651 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
652 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
653 newlines++;
654 }
655
656 for (i = 0; i < fptr->rbuf.len; i++) {
657 if (*p == '\n') newlines++;
658 if (extra_max == newlines) break;
659 p++;
660 }
661
662 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
663 while (newlines >= 0) {
664 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
665 if (newlines == 0) break;
666 if (r < 0) {
667 newlines--;
668 continue;
669 }
670 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
671 if (read_size < 0) {
672 int e = errno;
673 free(buf);
674 rb_syserr_fail_path(e, fptr->pathv);
675 }
676 if (read_size == fptr->rbuf.len) {
677 lseek(fptr->fd, r, SEEK_SET);
678 break;
679 }
680 else {
681 newlines--;
682 }
683 }
684 free(buf);
685 fptr->rbuf.off = 0;
686 fptr->rbuf.len = 0;
687 return;
688}
689
690/*
691 * We use io_seek to back cursor position when changing mode from text to binary,
692 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
693 * conversion for working properly with mode change.
694 *
695 * Return previous translation mode.
696 */
697static inline int
698set_binary_mode_with_seek_cur(rb_io_t *fptr)
699{
700 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
701
702 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
703 return setmode(fptr->fd, O_BINARY);
704 }
705 flush_before_seek(fptr);
706 return setmode(fptr->fd, O_BINARY);
707}
708#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
709
710#else
711/* Unix */
712# define DEFAULT_TEXTMODE 0
713#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
714#define NEED_WRITECONV(fptr) ( \
715 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
716 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
717 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
718 0)
719#define SET_BINARY_MODE(fptr) (void)(fptr)
720#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
721#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
722#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
723#endif
724
725#if !defined HAVE_SHUTDOWN && !defined shutdown
726#define shutdown(a,b) 0
727#endif
728
729#if defined(_WIN32)
730#define is_socket(fd, path) rb_w32_is_socket(fd)
731#elif !defined(S_ISSOCK)
732#define is_socket(fd, path) 0
733#else
734static int
735is_socket(int fd, VALUE path)
736{
737 struct stat sbuf;
738 if (fstat(fd, &sbuf) < 0)
739 rb_sys_fail_path(path);
740 return S_ISSOCK(sbuf.st_mode);
741}
742#endif
743
744static const char closed_stream[] = "closed stream";
745
746static void
747io_fd_check_closed(int fd)
748{
749 if (fd < 0) {
750 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
751 rb_raise(rb_eIOError, closed_stream);
752 }
753}
754
755void
756rb_eof_error(void)
757{
758 rb_raise(rb_eEOFError, "end of file reached");
759}
760
761 VALUE
762rb_io_taint_check(VALUE io)
763{
764 rb_check_frozen(io);
765 return io;
766}
767
768void
769rb_io_check_initialized(rb_io_t *fptr)
770{
771 if (!fptr) {
772 rb_raise(rb_eIOError, "uninitialized stream");
773 }
774}
775
776void
777rb_io_check_closed(rb_io_t *fptr)
778{
779 rb_io_check_initialized(fptr);
780 io_fd_check_closed(fptr->fd);
781}
782
783static rb_io_t *
784rb_io_get_fptr(VALUE io)
785{
786 rb_io_t *fptr = RFILE(io)->fptr;
787 rb_io_check_initialized(fptr);
788 return fptr;
789}
790
791 VALUE
792rb_io_get_io(VALUE io)
793{
794 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
795}
796
797 VALUE
798rb_io_check_io(VALUE io)
799{
800 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
801}
802
803 VALUE
804rb_io_get_write_io(VALUE io)
805{
806 VALUE write_io;
807 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
808 if (write_io) {
809 return write_io;
810 }
811 return io;
812}
813
814 VALUE
815rb_io_set_write_io(VALUE io, VALUE w)
816{
817 VALUE write_io;
818 rb_io_t *fptr = rb_io_get_fptr(io);
819 if (!RTEST(w)) {
820 w = 0;
821 }
822 else {
823 GetWriteIO(w);
824 }
825 write_io = fptr->tied_io_for_writing;
826 fptr->tied_io_for_writing = w;
827 return write_io ? write_io : Qnil;
828}
829
830/*
831 * call-seq:
832 * timeout -> duration or nil
833 *
834 * Get the internal timeout duration or nil if it was not set.
835 *
836 */
837 VALUE
838rb_io_timeout(VALUE self)
839{
840 rb_io_t *fptr = rb_io_get_fptr(self);
841
842 return fptr->timeout;
843}
844
845/*
846 * call-seq:
847 * timeout = duration -> duration
848 * timeout = nil -> nil
849 *
850 * Sets the internal timeout to the specified duration or nil. The timeout
851 * applies to all blocking operations where possible.
852 *
853 * When the operation performs longer than the timeout set, IO::TimeoutError
854 * is raised.
855 *
856 * This affects the following methods (but is not limited to): #gets, #puts,
857 * #read, #write, #wait_readable and #wait_writable. This also affects
858 * blocking socket operations like Socket#accept and Socket#connect.
859 *
860 * Some operations like File#open and IO#close are not affected by the
861 * timeout. A timeout during a write operation may leave the IO in an
862 * inconsistent state, e.g. data was partially written. Generally speaking, a
863 * timeout is a last ditch effort to prevent an application from hanging on
864 * slow I/O operations, such as those that occur during a slowloris attack.
865 */
866 VALUE
867rb_io_set_timeout(VALUE self, VALUE timeout)
868{
869 // Validate it:
870 if (RTEST(timeout)) {
871 rb_time_interval(timeout);
872 }
873
874 rb_io_t *fptr = rb_io_get_fptr(self);
875
876 fptr->timeout = timeout;
877
878 return self;
879}
880
881/*
882 * call-seq:
883 * IO.try_convert(object) -> new_io or nil
884 *
885 * Attempts to convert +object+ into an \IO object via method +to_io+;
886 * returns the new \IO object if successful, or +nil+ otherwise:
887 *
888 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
889 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
890 * IO.try_convert('STDOUT') # => nil
891 *
892 */
893static VALUE
894rb_io_s_try_convert(VALUE dummy, VALUE io)
895{
896 return rb_io_check_io(io);
897}
898
899#if !RUBY_CRLF_ENVIRONMENT
900static void
901io_unread(rb_io_t *fptr)
902{
903 rb_off_t r;
904 rb_io_check_closed(fptr);
905 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
906 return;
907 /* xxx: target position may be negative if buffer is filled by ungetc */
908 errno = 0;
909 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
910 if (r < 0 && errno) {
911 if (errno == ESPIPE)
912 fptr->mode |= FMODE_DUPLEX;
913 return;
914 }
915 fptr->rbuf.off = 0;
916 fptr->rbuf.len = 0;
917 return;
918}
919#endif
920
921static rb_encoding *io_input_encoding(rb_io_t *fptr);
922
923static void
924io_ungetbyte(VALUE str, rb_io_t *fptr)
925{
926 long len = RSTRING_LEN(str);
927
928 if (fptr->rbuf.ptr == NULL) {
929 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
930 fptr->rbuf.off = 0;
931 fptr->rbuf.len = 0;
932#if SIZEOF_LONG > SIZEOF_INT
933 if (len > INT_MAX)
934 rb_raise(rb_eIOError, "ungetbyte failed");
935#endif
936 if (len > min_capa)
937 fptr->rbuf.capa = (int)len;
938 else
939 fptr->rbuf.capa = min_capa;
940 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
941 }
942 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
943 rb_raise(rb_eIOError, "ungetbyte failed");
944 }
945 if (fptr->rbuf.off < len) {
946 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
947 fptr->rbuf.ptr+fptr->rbuf.off,
948 char, fptr->rbuf.len);
949 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
950 }
951 fptr->rbuf.off-=(int)len;
952 fptr->rbuf.len+=(int)len;
953 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
954}
955
956static rb_io_t *
957flush_before_seek(rb_io_t *fptr)
958{
959 if (io_fflush(fptr) < 0)
960 rb_sys_fail_on_write(fptr);
961 io_unread(fptr);
962 errno = 0;
963 return fptr;
964}
965
966#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
967#define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
968
969#ifndef SEEK_CUR
970# define SEEK_SET 0
971# define SEEK_CUR 1
972# define SEEK_END 2
973#endif
974
975void
976rb_io_check_char_readable(rb_io_t *fptr)
977{
978 rb_io_check_closed(fptr);
979 if (!(fptr->mode & FMODE_READABLE)) {
980 rb_raise(rb_eIOError, "not opened for reading");
981 }
982 if (fptr->wbuf.len) {
983 if (io_fflush(fptr) < 0)
984 rb_sys_fail_on_write(fptr);
985 }
986 if (fptr->tied_io_for_writing) {
987 rb_io_t *wfptr;
988 GetOpenFile(fptr->tied_io_for_writing, wfptr);
989 if (io_fflush(wfptr) < 0)
990 rb_sys_fail_on_write(wfptr);
991 }
992}
993
994void
995rb_io_check_byte_readable(rb_io_t *fptr)
996{
997 rb_io_check_char_readable(fptr);
998 if (READ_CHAR_PENDING(fptr)) {
999 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1000 }
1001}
1002
1003void
1004rb_io_check_readable(rb_io_t *fptr)
1005{
1006 rb_io_check_byte_readable(fptr);
1007}
1008
1009static rb_encoding*
1010io_read_encoding(rb_io_t *fptr)
1011{
1012 if (fptr->encs.enc) {
1013 return fptr->encs.enc;
1014 }
1015 return rb_default_external_encoding();
1016}
1017
1018static rb_encoding*
1019io_input_encoding(rb_io_t *fptr)
1020{
1021 if (fptr->encs.enc2) {
1022 return fptr->encs.enc2;
1023 }
1024 return io_read_encoding(fptr);
1025}
1026
1027void
1028rb_io_check_writable(rb_io_t *fptr)
1029{
1030 rb_io_check_closed(fptr);
1031 if (!(fptr->mode & FMODE_WRITABLE)) {
1032 rb_raise(rb_eIOError, "not opened for writing");
1033 }
1034 if (fptr->rbuf.len) {
1035 io_unread(fptr);
1036 }
1037}
1038
1039int
1040rb_io_read_pending(rb_io_t *fptr)
1041{
1042 /* This function is used for bytes and chars. Confusing. */
1043 if (READ_CHAR_PENDING(fptr))
1044 return 1; /* should raise? */
1045 return READ_DATA_PENDING(fptr);
1046}
1047
1048void
1049rb_io_read_check(rb_io_t *fptr)
1050{
1051 if (!READ_DATA_PENDING(fptr)) {
1052 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1053 }
1054 return;
1055}
1056
1057int
1058rb_gc_for_fd(int err)
1059{
1060 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1061 rb_gc();
1062 return 1;
1063 }
1064 return 0;
1065}
1066
1067/* try `expr` upto twice while it returns false and `errno`
1068 * is to GC. Each `errno`s are available as `first_errno` and
1069 * `retried_errno` respectively */
1070#define TRY_WITH_GC(expr) \
1071 for (int first_errno, retried_errno = 0, retried = 0; \
1072 (!retried && \
1073 !(expr) && \
1074 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1075 (retried_errno = errno, 1)); \
1076 (void)retried_errno, retried = 1)
1077
1078static int
1079ruby_dup(int orig)
1080{
1081 int fd = -1;
1082
1083 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1084 rb_syserr_fail(first_errno, 0);
1085 }
1086 rb_update_max_fd(fd);
1087 return fd;
1088}
1089
1090static VALUE
1091io_alloc(VALUE klass)
1092{
1093 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1094
1095 io->fptr = 0;
1096
1097 return (VALUE)io;
1098}
1099
1100#ifndef S_ISREG
1101# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1102#endif
1103
1104 struct io_internal_read_struct {
1105 VALUE th;
1106 rb_io_t *fptr;
1107 int nonblock;
1108 int fd;
1109
1110 void *buf;
1111 size_t capa;
1112 struct timeval *timeout;
1113};
1114
1115 struct io_internal_write_struct {
1116 VALUE th;
1117 rb_io_t *fptr;
1118 int nonblock;
1119 int fd;
1120
1121 const void *buf;
1122 size_t capa;
1123 struct timeval *timeout;
1124};
1125
1126#ifdef HAVE_WRITEV
1127struct io_internal_writev_struct {
1128 VALUE th;
1129 rb_io_t *fptr;
1130 int nonblock;
1131 int fd;
1132
1133 int iovcnt;
1134 const struct iovec *iov;
1135 struct timeval *timeout;
1136};
1137#endif
1138
1139static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1140
1146static inline int
1147io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1148{
1149 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1150
1151 if (ready > 0) {
1152 return ready;
1153 }
1154 else if (ready == 0) {
1155 errno = ETIMEDOUT;
1156 return -1;
1157 }
1158
1159 errno = error;
1160 return -1;
1161}
1162
1163static VALUE
1164internal_read_func(void *ptr)
1165{
1166 struct io_internal_read_struct *iis = ptr;
1167 ssize_t result;
1168
1169 if (iis->timeout && !iis->nonblock) {
1170 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1171 return -1;
1172 }
1173 }
1174
1175 retry:
1176 result = read(iis->fd, iis->buf, iis->capa);
1177
1178 if (result < 0 && !iis->nonblock) {
1179 if (io_again_p(errno)) {
1180 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1181 return -1;
1182 }
1183 else {
1184 goto retry;
1185 }
1186 }
1187 }
1188
1189 return result;
1190}
1191
1192#if defined __APPLE__
1193# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1194#else
1195# define do_write_retry(code) result = code
1196#endif
1197
1198static VALUE
1199internal_write_func(void *ptr)
1200{
1201 struct io_internal_write_struct *iis = ptr;
1202 ssize_t result;
1203
1204 if (iis->timeout && !iis->nonblock) {
1205 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1206 return -1;
1207 }
1208 }
1209
1210 retry:
1211 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1212
1213 if (result < 0 && !iis->nonblock) {
1214 int e = errno;
1215 if (io_again_p(e)) {
1216 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1217 return -1;
1218 }
1219 else {
1220 goto retry;
1221 }
1222 }
1223 }
1224
1225 return result;
1226}
1227
1228#ifdef HAVE_WRITEV
1229static VALUE
1230internal_writev_func(void *ptr)
1231{
1232 struct io_internal_writev_struct *iis = ptr;
1233 ssize_t result;
1234
1235 if (iis->timeout && !iis->nonblock) {
1236 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1237 return -1;
1238 }
1239 }
1240
1241 retry:
1242 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1243
1244 if (result < 0 && !iis->nonblock) {
1245 if (io_again_p(errno)) {
1246 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1247 return -1;
1248 }
1249 else {
1250 goto retry;
1251 }
1252 }
1253 }
1254
1255 return result;
1256}
1257#endif
1258
1259static ssize_t
1260rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1261{
1262 VALUE scheduler = rb_fiber_scheduler_current();
1263 if (scheduler != Qnil) {
1264 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1265
1266 if (!UNDEF_P(result)) {
1267 return rb_fiber_scheduler_io_result_apply(result);
1268 }
1269 }
1270
1271 struct io_internal_read_struct iis = {
1272 .th = rb_thread_current(),
1273 .fptr = fptr,
1274 .nonblock = 0,
1275 .fd = fptr->fd,
1276
1277 .buf = buf,
1278 .capa = count,
1279 .timeout = NULL,
1280 };
1281
1282 struct timeval timeout_storage;
1283
1284 if (fptr->timeout != Qnil) {
1285 timeout_storage = rb_time_interval(fptr->timeout);
1286 iis.timeout = &timeout_storage;
1287 }
1288
1289 return (ssize_t)rb_thread_io_blocking_call(internal_read_func, &iis, fptr->fd, RB_WAITFD_IN);
1290}
1291
1292static ssize_t
1293rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1294{
1295 VALUE scheduler = rb_fiber_scheduler_current();
1296 if (scheduler != Qnil) {
1297 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1298
1299 if (!UNDEF_P(result)) {
1300 return rb_fiber_scheduler_io_result_apply(result);
1301 }
1302 }
1303
1304 struct io_internal_write_struct iis = {
1305 .th = rb_thread_current(),
1306 .fptr = fptr,
1307 .nonblock = 0,
1308 .fd = fptr->fd,
1309
1310 .buf = buf,
1311 .capa = count,
1312 .timeout = NULL
1313 };
1314
1315 struct timeval timeout_storage;
1316
1317 if (fptr->timeout != Qnil) {
1318 timeout_storage = rb_time_interval(fptr->timeout);
1319 iis.timeout = &timeout_storage;
1320 }
1321
1322 return (ssize_t)rb_thread_io_blocking_call(internal_write_func, &iis, fptr->fd, RB_WAITFD_OUT);
1323}
1324
1325#ifdef HAVE_WRITEV
1326static ssize_t
1327rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1328{
1329 if (!iovcnt) return 0;
1330
1331 VALUE scheduler = rb_fiber_scheduler_current();
1332 if (scheduler != Qnil) {
1333 // This path assumes at least one `iov`:
1334 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1335
1336 if (!UNDEF_P(result)) {
1337 return rb_fiber_scheduler_io_result_apply(result);
1338 }
1339 }
1340
1341 struct io_internal_writev_struct iis = {
1342 .th = rb_thread_current(),
1343 .fptr = fptr,
1344 .nonblock = 0,
1345 .fd = fptr->fd,
1346
1347 .iov = iov,
1348 .iovcnt = iovcnt,
1349 .timeout = NULL
1350 };
1351
1352 struct timeval timeout_storage;
1353
1354 if (fptr->timeout != Qnil) {
1355 timeout_storage = rb_time_interval(fptr->timeout);
1356 iis.timeout = &timeout_storage;
1357 }
1358
1359 return (ssize_t)rb_thread_io_blocking_call(internal_writev_func, &iis, fptr->fd, RB_WAITFD_OUT);
1360}
1361#endif
1362
1363static VALUE
1364io_flush_buffer_sync(void *arg)
1365{
1366 rb_io_t *fptr = arg;
1367 long l = fptr->wbuf.len;
1368 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1369
1370 if (fptr->wbuf.len <= r) {
1371 fptr->wbuf.off = 0;
1372 fptr->wbuf.len = 0;
1373 return 0;
1374 }
1375
1376 if (0 <= r) {
1377 fptr->wbuf.off += (int)r;
1378 fptr->wbuf.len -= (int)r;
1379 errno = EAGAIN;
1380 }
1381
1382 return (VALUE)-1;
1383}
1384
1385static VALUE
1386io_flush_buffer_async(VALUE arg)
1387{
1388 rb_io_t *fptr = (rb_io_t *)arg;
1389 return rb_thread_io_blocking_call(io_flush_buffer_sync, fptr, fptr->fd, RB_WAITFD_OUT);
1390}
1391
1392static inline int
1393io_flush_buffer(rb_io_t *fptr)
1394{
1395 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1396 return (int)io_flush_buffer_async((VALUE)fptr);
1397 }
1398 else {
1399 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1400 }
1401}
1402
1403static int
1404io_fflush(rb_io_t *fptr)
1405{
1406 rb_io_check_closed(fptr);
1407
1408 if (fptr->wbuf.len == 0)
1409 return 0;
1410
1411 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1412 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1413 return -1;
1414
1415 rb_io_check_closed(fptr);
1416 }
1417
1418 return 0;
1419}
1420
1421 VALUE
1422rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1423{
1424 VALUE scheduler = rb_fiber_scheduler_current();
1425
1426 if (scheduler != Qnil) {
1427 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1428 }
1429
1430 rb_io_t * fptr = NULL;
1431 RB_IO_POINTER(io, fptr);
1432
1433 struct timeval tv_storage;
1434 struct timeval *tv = NULL;
1435
1436 if (NIL_OR_UNDEF_P(timeout)) {
1437 timeout = fptr->timeout;
1438 }
1439
1440 if (timeout != Qnil) {
1441 tv_storage = rb_time_interval(timeout);
1442 tv = &tv_storage;
1443 }
1444
1445 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1446
1447 if (ready < 0) {
1448 rb_sys_fail(0);
1449 }
1450
1451 // Not sure if this is necessary:
1452 rb_io_check_closed(fptr);
1453
1454 if (ready) {
1455 return RB_INT2NUM(ready);
1456 }
1457 else {
1458 return Qfalse;
1459 }
1460}
1461
1462static VALUE
1463io_from_fd(int fd)
1464{
1465 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1466}
1467
1468static int
1469io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1470{
1471 VALUE scheduler = rb_fiber_scheduler_current();
1472
1473 if (scheduler != Qnil) {
1474 return RTEST(
1475 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1476 );
1477 }
1478
1479 return rb_thread_wait_for_single_fd(fd, events, timeout);
1480}
1481
1482int
1483rb_io_wait_readable(int f)
1484{
1485 io_fd_check_closed(f);
1486
1487 VALUE scheduler = rb_fiber_scheduler_current();
1488
1489 switch (errno) {
1490 case EINTR:
1491#if defined(ERESTART)
1492 case ERESTART:
1493#endif
1494 rb_thread_check_ints();
1495 return TRUE;
1496
1497 case EAGAIN:
1498#if EWOULDBLOCK != EAGAIN
1499 case EWOULDBLOCK:
1500#endif
1501 if (scheduler != Qnil) {
1502 return RTEST(
1503 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1504 );
1505 }
1506 else {
1507 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1508 }
1509 return TRUE;
1510
1511 default:
1512 return FALSE;
1513 }
1514}
1515
1516int
1517rb_io_wait_writable(int f)
1518{
1519 io_fd_check_closed(f);
1520
1521 VALUE scheduler = rb_fiber_scheduler_current();
1522
1523 switch (errno) {
1524 case EINTR:
1525#if defined(ERESTART)
1526 case ERESTART:
1527#endif
1528 /*
1529 * In old Linux, several special files under /proc and /sys don't handle
1530 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1531 * Otherwise, we face nasty hang up. Sigh.
1532 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1533 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1534 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1535 * Then rb_thread_check_ints() is enough.
1536 */
1537 rb_thread_check_ints();
1538 return TRUE;
1539
1540 case EAGAIN:
1541#if EWOULDBLOCK != EAGAIN
1542 case EWOULDBLOCK:
1543#endif
1544 if (scheduler != Qnil) {
1545 return RTEST(
1546 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1547 );
1548 }
1549 else {
1550 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1551 }
1552 return TRUE;
1553
1554 default:
1555 return FALSE;
1556 }
1557}
1558
1559int
1560rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1561{
1562 return io_wait_for_single_fd(fd, events, timeout);
1563}
1564
1565int
1566rb_thread_wait_fd(int fd)
1567{
1568 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1569}
1570
1571int
1572rb_thread_fd_writable(int fd)
1573{
1574 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1575}
1576
1577 VALUE
1578rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1579{
1580 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1581 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1582 // instead relies on `read(-1) -> -1` which causes this code path. We then
1583 // check here whether the IO was in fact closed. Probably it's better to
1584 // check that `fptr->fd != -1` before using it in syscall.
1585 rb_io_check_closed(RFILE(io)->fptr);
1586
1587 switch (error) {
1588 // In old Linux, several special files under /proc and /sys don't handle
1589 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1590 // Otherwise, we face nasty hang up. Sigh.
1591 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1592 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1593 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1594 // Then rb_thread_check_ints() is enough.
1595 case EINTR:
1596#if defined(ERESTART)
1597 case ERESTART:
1598#endif
1599 // We might have pending interrupts since the previous syscall was interrupted:
1600 rb_thread_check_ints();
1601
1602 // The operation was interrupted, so retry it immediately:
1603 return events;
1604
1605 case EAGAIN:
1606#if EWOULDBLOCK != EAGAIN
1607 case EWOULDBLOCK:
1608#endif
1609 // The operation would block, so wait for the specified events:
1610 return rb_io_wait(io, events, timeout);
1611
1612 default:
1613 // Non-specific error, no event is ready:
1614 return Qfalse;
1615 }
1616}
1617
1618int
1619rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
1620{
1621 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1622
1623 if (RTEST(result)) {
1624 return RB_NUM2INT(result);
1625 }
1626 else {
1627 return 0;
1628 }
1629}
1630
1631int
1632rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
1633{
1634 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1635
1636 if (RTEST(result)) {
1637 return RB_NUM2INT(result);
1638 }
1639 else {
1640 return 0;
1641 }
1642}
1643
1644static void
1645make_writeconv(rb_io_t *fptr)
1646{
1647 if (!fptr->writeconv_initialized) {
1648 const char *senc, *denc;
1649 rb_encoding *enc;
1650 int ecflags;
1651 VALUE ecopts;
1652
1653 fptr->writeconv_initialized = 1;
1654
1655 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1656 ecopts = fptr->encs.ecopts;
1657
1658 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1659 /* no encoding conversion */
1660 fptr->writeconv_pre_ecflags = 0;
1661 fptr->writeconv_pre_ecopts = Qnil;
1662 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1663 if (!fptr->writeconv)
1664 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1665 fptr->writeconv_asciicompat = Qnil;
1666 }
1667 else {
1668 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1669 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1670 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1671 /* single conversion */
1672 fptr->writeconv_pre_ecflags = ecflags;
1673 fptr->writeconv_pre_ecopts = ecopts;
1674 fptr->writeconv = NULL;
1675 fptr->writeconv_asciicompat = Qnil;
1676 }
1677 else {
1678 /* double conversion */
1679 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1680 fptr->writeconv_pre_ecopts = ecopts;
1681 if (senc) {
1682 denc = rb_enc_name(enc);
1683 fptr->writeconv_asciicompat = rb_str_new2(senc);
1684 }
1685 else {
1686 senc = denc = "";
1687 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1688 }
1689 ecflags = fptr->encs.ecflags & (ECONV_ERROR_HANDLER_MASK|ECONV_STATEFUL_DECORATOR_MASK);
1690 ecopts = fptr->encs.ecopts;
1691 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1692 if (!fptr->writeconv)
1693 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1694 }
1695 }
1696 }
1697}
1698
1699/* writing functions */
1700 struct binwrite_arg {
1701 rb_io_t *fptr;
1702 VALUE str;
1703 const char *ptr;
1704 long length;
1705};
1706
1707 struct write_arg {
1708 VALUE io;
1709 VALUE str;
1710 int nosync;
1711};
1712
1713#ifdef HAVE_WRITEV
1714static ssize_t
1715io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1716{
1717 if (fptr->wbuf.len) {
1718 struct iovec iov[2];
1719
1720 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1721 iov[0].iov_len = fptr->wbuf.len;
1722 iov[1].iov_base = (void*)ptr;
1723 iov[1].iov_len = length;
1724
1725 ssize_t result = rb_writev_internal(fptr, iov, 2);
1726
1727 if (result < 0)
1728 return result;
1729
1730 if (result >= fptr->wbuf.len) {
1731 // We wrote more than the internal buffer:
1732 result -= fptr->wbuf.len;
1733 fptr->wbuf.off = 0;
1734 fptr->wbuf.len = 0;
1735 }
1736 else {
1737 // We only wrote less data than the internal buffer:
1738 fptr->wbuf.off += (int)result;
1739 fptr->wbuf.len -= (int)result;
1740
1741 result = 0;
1742 }
1743
1744 return result;
1745 }
1746 else {
1747 return rb_io_write_memory(fptr, ptr, length);
1748 }
1749}
1750#else
1751static ssize_t
1752io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1753{
1754 long remaining = length;
1755
1756 if (fptr->wbuf.len) {
1757 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1758 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1759 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1760 fptr->wbuf.off = 0;
1761 }
1762
1763 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1764 fptr->wbuf.len += (int)length;
1765
1766 // We copied the entire incoming data to the internal buffer:
1767 remaining = 0;
1768 }
1769
1770 // Flush the internal buffer:
1771 if (io_fflush(fptr) < 0) {
1772 return -1;
1773 }
1774
1775 // If all the data was buffered, we are done:
1776 if (remaining == 0) {
1777 return length;
1778 }
1779 }
1780
1781 // Otherwise, we should write the data directly:
1782 return rb_io_write_memory(fptr, ptr, length);
1783}
1784#endif
1785
1786static VALUE
1787io_binwrite_string(VALUE arg)
1788{
1789 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1790
1791 const char *ptr = p->ptr;
1792 size_t remaining = p->length;
1793
1794 while (remaining) {
1795 // Write as much as possible:
1796 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1797
1798 if (result == 0) {
1799 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1800 // should try again immediately.
1801 }
1802 else if (result > 0) {
1803 if ((size_t)result == remaining) break;
1804 ptr += result;
1805 remaining -= result;
1806 }
1807 // Wait for it to become writable:
1808 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1809 rb_io_check_closed(p->fptr);
1810 }
1811 else {
1812 // The error was unrelated to waiting for it to become writable, so we fail:
1813 return -1;
1814 }
1815 }
1816
1817 return p->length;
1818}
1819
1820inline static void
1821io_allocate_write_buffer(rb_io_t *fptr, int sync)
1822{
1823 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1824 fptr->wbuf.off = 0;
1825 fptr->wbuf.len = 0;
1826 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1827 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1828 }
1829
1830 if (NIL_P(fptr->write_lock)) {
1831 fptr->write_lock = rb_mutex_new();
1832 rb_mutex_allow_trap(fptr->write_lock, 1);
1833 }
1834}
1835
1836static inline int
1837io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1838{
1839 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1840 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1841 return 1;
1842
1843 // If the amount of data we want to write exceeds the internal buffer:
1844 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1845 return 1;
1846
1847 // Otherwise, we can append to the internal buffer:
1848 return 0;
1849}
1850
1851static long
1852io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
1853{
1854 if (len <= 0) return len;
1855
1856 // Don't write anything if current thread has a pending interrupt:
1857 rb_thread_check_ints();
1858
1859 io_allocate_write_buffer(fptr, !nosync);
1860
1861 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1862 struct binwrite_arg arg;
1863
1864 arg.fptr = fptr;
1865 arg.str = str;
1866 arg.ptr = ptr;
1867 arg.length = len;
1868
1869 if (!NIL_P(fptr->write_lock)) {
1870 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1871 }
1872 else {
1873 return io_binwrite_string((VALUE)&arg);
1874 }
1875 }
1876 else {
1877 if (fptr->wbuf.off) {
1878 if (fptr->wbuf.len)
1879 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1880 fptr->wbuf.off = 0;
1881 }
1882
1883 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1884 fptr->wbuf.len += (int)len;
1885
1886 return len;
1887 }
1888}
1889
1890# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1891 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1892
1893#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1894 MODE_BTMODE(d, e, f) : \
1895 MODE_BTMODE(a, b, c))
1896
1897static VALUE
1898do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1899{
1900 if (NEED_WRITECONV(fptr)) {
1901 VALUE common_encoding = Qnil;
1902 SET_BINARY_MODE(fptr);
1903
1904 make_writeconv(fptr);
1905
1906 if (fptr->writeconv) {
1907#define fmode (fptr->mode)
1908 if (!NIL_P(fptr->writeconv_asciicompat))
1909 common_encoding = fptr->writeconv_asciicompat;
1910 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1911 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1912 rb_enc_name(rb_enc_get(str)));
1913 }
1914#undef fmode
1915 }
1916 else {
1917 if (fptr->encs.enc2)
1918 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1919 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1920 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1921 }
1922
1923 if (!NIL_P(common_encoding)) {
1924 str = rb_str_encode(str, common_encoding,
1925 fptr->writeconv_pre_ecflags, fptr->writeconv_pre_ecopts);
1926 *converted = 1;
1927 }
1928
1929 if (fptr->writeconv) {
1930 str = rb_econv_str_convert(fptr->writeconv, str, ECONV_PARTIAL_INPUT);
1931 *converted = 1;
1932 }
1933 }
1934#if RUBY_CRLF_ENVIRONMENT
1935#define fmode (fptr->mode)
1936 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1937 if ((fptr->mode & FMODE_READABLE) &&
1938 !(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
1939 setmode(fptr->fd, O_BINARY);
1940 }
1941 else {
1942 setmode(fptr->fd, O_TEXT);
1943 }
1944 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1945 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1946 rb_enc_name(rb_enc_get(str)));
1947 }
1948 }
1949#undef fmode
1950#endif
1951 return str;
1952}
1953
1954static long
1955io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1956{
1957 int converted = 0;
1958 VALUE tmp;
1959 long n, len;
1960 const char *ptr;
1961
1962#ifdef _WIN32
1963 if (fptr->mode & FMODE_TTY) {
1964 long len = rb_w32_write_console(str, fptr->fd);
1965 if (len > 0) return len;
1966 }
1967#endif
1968
1969 str = do_writeconv(str, fptr, &converted);
1970 if (converted)
1971 OBJ_FREEZE(str);
1972
1973 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
1974 RSTRING_GETMEM(tmp, ptr, len);
1975 n = io_binwrite(tmp, ptr, len, fptr, nosync);
1976 rb_str_tmp_frozen_release(str, tmp);
1977
1978 return n;
1979}
1980
1981ssize_t
1982rb_io_bufwrite(VALUE io, const void *buf, size_t size)
1983{
1984 rb_io_t *fptr;
1985
1986 GetOpenFile(io, fptr);
1987 rb_io_check_writable(fptr);
1988 return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
1989}
1990
1991static VALUE
1992io_write(VALUE io, VALUE str, int nosync)
1993{
1994 rb_io_t *fptr;
1995 long n;
1996 VALUE tmp;
1997
1998 io = GetWriteIO(io);
1999 str = rb_obj_as_string(str);
2000 tmp = rb_io_check_io(io);
2001
2002 if (NIL_P(tmp)) {
2003 /* port is not IO, call write method for it. */
2004 return rb_funcall(io, id_write, 1, str);
2005 }
2006
2007 io = tmp;
2008 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2009
2010 GetOpenFile(io, fptr);
2011 rb_io_check_writable(fptr);
2012
2013 n = io_fwrite(str, fptr, nosync);
2014 if (n < 0L) rb_sys_fail_on_write(fptr);
2015
2016 return LONG2FIX(n);
2017}
2018
2019#ifdef HAVE_WRITEV
2020struct binwritev_arg {
2021 rb_io_t *fptr;
2022 struct iovec *iov;
2023 int iovcnt;
2024 size_t total;
2025};
2026
2027static VALUE
2028io_binwritev_internal(VALUE arg)
2029{
2030 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2031
2032 size_t remaining = p->total;
2033 size_t offset = 0;
2034
2035 rb_io_t *fptr = p->fptr;
2036 struct iovec *iov = p->iov;
2037 int iovcnt = p->iovcnt;
2038
2039 while (remaining) {
2040 long result = rb_writev_internal(fptr, iov, iovcnt);
2041
2042 if (result >= 0) {
2043 offset += result;
2044 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2045 if (offset < (size_t)fptr->wbuf.len) {
2046 fptr->wbuf.off += result;
2047 fptr->wbuf.len -= result;
2048 }
2049 else {
2050 offset -= (size_t)fptr->wbuf.len;
2051 fptr->wbuf.off = 0;
2052 fptr->wbuf.len = 0;
2053 }
2054 }
2055
2056 if (offset == p->total) {
2057 return p->total;
2058 }
2059
2060 while (result >= (ssize_t)iov->iov_len) {
2061 /* iovcnt > 0 */
2062 result -= iov->iov_len;
2063 iov->iov_len = 0;
2064 iov++;
2065
2066 if (!--iovcnt) {
2067 // I don't believe this code path can ever occur.
2068 return offset;
2069 }
2070 }
2071
2072 iov->iov_base = (char *)iov->iov_base + result;
2073 iov->iov_len -= result;
2074 }
2075 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2076 rb_io_check_closed(fptr);
2077 }
2078 else {
2079 return -1;
2080 }
2081 }
2082
2083 return offset;
2084}
2085
2086static long
2087io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2088{
2089 // Don't write anything if current thread has a pending interrupt:
2090 rb_thread_check_ints();
2091
2092 if (iovcnt == 0) return 0;
2093
2094 size_t total = 0;
2095 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2096
2097 io_allocate_write_buffer(fptr, 1);
2098
2099 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2100 // The end of the buffered data:
2101 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2102
2103 if (offset + total <= (size_t)fptr->wbuf.capa) {
2104 for (int i = 1; i < iovcnt; i++) {
2105 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2106 offset += iov[i].iov_len;
2107 }
2108
2109 fptr->wbuf.len += total;
2110
2111 return total;
2112 }
2113 else {
2114 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2115 iov[0].iov_len = fptr->wbuf.len;
2116 }
2117 }
2118 else {
2119 // The first iov is reserved for the internal buffer, and it's empty.
2120 iov++;
2121
2122 if (!--iovcnt) {
2123 // If there are no other io vectors we are done.
2124 return 0;
2125 }
2126 }
2127
2128 struct binwritev_arg arg;
2129 arg.fptr = fptr;
2130 arg.iov = iov;
2131 arg.iovcnt = iovcnt;
2132 arg.total = total;
2133
2134 if (!NIL_P(fptr->write_lock)) {
2135 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2136 }
2137 else {
2138 return io_binwritev_internal((VALUE)&arg);
2139 }
2140}
2141
2142static long
2143io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2144{
2145 int i, converted, iovcnt = argc + 1;
2146 long n;
2147 VALUE v1, v2, str, tmp, *tmp_array;
2148 struct iovec *iov;
2149
2150 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2151 tmp_array = ALLOCV_N(VALUE, v2, argc);
2152
2153 for (i = 0; i < argc; i++) {
2154 str = rb_obj_as_string(argv[i]);
2155 converted = 0;
2156 str = do_writeconv(str, fptr, &converted);
2157
2158 if (converted)
2159 OBJ_FREEZE(str);
2160
2161 tmp = rb_str_tmp_frozen_acquire(str);
2162 tmp_array[i] = tmp;
2163
2164 /* iov[0] is reserved for buffer of fptr */
2165 iov[i+1].iov_base = RSTRING_PTR(tmp);
2166 iov[i+1].iov_len = RSTRING_LEN(tmp);
2167 }
2168
2169 n = io_binwritev(iov, iovcnt, fptr);
2170 if (v1) ALLOCV_END(v1);
2171
2172 for (i = 0; i < argc; i++) {
2173 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2174 }
2175
2176 if (v2) ALLOCV_END(v2);
2177
2178 return n;
2179}
2180
2181static int
2182iovcnt_ok(int iovcnt)
2183{
2184#ifdef IOV_MAX
2185 return iovcnt < IOV_MAX;
2186#else /* GNU/Hurd has writev, but no IOV_MAX */
2187 return 1;
2188#endif
2189}
2190#endif /* HAVE_WRITEV */
2191
2192static VALUE
2193io_writev(int argc, const VALUE *argv, VALUE io)
2194{
2195 rb_io_t *fptr;
2196 long n;
2197 VALUE tmp, total = INT2FIX(0);
2198 int i, cnt = 1;
2199
2200 io = GetWriteIO(io);
2201 tmp = rb_io_check_io(io);
2202
2203 if (NIL_P(tmp)) {
2204 /* port is not IO, call write method for it. */
2205 return rb_funcallv(io, id_write, argc, argv);
2206 }
2207
2208 io = tmp;
2209
2210 GetOpenFile(io, fptr);
2211 rb_io_check_writable(fptr);
2212
2213 for (i = 0; i < argc; i += cnt) {
2214#ifdef HAVE_WRITEV
2215 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2216 n = io_fwritev(cnt, &argv[i], fptr);
2217 }
2218 else
2219#endif
2220 {
2221 cnt = 1;
2222 /* sync at last item */
2223 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2224 }
2225
2226 if (n < 0L)
2227 rb_sys_fail_on_write(fptr);
2228
2229 total = rb_fix_plus(LONG2FIX(n), total);
2230 }
2231
2232 return total;
2233}
2234
2235/*
2236 * call-seq:
2237 * write(*objects) -> integer
2238 *
2239 * Writes each of the given +objects+ to +self+,
2240 * which must be opened for writing
2241 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2242 * returns the total number bytes written;
2243 * each of +objects+ that is not a string is converted via method +to_s+:
2244 *
2245 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2246 * $stdout.write('foo', :bar, 2, "\n") # => 8
2247 *
2248 * Output:
2249 *
2250 * Hello, World!
2251 * foobar2
2252 *
2253 * Related: IO#read.
2254 */
2255
2256static VALUE
2257io_write_m(int argc, VALUE *argv, VALUE io)
2258{
2259 if (argc != 1) {
2260 return io_writev(argc, argv, io);
2261 }
2262 else {
2263 VALUE str = argv[0];
2264 return io_write(io, str, 0);
2265 }
2266}
2267
2268 VALUE
2269rb_io_write(VALUE io, VALUE str)
2270{
2271 return rb_funcallv(io, id_write, 1, &str);
2272}
2273
2274static VALUE
2275rb_io_writev(VALUE io, int argc, const VALUE *argv)
2276{
2277 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2278 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2279 VALUE klass = CLASS_OF(io);
2280 char sep = FL_TEST(klass, FL_SINGLETON) ? (klass = io, '.') : '#';
2281 rb_category_warning(
2282 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2283 " which accepts just one argument",
2284 klass, sep
2285 );
2286 }
2287
2288 do rb_io_write(io, *argv++); while (--argc);
2289
2290 return Qnil;
2291 }
2292
2293 return rb_funcallv(io, id_write, argc, argv);
2294}
2295
2296/*
2297 * call-seq:
2298 * self << object -> self
2299 *
2300 * Writes the given +object+ to +self+,
2301 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2302 * returns +self+;
2303 * if +object+ is not a string, it is converted via method +to_s+:
2304 *
2305 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2306 * $stdout << 'foo' << :bar << 2 << "\n"
2307 *
2308 * Output:
2309 *
2310 * Hello, World!
2311 * foobar2
2312 *
2313 */
2314
2315
2316 VALUE
2317rb_io_addstr(VALUE io, VALUE str)
2318{
2319 rb_io_write(io, str);
2320 return io;
2321}
2322
2323#ifdef HAVE_FSYNC
2324static VALUE
2325nogvl_fsync(void *ptr)
2326{
2327 rb_io_t *fptr = ptr;
2328
2329#ifdef _WIN32
2330 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2331 return 0;
2332#endif
2333 return (VALUE)fsync(fptr->fd);
2334}
2335#endif
2336
2337 VALUE
2338rb_io_flush_raw(VALUE io, int sync)
2339{
2340 rb_io_t *fptr;
2341
2342 if (!RB_TYPE_P(io, T_FILE)) {
2343 return rb_funcall(io, id_flush, 0);
2344 }
2345
2346 io = GetWriteIO(io);
2347 GetOpenFile(io, fptr);
2348
2349 if (fptr->mode & FMODE_WRITABLE) {
2350 if (io_fflush(fptr) < 0)
2351 rb_sys_fail_on_write(fptr);
2352 }
2353 if (fptr->mode & FMODE_READABLE) {
2354 io_unread(fptr);
2355 }
2356
2357 return io;
2358}
2359
2360/*
2361 * call-seq:
2362 * flush -> self
2363 *
2364 * Flushes data buffered in +self+ to the operating system
2365 * (but does not necessarily flush data buffered in the operating system):
2366 *
2367 * $stdout.print 'no newline' # Not necessarily flushed.
2368 * $stdout.flush # Flushed.
2369 *
2370 */
2371
2372 VALUE
2373rb_io_flush(VALUE io)
2374{
2375 return rb_io_flush_raw(io, 1);
2376}
2377
2378/*
2379 * call-seq:
2380 * tell -> integer
2381 *
2382 * Returns the current position (in bytes) in +self+
2383 * (see {Position}[rdoc-ref:IO@Position]):
2384 *
2385 * f = File.open('t.txt')
2386 * f.tell # => 0
2387 * f.gets # => "First line\n"
2388 * f.tell # => 12
2389 * f.close
2390 *
2391 * Related: IO#pos=, IO#seek.
2392 */
2393
2394static VALUE
2395rb_io_tell(VALUE io)
2396{
2397 rb_io_t *fptr;
2398 rb_off_t pos;
2399
2400 GetOpenFile(io, fptr);
2401 pos = io_tell(fptr);
2402 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2403 pos -= fptr->rbuf.len;
2404 return OFFT2NUM(pos);
2405}
2406
2407static VALUE
2408rb_io_seek(VALUE io, VALUE offset, int whence)
2409{
2410 rb_io_t *fptr;
2411 rb_off_t pos;
2412
2413 pos = NUM2OFFT(offset);
2414 GetOpenFile(io, fptr);
2415 pos = io_seek(fptr, pos, whence);
2416 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2417
2418 return INT2FIX(0);
2419}
2420
2421static int
2422interpret_seek_whence(VALUE vwhence)
2423{
2424 if (vwhence == sym_SET)
2425 return SEEK_SET;
2426 if (vwhence == sym_CUR)
2427 return SEEK_CUR;
2428 if (vwhence == sym_END)
2429 return SEEK_END;
2430#ifdef SEEK_DATA
2431 if (vwhence == sym_DATA)
2432 return SEEK_DATA;
2433#endif
2434#ifdef SEEK_HOLE
2435 if (vwhence == sym_HOLE)
2436 return SEEK_HOLE;
2437#endif
2438 return NUM2INT(vwhence);
2439}
2440
2441/*
2442 * call-seq:
2443 * seek(offset, whence = IO::SEEK_SET) -> 0
2444 *
2445 * Seeks to the position given by integer +offset+
2446 * (see {Position}[rdoc-ref:IO@Position])
2447 * and constant +whence+, which is one of:
2448 *
2449 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2450 * Repositions the stream to its current position plus the given +offset+:
2451 *
2452 * f = File.open('t.txt')
2453 * f.tell # => 0
2454 * f.seek(20, :CUR) # => 0
2455 * f.tell # => 20
2456 * f.seek(-10, :CUR) # => 0
2457 * f.tell # => 10
2458 * f.close
2459 *
2460 * - +:END+ or <tt>IO::SEEK_END</tt>:
2461 * Repositions the stream to its end plus the given +offset+:
2462 *
2463 * f = File.open('t.txt')
2464 * f.tell # => 0
2465 * f.seek(0, :END) # => 0 # Repositions to stream end.
2466 * f.tell # => 52
2467 * f.seek(-20, :END) # => 0
2468 * f.tell # => 32
2469 * f.seek(-40, :END) # => 0
2470 * f.tell # => 12
2471 * f.close
2472 *
2473 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2474 * Repositions the stream to the given +offset+:
2475 *
2476 * f = File.open('t.txt')
2477 * f.tell # => 0
2478 * f.seek(20, :SET) # => 0
2479 * f.tell # => 20
2480 * f.seek(40, :SET) # => 0
2481 * f.tell # => 40
2482 * f.close
2483 *
2484 * Related: IO#pos=, IO#tell.
2485 *
2486 */
2487
2488static VALUE
2489rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2490{
2491 VALUE offset, ptrname;
2492 int whence = SEEK_SET;
2493
2494 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2495 whence = interpret_seek_whence(ptrname);
2496 }
2497
2498 return rb_io_seek(io, offset, whence);
2499}
2500
2501/*
2502 * call-seq:
2503 * pos = new_position -> new_position
2504 *
2505 * Seeks to the given +new_position+ (in bytes);
2506 * see {Position}[rdoc-ref:IO@Position]:
2507 *
2508 * f = File.open('t.txt')
2509 * f.tell # => 0
2510 * f.pos = 20 # => 20
2511 * f.tell # => 20
2512 * f.close
2513 *
2514 * Related: IO#seek, IO#tell.
2515 *
2516 */
2517
2518static VALUE
2519rb_io_set_pos(VALUE io, VALUE offset)
2520{
2521 rb_io_t *fptr;
2522 rb_off_t pos;
2523
2524 pos = NUM2OFFT(offset);
2525 GetOpenFile(io, fptr);
2526 pos = io_seek(fptr, pos, SEEK_SET);
2527 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2528
2529 return OFFT2NUM(pos);
2530}
2531
2532static void clear_readconv(rb_io_t *fptr);
2533
2534/*
2535 * call-seq:
2536 * rewind -> 0
2537 *
2538 * Repositions the stream to its beginning,
2539 * setting both the position and the line number to zero;
2540 * see {Position}[rdoc-ref:IO@Position]
2541 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2542 *
2543 * f = File.open('t.txt')
2544 * f.tell # => 0
2545 * f.lineno # => 0
2546 * f.gets # => "First line\n"
2547 * f.tell # => 12
2548 * f.lineno # => 1
2549 * f.rewind # => 0
2550 * f.tell # => 0
2551 * f.lineno # => 0
2552 * f.close
2553 *
2554 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2555 *
2556 */
2557
2558static VALUE
2559rb_io_rewind(VALUE io)
2560{
2561 rb_io_t *fptr;
2562
2563 GetOpenFile(io, fptr);
2564 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2565 if (io == ARGF.current_file) {
2566 ARGF.lineno -= fptr->lineno;
2567 }
2568 fptr->lineno = 0;
2569 if (fptr->readconv) {
2570 clear_readconv(fptr);
2571 }
2572
2573 return INT2FIX(0);
2574}
2575
2576static int
2577fptr_wait_readable(rb_io_t *fptr)
2578{
2579 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2580
2581 if (result)
2582 rb_io_check_closed(fptr);
2583
2584 return result;
2585}
2586
2587static int
2588io_fillbuf(rb_io_t *fptr)
2589{
2590 ssize_t r;
2591
2592 if (fptr->rbuf.ptr == NULL) {
2593 fptr->rbuf.off = 0;
2594 fptr->rbuf.len = 0;
2595 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2596 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2597#ifdef _WIN32
2598 fptr->rbuf.capa--;
2599#endif
2600 }
2601 if (fptr->rbuf.len == 0) {
2602 retry:
2603 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2604
2605 if (r < 0) {
2606 if (fptr_wait_readable(fptr))
2607 goto retry;
2608
2609 int e = errno;
2610 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2611 if (!NIL_P(fptr->pathv)) {
2612 rb_str_append(path, fptr->pathv);
2613 }
2614
2615 rb_syserr_fail_path(e, path);
2616 }
2617 if (r > 0) rb_io_check_closed(fptr);
2618 fptr->rbuf.off = 0;
2619 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2620 if (r == 0)
2621 return -1; /* EOF */
2622 }
2623 return 0;
2624}
2625
2626/*
2627 * call-seq:
2628 * eof -> true or false
2629 *
2630 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2631 * see {Position}[rdoc-ref:IO@Position]:
2632 *
2633 * f = File.open('t.txt')
2634 * f.eof # => false
2635 * f.seek(0, :END) # => 0
2636 * f.eof # => true
2637 * f.close
2638 *
2639 * Raises an exception unless the stream is opened for reading;
2640 * see {Mode}[rdoc-ref:File@Access+Modes].
2641 *
2642 * If +self+ is a stream such as pipe or socket, this method
2643 * blocks until the other end sends some data or closes it:
2644 *
2645 * r, w = IO.pipe
2646 * Thread.new { sleep 1; w.close }
2647 * r.eof? # => true # After 1-second wait.
2648 *
2649 * r, w = IO.pipe
2650 * Thread.new { sleep 1; w.puts "a" }
2651 * r.eof? # => false # After 1-second wait.
2652 *
2653 * r, w = IO.pipe
2654 * r.eof? # blocks forever
2655 *
2656 * Note that this method reads data to the input byte buffer. So
2657 * IO#sysread may not behave as you intend with IO#eof?, unless you
2658 * call IO#rewind first (which is not available for some streams).
2659 */
2660
2661 VALUE
2662rb_io_eof(VALUE io)
2663{
2664 rb_io_t *fptr;
2665
2666 GetOpenFile(io, fptr);
2667 rb_io_check_char_readable(fptr);
2668
2669 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2670 if (READ_DATA_PENDING(fptr)) return Qfalse;
2671 READ_CHECK(fptr);
2672#if RUBY_CRLF_ENVIRONMENT
2673 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2674 return RBOOL(eof(fptr->fd));;
2675 }
2676#endif
2677 return RBOOL(io_fillbuf(fptr) < 0);
2678}
2679
2680/*
2681 * call-seq:
2682 * sync -> true or false
2683 *
2684 * Returns the current sync mode of the stream.
2685 * When sync mode is true, all output is immediately flushed to the underlying
2686 * operating system and is not buffered by Ruby internally. See also #fsync.
2687 *
2688 * f = File.open('t.tmp', 'w')
2689 * f.sync # => false
2690 * f.sync = true
2691 * f.sync # => true
2692 * f.close
2693 *
2694 */
2695
2696static VALUE
2697rb_io_sync(VALUE io)
2698{
2699 rb_io_t *fptr;
2700
2701 io = GetWriteIO(io);
2702 GetOpenFile(io, fptr);
2703 return RBOOL(fptr->mode & FMODE_SYNC);
2704}
2705
2706#ifdef HAVE_FSYNC
2707
2708/*
2709 * call-seq:
2710 * sync = boolean -> boolean
2711 *
2712 * Sets the _sync_ _mode_ for the stream to the given value;
2713 * returns the given value.
2714 *
2715 * Values for the sync mode:
2716 *
2717 * - +true+: All output is immediately flushed to the
2718 * underlying operating system and is not buffered internally.
2719 * - +false+: Output may be buffered internally.
2720 *
2721 * Example;
2722 *
2723 * f = File.open('t.tmp', 'w')
2724 * f.sync # => false
2725 * f.sync = true
2726 * f.sync # => true
2727 * f.close
2728 *
2729 * Related: IO#fsync.
2730 *
2731 */
2732
2733static VALUE
2734rb_io_set_sync(VALUE io, VALUE sync)
2735{
2736 rb_io_t *fptr;
2737
2738 io = GetWriteIO(io);
2739 GetOpenFile(io, fptr);
2740 if (RTEST(sync)) {
2741 fptr->mode |= FMODE_SYNC;
2742 }
2743 else {
2744 fptr->mode &= ~FMODE_SYNC;
2745 }
2746 return sync;
2747}
2748
2749/*
2750 * call-seq:
2751 * fsync -> 0
2752 *
2753 * Immediately writes to disk all data buffered in the stream,
2754 * via the operating system's <tt>fsync(2)</tt>.
2755
2756 * Note this difference:
2757 *
2758 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2759 * but does not guarantee that the operating system actually writes the data to disk.
2760 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2761 * and that data is written to disk.
2762 *
2763 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2764 *
2765 */
2766
2767static VALUE
2768rb_io_fsync(VALUE io)
2769{
2770 rb_io_t *fptr;
2771
2772 io = GetWriteIO(io);
2773 GetOpenFile(io, fptr);
2774
2775 if (io_fflush(fptr) < 0)
2776 rb_sys_fail_on_write(fptr);
2777 if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
2778 rb_sys_fail_path(fptr->pathv);
2779 return INT2FIX(0);
2780}
2781#else
2782# define rb_io_fsync rb_f_notimplement
2783# define rb_io_sync rb_f_notimplement
2784static VALUE
2785rb_io_set_sync(VALUE io, VALUE sync)
2786{
2787 rb_notimplement();
2788 UNREACHABLE;
2789}
2790#endif
2791
2792#ifdef HAVE_FDATASYNC
2793static VALUE
2794nogvl_fdatasync(void *ptr)
2795{
2796 rb_io_t *fptr = ptr;
2797
2798#ifdef _WIN32
2799 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2800 return 0;
2801#endif
2802 return (VALUE)fdatasync(fptr->fd);
2803}
2804
2805/*
2806 * call-seq:
2807 * fdatasync -> 0
2808 *
2809 * Immediately writes to disk all data buffered in the stream,
2810 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2811 * otherwise via <tt>fsync(2)</tt>, if supported;
2812 * otherwise raises an exception.
2813 *
2814 */
2815
2816static VALUE
2817rb_io_fdatasync(VALUE io)
2818{
2819 rb_io_t *fptr;
2820
2821 io = GetWriteIO(io);
2822 GetOpenFile(io, fptr);
2823
2824 if (io_fflush(fptr) < 0)
2825 rb_sys_fail_on_write(fptr);
2826
2827 if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
2828 return INT2FIX(0);
2829
2830 /* fall back */
2831 return rb_io_fsync(io);
2832}
2833#else
2834#define rb_io_fdatasync rb_io_fsync
2835#endif
2836
2837/*
2838 * call-seq:
2839 * fileno -> integer
2840 *
2841 * Returns the integer file descriptor for the stream:
2842 *
2843 * $stdin.fileno # => 0
2844 * $stdout.fileno # => 1
2845 * $stderr.fileno # => 2
2846 * File.open('t.txt').fileno # => 10
2847 * f.close
2848 *
2849 */
2850
2851static VALUE
2852rb_io_fileno(VALUE io)
2853{
2854 rb_io_t *fptr = RFILE(io)->fptr;
2855 int fd;
2856
2857 rb_io_check_closed(fptr);
2858 fd = fptr->fd;
2859 return INT2FIX(fd);
2860}
2861
2862int
2863rb_io_descriptor(VALUE io)
2864{
2865 if (RB_TYPE_P(io, T_FILE)) {
2866 rb_io_t *fptr = RFILE(io)->fptr;
2867 rb_io_check_closed(fptr);
2868 return fptr->fd;
2869 }
2870 else {
2871 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2872 if (!UNDEF_P(fileno)) {
2873 return RB_NUM2INT(fileno);
2874 }
2875 }
2876
2877 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2878
2879 UNREACHABLE_RETURN(-1);
2880}
2881
2882int
2883rb_io_mode(VALUE io)
2884{
2885 rb_io_t *fptr;
2886 GetOpenFile(io, fptr);
2887 return fptr->mode;
2888}
2889
2890/*
2891 * call-seq:
2892 * pid -> integer or nil
2893 *
2894 * Returns the process ID of a child process associated with the stream,
2895 * which will have been set by IO#popen, or +nil+ if the stream was not
2896 * created by IO#popen:
2897 *
2898 * pipe = IO.popen("-")
2899 * if pipe
2900 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2901 * else
2902 * $stderr.puts "In child, pid is #{$$}"
2903 * end
2904 *
2905 * Output:
2906 *
2907 * In child, pid is 26209
2908 * In parent, child pid is 26209
2909 *
2910 */
2911
2912static VALUE
2913rb_io_pid(VALUE io)
2914{
2915 rb_io_t *fptr;
2916
2917 GetOpenFile(io, fptr);
2918 if (!fptr->pid)
2919 return Qnil;
2920 return PIDT2NUM(fptr->pid);
2921}
2922
2923/*
2924 * call-seq:
2925 * path -> string or nil
2926 *
2927 * Returns the path associated with the IO, or +nil+ if there is no path
2928 * associated with the IO. It is not guaranteed that the path exists on
2929 * the filesystem.
2930 *
2931 * $stdin.path # => "<STDIN>"
2932 *
2933 * File.open("testfile") {|f| f.path} # => "testfile"
2934 */
2935
2936 VALUE
2937rb_io_path(VALUE io)
2938{
2939 rb_io_t *fptr = RFILE(io)->fptr;
2940
2941 if (!fptr)
2942 return Qnil;
2943
2944 return rb_obj_dup(fptr->pathv);
2945}
2946
2947/*
2948 * call-seq:
2949 * inspect -> string
2950 *
2951 * Returns a string representation of +self+:
2952 *
2953 * f = File.open('t.txt')
2954 * f.inspect # => "#<File:t.txt>"
2955 * f.close
2956 *
2957 */
2958
2959static VALUE
2960rb_io_inspect(VALUE obj)
2961{
2962 rb_io_t *fptr;
2963 VALUE result;
2964 static const char closed[] = " (closed)";
2965
2966 fptr = RFILE(obj)->fptr;
2967 if (!fptr) return rb_any_to_s(obj);
2968 result = rb_str_new_cstr("#<");
2969 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2970 rb_str_cat2(result, ":");
2971 if (NIL_P(fptr->pathv)) {
2972 if (fptr->fd < 0) {
2973 rb_str_cat(result, closed+1, strlen(closed)-1);
2974 }
2975 else {
2976 rb_str_catf(result, "fd %d", fptr->fd);
2977 }
2978 }
2979 else {
2980 rb_str_append(result, fptr->pathv);
2981 if (fptr->fd < 0) {
2982 rb_str_cat(result, closed, strlen(closed));
2983 }
2984 }
2985 return rb_str_cat2(result, ">");
2986}
2987
2988/*
2989 * call-seq:
2990 * to_io -> self
2991 *
2992 * Returns +self+.
2993 *
2994 */
2995
2996static VALUE
2997rb_io_to_io(VALUE io)
2998{
2999 return io;
3000}
3001
3002/* reading functions */
3003static long
3004read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3005{
3006 int n;
3007
3008 n = READ_DATA_PENDING_COUNT(fptr);
3009 if (n <= 0) return 0;
3010 if (n > len) n = (int)len;
3011 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3012 fptr->rbuf.off += n;
3013 fptr->rbuf.len -= n;
3014 return n;
3015}
3016
3017static long
3018io_bufread(char *ptr, long len, rb_io_t *fptr)
3019{
3020 long offset = 0;
3021 long n = len;
3022 long c;
3023
3024 if (READ_DATA_PENDING(fptr) == 0) {
3025 while (n > 0) {
3026 again:
3027 rb_io_check_closed(fptr);
3028 c = rb_io_read_memory(fptr, ptr+offset, n);
3029 if (c == 0) break;
3030 if (c < 0) {
3031 if (fptr_wait_readable(fptr))
3032 goto again;
3033 return -1;
3034 }
3035 offset += c;
3036 if ((n -= c) <= 0) break;
3037 }
3038 return len - n;
3039 }
3040
3041 while (n > 0) {
3042 c = read_buffered_data(ptr+offset, n, fptr);
3043 if (c > 0) {
3044 offset += c;
3045 if ((n -= c) <= 0) break;
3046 }
3047 rb_io_check_closed(fptr);
3048 if (io_fillbuf(fptr) < 0) {
3049 break;
3050 }
3051 }
3052 return len - n;
3053}
3054
3055static int io_setstrbuf(VALUE *str, long len);
3056
3057 struct bufread_arg {
3058 char *str_ptr;
3059 long len;
3060 rb_io_t *fptr;
3061};
3062
3063static VALUE
3064bufread_call(VALUE arg)
3065{
3066 struct bufread_arg *p = (struct bufread_arg *)arg;
3067 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3068 return Qundef;
3069}
3070
3071static long
3072io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3073{
3074 long len;
3075 struct bufread_arg arg;
3076
3077 io_setstrbuf(&str, offset + size);
3078 arg.str_ptr = RSTRING_PTR(str) + offset;
3079 arg.len = size;
3080 arg.fptr = fptr;
3081 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3082 len = arg.len;
3083 if (len < 0) rb_sys_fail_path(fptr->pathv);
3084 return len;
3085}
3086
3087static long
3088remain_size(rb_io_t *fptr)
3089{
3090 struct stat st;
3091 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3092 rb_off_t pos;
3093
3094 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3095#if defined(__HAIKU__)
3096 && (st.st_dev > 3)
3097#endif
3098 )
3099 {
3100 if (io_fflush(fptr) < 0)
3101 rb_sys_fail_on_write(fptr);
3102 pos = lseek(fptr->fd, 0, SEEK_CUR);
3103 if (st.st_size >= pos && pos >= 0) {
3104 siz += st.st_size - pos;
3105 if (siz > LONG_MAX) {
3106 rb_raise(rb_eIOError, "file too big for single read");
3107 }
3108 }
3109 }
3110 else {
3111 siz += BUFSIZ;
3112 }
3113 return (long)siz;
3114}
3115
3116static VALUE
3117io_enc_str(VALUE str, rb_io_t *fptr)
3118{
3119 rb_enc_associate(str, io_read_encoding(fptr));
3120 return str;
3121}
3122
3123static rb_encoding *io_read_encoding(rb_io_t *fptr);
3124
3125static void
3126make_readconv(rb_io_t *fptr, int size)
3127{
3128 if (!fptr->readconv) {
3129 int ecflags;
3130 VALUE ecopts;
3131 const char *sname, *dname;
3132 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3133 ecopts = fptr->encs.ecopts;
3134 if (fptr->encs.enc2) {
3135 sname = rb_enc_name(fptr->encs.enc2);
3136 dname = rb_enc_name(io_read_encoding(fptr));
3137 }
3138 else {
3139 sname = dname = "";
3140 }
3141 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3142 if (!fptr->readconv)
3143 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3144 fptr->cbuf.off = 0;
3145 fptr->cbuf.len = 0;
3146 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3147 fptr->cbuf.capa = size;
3148 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3149 }
3150}
3151
3152#define MORE_CHAR_SUSPENDED Qtrue
3153#define MORE_CHAR_FINISHED Qnil
3154static VALUE
3155fill_cbuf(rb_io_t *fptr, int ec_flags)
3156{
3157 const unsigned char *ss, *sp, *se;
3158 unsigned char *ds, *dp, *de;
3159 rb_econv_result_t res;
3160 int putbackable;
3161 int cbuf_len0;
3162 VALUE exc;
3163
3164 ec_flags |= ECONV_PARTIAL_INPUT;
3165
3166 if (fptr->cbuf.len == fptr->cbuf.capa)
3167 return MORE_CHAR_SUSPENDED; /* cbuf full */
3168 if (fptr->cbuf.len == 0)
3169 fptr->cbuf.off = 0;
3170 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3171 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3172 fptr->cbuf.off = 0;
3173 }
3174
3175 cbuf_len0 = fptr->cbuf.len;
3176
3177 while (1) {
3178 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3179 se = sp + fptr->rbuf.len;
3180 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3181 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3182 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3183 fptr->rbuf.off += (int)(sp - ss);
3184 fptr->rbuf.len -= (int)(sp - ss);
3185 fptr->cbuf.len += (int)(dp - ds);
3186
3187 putbackable = rb_econv_putbackable(fptr->readconv);
3188 if (putbackable) {
3189 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3190 fptr->rbuf.off -= putbackable;
3191 fptr->rbuf.len += putbackable;
3192 }
3193
3194 exc = rb_econv_make_exception(fptr->readconv);
3195 if (!NIL_P(exc))
3196 return exc;
3197
3198 if (cbuf_len0 != fptr->cbuf.len)
3199 return MORE_CHAR_SUSPENDED;
3200
3201 if (res == econv_finished) {
3202 return MORE_CHAR_FINISHED;
3203 }
3204
3205 if (res == econv_source_buffer_empty) {
3206 if (fptr->rbuf.len == 0) {
3207 READ_CHECK(fptr);
3208 if (io_fillbuf(fptr) < 0) {
3209 if (!fptr->readconv) {
3210 return MORE_CHAR_FINISHED;
3211 }
3212 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3213 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3214 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3215 fptr->cbuf.len += (int)(dp - ds);
3216 rb_econv_check_error(fptr->readconv);
3217 break;
3218 }
3219 }
3220 }
3221 }
3222 if (cbuf_len0 != fptr->cbuf.len)
3223 return MORE_CHAR_SUSPENDED;
3224
3225 return MORE_CHAR_FINISHED;
3226}
3227
3228static VALUE
3229more_char(rb_io_t *fptr)
3230{
3231 VALUE v;
3232 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3233 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3234 rb_exc_raise(v);
3235 return v;
3236}
3237
3238static VALUE
3239io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3240{
3241 VALUE str = Qnil;
3242 if (strp) {
3243 str = *strp;
3244 if (NIL_P(str)) {
3245 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3246 }
3247 else {
3248 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3249 }
3250 rb_enc_associate(str, fptr->encs.enc);
3251 }
3252 fptr->cbuf.off += len;
3253 fptr->cbuf.len -= len;
3254 /* xxx: set coderange */
3255 if (fptr->cbuf.len == 0)
3256 fptr->cbuf.off = 0;
3257 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3258 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3259 fptr->cbuf.off = 0;
3260 }
3261 return str;
3262}
3263
3264static int
3265io_setstrbuf(VALUE *str, long len)
3266{
3267#ifdef _WIN32
3268 if (len > 0)
3269 len = (len + 1) & ~1L; /* round up for wide char */
3270#endif
3271 if (NIL_P(*str)) {
3272 *str = rb_str_new(0, len);
3273 return TRUE;
3274 }
3275 else {
3276 VALUE s = StringValue(*str);
3277 rb_str_modify(s);
3278
3279 long clen = RSTRING_LEN(s);
3280 if (clen >= len) {
3281 return FALSE;
3282 }
3283 len -= clen;
3284 }
3285 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3286 rb_str_modify_expand(*str, len);
3287 }
3288 return FALSE;
3289}
3290
3291#define MAX_REALLOC_GAP 4096
3292static void
3293io_shrink_read_string(VALUE str, long n)
3294{
3295 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3296 rb_str_resize(str, n);
3297 }
3298}
3299
3300static void
3301io_set_read_length(VALUE str, long n, int shrinkable)
3302{
3303 if (RSTRING_LEN(str) != n) {
3304 rb_str_modify(str);
3305 rb_str_set_len(str, n);
3306 if (shrinkable) io_shrink_read_string(str, n);
3307 }
3308}
3309
3310static VALUE
3311read_all(rb_io_t *fptr, long siz, VALUE str)
3312{
3313 long bytes;
3314 long n;
3315 long pos;
3316 rb_encoding *enc;
3317 int cr;
3318 int shrinkable;
3319
3320 if (NEED_READCONV(fptr)) {
3321 int first = !NIL_P(str);
3322 SET_BINARY_MODE(fptr);
3323 shrinkable = io_setstrbuf(&str,0);
3324 make_readconv(fptr, 0);
3325 while (1) {
3326 VALUE v;
3327 if (fptr->cbuf.len) {
3328 if (first) rb_str_set_len(str, first = 0);
3329 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3330 }
3331 v = fill_cbuf(fptr, 0);
3332 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3333 if (fptr->cbuf.len) {
3334 if (first) rb_str_set_len(str, first = 0);
3335 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3336 }
3337 rb_exc_raise(v);
3338 }
3339 if (v == MORE_CHAR_FINISHED) {
3340 clear_readconv(fptr);
3341 if (first) rb_str_set_len(str, first = 0);
3342 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3343 return io_enc_str(str, fptr);
3344 }
3345 }
3346 }
3347
3348 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3349 bytes = 0;
3350 pos = 0;
3351
3352 enc = io_read_encoding(fptr);
3353 cr = 0;
3354
3355 if (siz == 0) siz = BUFSIZ;
3356 shrinkable = io_setstrbuf(&str, siz);
3357 for (;;) {
3358 READ_CHECK(fptr);
3359 n = io_fread(str, bytes, siz - bytes, fptr);
3360 if (n == 0 && bytes == 0) {
3361 rb_str_set_len(str, 0);
3362 break;
3363 }
3364 bytes += n;
3365 rb_str_set_len(str, bytes);
3366 if (cr != ENC_CODERANGE_BROKEN)
3367 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3368 if (bytes < siz) break;
3369 siz += BUFSIZ;
3370
3371 size_t capa = rb_str_capacity(str);
3372 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3373 if (capa < BUFSIZ) {
3374 capa = BUFSIZ;
3375 }
3376 else if (capa > IO_MAX_BUFFER_GROWTH) {
3377 capa = IO_MAX_BUFFER_GROWTH;
3378 }
3379 rb_str_modify_expand(str, capa);
3380 }
3381 }
3382 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3383 str = io_enc_str(str, fptr);
3384 ENC_CODERANGE_SET(str, cr);
3385 return str;
3386}
3387
3388void
3389rb_io_set_nonblock(rb_io_t *fptr)
3390{
3391 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3392 rb_sys_fail_path(fptr->pathv);
3393 }
3394}
3395
3396static VALUE
3397io_read_memory_call(VALUE arg)
3398{
3399 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3400
3401 VALUE scheduler = rb_fiber_scheduler_current();
3402 if (scheduler != Qnil) {
3403 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3404
3405 if (!UNDEF_P(result)) {
3406 // This is actually returned as a pseudo-VALUE and later cast to a long:
3407 return (VALUE)rb_fiber_scheduler_io_result_apply(result);
3408 }
3409 }
3410
3411 if (iis->nonblock) {
3412 return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->fd, 0);
3413 }
3414 else {
3415 return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->fd, RB_WAITFD_IN);
3416 }
3417}
3418
3419static long
3420io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3421{
3422 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3423}
3424
3425#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3426
3427static VALUE
3428io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3429{
3430 rb_io_t *fptr;
3431 VALUE length, str;
3432 long n, len;
3433 struct io_internal_read_struct iis;
3434 int shrinkable;
3435
3436 rb_scan_args(argc, argv, "11", &length, &str);
3437
3438 if ((len = NUM2LONG(length)) < 0) {
3439 rb_raise(rb_eArgError, "negative length %ld given", len);
3440 }
3441
3442 shrinkable = io_setstrbuf(&str, len);
3443
3444 GetOpenFile(io, fptr);
3445 rb_io_check_byte_readable(fptr);
3446
3447 if (len == 0) {
3448 io_set_read_length(str, 0, shrinkable);
3449 return str;
3450 }
3451
3452 if (!nonblock)
3453 READ_CHECK(fptr);
3454 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3455 if (n <= 0) {
3456 again:
3457 if (nonblock) {
3458 rb_io_set_nonblock(fptr);
3459 }
3460 io_setstrbuf(&str, len);
3461 iis.th = rb_thread_current();
3462 iis.fptr = fptr;
3463 iis.nonblock = nonblock;
3464 iis.fd = fptr->fd;
3465 iis.buf = RSTRING_PTR(str);
3466 iis.capa = len;
3467 iis.timeout = NULL;
3468 n = io_read_memory_locktmp(str, &iis);
3469 if (n < 0) {
3470 int e = errno;
3471 if (!nonblock && fptr_wait_readable(fptr))
3472 goto again;
3473 if (nonblock && (io_again_p(e))) {
3474 if (no_exception)
3475 return sym_wait_readable;
3476 else
3477 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3478 e, "read would block");
3479 }
3480 rb_syserr_fail_path(e, fptr->pathv);
3481 }
3482 }
3483 io_set_read_length(str, n, shrinkable);
3484
3485 if (n == 0)
3486 return Qnil;
3487 else
3488 return str;
3489}
3490
3491/*
3492 * call-seq:
3493 * readpartial(maxlen) -> string
3494 * readpartial(maxlen, out_string) -> out_string
3495 *
3496 * Reads up to +maxlen+ bytes from the stream;
3497 * returns a string (either a new string or the given +out_string+).
3498 * Its encoding is:
3499 *
3500 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3501 * - ASCII-8BIT, otherwise.
3502 *
3503 * - Contains +maxlen+ bytes from the stream, if available.
3504 * - Otherwise contains all available bytes, if any available.
3505 * - Otherwise is an empty string.
3506 *
3507 * With the single non-negative integer argument +maxlen+ given,
3508 * returns a new string:
3509 *
3510 * f = File.new('t.txt')
3511 * f.readpartial(20) # => "First line\nSecond l"
3512 * f.readpartial(20) # => "ine\n\nFourth line\n"
3513 * f.readpartial(20) # => "Fifth line\n"
3514 * f.readpartial(20) # Raises EOFError.
3515 * f.close
3516 *
3517 * With both argument +maxlen+ and string argument +out_string+ given,
3518 * returns modified +out_string+:
3519 *
3520 * f = File.new('t.txt')
3521 * s = 'foo'
3522 * f.readpartial(20, s) # => "First line\nSecond l"
3523 * s = 'bar'
3524 * f.readpartial(0, s) # => ""
3525 * f.close
3526 *
3527 * This method is useful for a stream such as a pipe, a socket, or a tty.
3528 * It blocks only when no data is immediately available.
3529 * This means that it blocks only when _all_ of the following are true:
3530 *
3531 * - The byte buffer in the stream is empty.
3532 * - The content of the stream is empty.
3533 * - The stream is not at EOF.
3534 *
3535 * When blocked, the method waits for either more data or EOF on the stream:
3536 *
3537 * - If more data is read, the method returns the data.
3538 * - If EOF is reached, the method raises EOFError.
3539 *
3540 * When not blocked, the method responds immediately:
3541 *
3542 * - Returns data from the buffer if there is any.
3543 * - Otherwise returns data from the stream if there is any.
3544 * - Otherwise raises EOFError if the stream has reached EOF.
3545 *
3546 * Note that this method is similar to sysread. The differences are:
3547 *
3548 * - If the byte buffer is not empty, read from the byte buffer
3549 * instead of "sysread for buffered IO (IOError)".
3550 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3551 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3552 * readpartial retries the system call.
3553 *
3554 * The latter means that readpartial is non-blocking-flag insensitive.
3555 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3556 * if the fd is blocking mode.
3557 *
3558 * Examples:
3559 *
3560 * # # Returned Buffer Content Pipe Content
3561 * r, w = IO.pipe #
3562 * w << 'abc' # "" "abc".
3563 * r.readpartial(4096) # => "abc" "" ""
3564 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3565 *
3566 * # # Returned Buffer Content Pipe Content
3567 * r, w = IO.pipe #
3568 * w << 'abc' # "" "abc"
3569 * w.close # "" "abc" EOF
3570 * r.readpartial(4096) # => "abc" "" EOF
3571 * r.readpartial(4096) # raises EOFError
3572 *
3573 * # # Returned Buffer Content Pipe Content
3574 * r, w = IO.pipe #
3575 * w << "abc\ndef\n" # "" "abc\ndef\n"
3576 * r.gets # => "abc\n" "def\n" ""
3577 * w << "ghi\n" # "def\n" "ghi\n"
3578 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3579 * r.readpartial(4096) # => "ghi\n" "" ""
3580 *
3581 */
3582
3583static VALUE
3584io_readpartial(int argc, VALUE *argv, VALUE io)
3585{
3586 VALUE ret;
3587
3588 ret = io_getpartial(argc, argv, io, Qnil, 0);
3589 if (NIL_P(ret))
3590 rb_eof_error();
3591 return ret;
3592}
3593
3594static VALUE
3595io_nonblock_eof(int no_exception)
3596{
3597 if (!no_exception) {
3598 rb_eof_error();
3599 }
3600 return Qnil;
3601}
3602
3603/* :nodoc: */
3604static VALUE
3605io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3606{
3607 rb_io_t *fptr;
3608 long n, len;
3609 struct io_internal_read_struct iis;
3610 int shrinkable;
3611
3612 if ((len = NUM2LONG(length)) < 0) {
3613 rb_raise(rb_eArgError, "negative length %ld given", len);
3614 }
3615
3616 shrinkable = io_setstrbuf(&str, len);
3617 rb_bool_expected(ex, "exception", TRUE);
3618
3619 GetOpenFile(io, fptr);
3620 rb_io_check_byte_readable(fptr);
3621
3622 if (len == 0) {
3623 io_set_read_length(str, 0, shrinkable);
3624 return str;
3625 }
3626
3627 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3628 if (n <= 0) {
3629 rb_fd_set_nonblock(fptr->fd);
3630 shrinkable |= io_setstrbuf(&str, len);
3631 iis.fptr = fptr;
3632 iis.nonblock = 1;
3633 iis.fd = fptr->fd;
3634 iis.buf = RSTRING_PTR(str);
3635 iis.capa = len;
3636 iis.timeout = NULL;
3637 n = io_read_memory_locktmp(str, &iis);
3638 if (n < 0) {
3639 int e = errno;
3640 if (io_again_p(e)) {
3641 if (!ex) return sym_wait_readable;
3642 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3643 e, "read would block");
3644 }
3645 rb_syserr_fail_path(e, fptr->pathv);
3646 }
3647 }
3648 io_set_read_length(str, n, shrinkable);
3649
3650 if (n == 0) {
3651 if (!ex) return Qnil;
3652 rb_eof_error();
3653 }
3654
3655 return str;
3656}
3657
3658/* :nodoc: */
3659static VALUE
3660io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3661{
3662 rb_io_t *fptr;
3663 long n;
3664
3665 if (!RB_TYPE_P(str, T_STRING))
3666 str = rb_obj_as_string(str);
3667 rb_bool_expected(ex, "exception", TRUE);
3668
3669 io = GetWriteIO(io);
3670 GetOpenFile(io, fptr);
3671 rb_io_check_writable(fptr);
3672
3673 if (io_fflush(fptr) < 0)
3674 rb_sys_fail_on_write(fptr);
3675
3676 rb_fd_set_nonblock(fptr->fd);
3677 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3678 RB_GC_GUARD(str);
3679
3680 if (n < 0) {
3681 int e = errno;
3682 if (io_again_p(e)) {
3683 if (!ex) {
3684 return sym_wait_writable;
3685 }
3686 else {
3687 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3688 }
3689 }
3690 rb_syserr_fail_path(e, fptr->pathv);
3691 }
3692
3693 return LONG2FIX(n);
3694}
3695
3696/*
3697 * call-seq:
3698 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3699 *
3700 * Reads bytes from the stream; the stream must be opened for reading
3701 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3702 *
3703 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3704 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3705 *
3706 * Returns a string (either a new string or the given +out_string+)
3707 * containing the bytes read.
3708 * The encoding of the string depends on both +maxLen+ and +out_string+:
3709 *
3710 * - +maxlen+ is +nil+: uses internal encoding of +self+
3711 * (regardless of whether +out_string+ was given).
3712 * - +maxlen+ not +nil+:
3713 *
3714 * - +out_string+ given: encoding of +out_string+ not modified.
3715 * - +out_string+ not given: ASCII-8BIT is used.
3716 *
3717 * <b>Without Argument +out_string+</b>
3718 *
3719 * When argument +out_string+ is omitted,
3720 * the returned value is a new string:
3721 *
3722 * f = File.new('t.txt')
3723 * f.read
3724 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3725 * f.rewind
3726 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3727 * f.read(30) # => "rth line\r\nFifth line\r\n"
3728 * f.read(30) # => nil
3729 * f.close
3730 *
3731 * If +maxlen+ is zero, returns an empty string.
3732 *
3733 * <b> With Argument +out_string+</b>
3734 *
3735 * When argument +out_string+ is given,
3736 * the returned value is +out_string+, whose content is replaced:
3737 *
3738 * f = File.new('t.txt')
3739 * s = 'foo' # => "foo"
3740 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3741 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3742 * f.rewind
3743 * s = 'bar'
3744 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3745 * s # => "First line\r\nSecond line\r\n\r\nFou"
3746 * s = 'baz'
3747 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3748 * s # => "rth line\r\nFifth line\r\n"
3749 * s = 'bat'
3750 * f.read(30, s) # => nil
3751 * s # => ""
3752 * f.close
3753 *
3754 * Note that this method behaves like the fread() function in C.
3755 * This means it retries to invoke read(2) system calls to read data
3756 * with the specified maxlen (or until EOF).
3757 *
3758 * This behavior is preserved even if the stream is in non-blocking mode.
3759 * (This method is non-blocking-flag insensitive as other methods.)
3760 *
3761 * If you need the behavior like a single read(2) system call,
3762 * consider #readpartial, #read_nonblock, and #sysread.
3763 *
3764 * Related: IO#write.
3765 */
3766
3767static VALUE
3768io_read(int argc, VALUE *argv, VALUE io)
3769{
3770 rb_io_t *fptr;
3771 long n, len;
3772 VALUE length, str;
3773 int shrinkable;
3774#if RUBY_CRLF_ENVIRONMENT
3775 int previous_mode;
3776#endif
3777
3778 rb_scan_args(argc, argv, "02", &length, &str);
3779
3780 if (NIL_P(length)) {
3781 GetOpenFile(io, fptr);
3782 rb_io_check_char_readable(fptr);
3783 return read_all(fptr, remain_size(fptr), str);
3784 }
3785 len = NUM2LONG(length);
3786 if (len < 0) {
3787 rb_raise(rb_eArgError, "negative length %ld given", len);
3788 }
3789
3790 shrinkable = io_setstrbuf(&str,len);
3791
3792 GetOpenFile(io, fptr);
3793 rb_io_check_byte_readable(fptr);
3794 if (len == 0) {
3795 io_set_read_length(str, 0, shrinkable);
3796 return str;
3797 }
3798
3799 READ_CHECK(fptr);
3800#if RUBY_CRLF_ENVIRONMENT
3801 previous_mode = set_binary_mode_with_seek_cur(fptr);
3802#endif
3803 n = io_fread(str, 0, len, fptr);
3804 io_set_read_length(str, n, shrinkable);
3805#if RUBY_CRLF_ENVIRONMENT
3806 if (previous_mode == O_TEXT) {
3807 setmode(fptr->fd, O_TEXT);
3808 }
3809#endif
3810 if (n == 0) return Qnil;
3811
3812 return str;
3813}
3814
3815static void
3816rscheck(const char *rsptr, long rslen, VALUE rs)
3817{
3818 if (!rs) return;
3819 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3820 rb_raise(rb_eRuntimeError, "rs modified");
3821}
3822
3823static const char *
3824search_delim(const char *p, long len, int delim, rb_encoding *enc)
3825{
3826 if (rb_enc_mbminlen(enc) == 1) {
3827 p = memchr(p, delim, len);
3828 if (p) return p + 1;
3829 }
3830 else {
3831 const char *end = p + len;
3832 while (p < end) {
3833 int r = rb_enc_precise_mbclen(p, end, enc);
3834 if (!MBCLEN_CHARFOUND_P(r)) {
3835 p += rb_enc_mbminlen(enc);
3836 continue;
3837 }
3838 int n = MBCLEN_CHARFOUND_LEN(r);
3839 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3840 return p + n;
3841 }
3842 p += n;
3843 }
3844 }
3845 return NULL;
3846}
3847
3848static int
3849appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3850{
3851 VALUE str = *strp;
3852 long limit = *lp;
3853
3854 if (NEED_READCONV(fptr)) {
3855 SET_BINARY_MODE(fptr);
3856 make_readconv(fptr, 0);
3857 do {
3858 const char *p, *e;
3859 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3860 if (searchlen) {
3861 p = READ_CHAR_PENDING_PTR(fptr);
3862 if (0 < limit && limit < searchlen)
3863 searchlen = (int)limit;
3864 e = search_delim(p, searchlen, delim, enc);
3865 if (e) {
3866 int len = (int)(e-p);
3867 if (NIL_P(str))
3868 *strp = str = rb_str_new(p, len);
3869 else
3870 rb_str_buf_cat(str, p, len);
3871 fptr->cbuf.off += len;
3872 fptr->cbuf.len -= len;
3873 limit -= len;
3874 *lp = limit;
3875 return delim;
3876 }
3877
3878 if (NIL_P(str))
3879 *strp = str = rb_str_new(p, searchlen);
3880 else
3881 rb_str_buf_cat(str, p, searchlen);
3882 fptr->cbuf.off += searchlen;
3883 fptr->cbuf.len -= searchlen;
3884 limit -= searchlen;
3885
3886 if (limit == 0) {
3887 *lp = limit;
3888 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3889 }
3890 }
3891 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3892 clear_readconv(fptr);
3893 *lp = limit;
3894 return EOF;
3895 }
3896
3897 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3898 do {
3899 long pending = READ_DATA_PENDING_COUNT(fptr);
3900 if (pending > 0) {
3901 const char *p = READ_DATA_PENDING_PTR(fptr);
3902 const char *e;
3903 long last;
3904
3905 if (limit > 0 && pending > limit) pending = limit;
3906 e = search_delim(p, pending, delim, enc);
3907 if (e) pending = e - p;
3908 if (!NIL_P(str)) {
3909 last = RSTRING_LEN(str);
3910 rb_str_resize(str, last + pending);
3911 }
3912 else {
3913 last = 0;
3914 *strp = str = rb_str_buf_new(pending);
3915 rb_str_set_len(str, pending);
3916 }
3917 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3918 limit -= pending;
3919 *lp = limit;
3920 if (e) return delim;
3921 if (limit == 0)
3922 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3923 }
3924 READ_CHECK(fptr);
3925 } while (io_fillbuf(fptr) >= 0);
3926 *lp = limit;
3927 return EOF;
3928}
3929
3930static inline int
3931swallow(rb_io_t *fptr, int term)
3932{
3933 if (NEED_READCONV(fptr)) {
3934 rb_encoding *enc = io_read_encoding(fptr);
3935 int needconv = rb_enc_mbminlen(enc) != 1;
3936 SET_BINARY_MODE(fptr);
3937 make_readconv(fptr, 0);
3938 do {
3939 size_t cnt;
3940 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3941 const char *p = READ_CHAR_PENDING_PTR(fptr);
3942 int i;
3943 if (!needconv) {
3944 if (*p != term) return TRUE;
3945 i = (int)cnt;
3946 while (--i && *++p == term);
3947 }
3948 else {
3949 const char *e = p + cnt;
3950 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3951 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3952 i = (int)(e - p);
3953 }
3954 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3955 }
3956 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3957 return FALSE;
3958 }
3959
3960 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3961 do {
3962 size_t cnt;
3963 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3964 char buf[1024];
3965 const char *p = READ_DATA_PENDING_PTR(fptr);
3966 int i;
3967 if (cnt > sizeof buf) cnt = sizeof buf;
3968 if (*p != term) return TRUE;
3969 i = (int)cnt;
3970 while (--i && *++p == term);
3971 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
3972 rb_sys_fail_path(fptr->pathv);
3973 }
3974 READ_CHECK(fptr);
3975 } while (io_fillbuf(fptr) == 0);
3976 return FALSE;
3977}
3978
3979static VALUE
3980rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
3981{
3982 VALUE str = Qnil;
3983 int len = 0;
3984 long pos = 0;
3985 int cr = 0;
3986
3987 do {
3988 int pending = READ_DATA_PENDING_COUNT(fptr);
3989
3990 if (pending > 0) {
3991 const char *p = READ_DATA_PENDING_PTR(fptr);
3992 const char *e;
3993 int chomplen = 0;
3994
3995 e = memchr(p, '\n', pending);
3996 if (e) {
3997 pending = (int)(e - p + 1);
3998 if (chomp) {
3999 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4000 }
4001 }
4002 if (NIL_P(str)) {
4003 str = rb_str_new(p, pending - chomplen);
4004 fptr->rbuf.off += pending;
4005 fptr->rbuf.len -= pending;
4006 }
4007 else {
4008 rb_str_resize(str, len + pending - chomplen);
4009 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4010 fptr->rbuf.off += chomplen;
4011 fptr->rbuf.len -= chomplen;
4012 if (pending == 1 && chomplen == 1 && len > 0) {
4013 if (RSTRING_PTR(str)[len-1] == '\r') {
4014 rb_str_resize(str, --len);
4015 break;
4016 }
4017 }
4018 }
4019 len += pending - chomplen;
4020 if (cr != ENC_CODERANGE_BROKEN)
4021 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4022 if (e) break;
4023 }
4024 READ_CHECK(fptr);
4025 } while (io_fillbuf(fptr) >= 0);
4026 if (NIL_P(str)) return Qnil;
4027
4028 str = io_enc_str(str, fptr);
4029 ENC_CODERANGE_SET(str, cr);
4030 fptr->lineno++;
4031
4032 return str;
4033}
4034
4035 struct getline_arg {
4036 VALUE io;
4037 VALUE rs;
4038 long limit;
4039 unsigned int chomp: 1;
4040};
4041
4042static void
4043extract_getline_opts(VALUE opts, struct getline_arg *args)
4044{
4045 int chomp = FALSE;
4046 if (!NIL_P(opts)) {
4047 static ID kwds[1];
4048 VALUE vchomp;
4049 if (!kwds[0]) {
4050 kwds[0] = rb_intern_const("chomp");
4051 }
4052 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4053 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4054 }
4055 args->chomp = chomp;
4056}
4057
4058static void
4059extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4060{
4061 VALUE rs = rb_rs, lim = Qnil;
4062
4063 if (argc == 1) {
4064 VALUE tmp = Qnil;
4065
4066 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4067 rs = tmp;
4068 }
4069 else {
4070 lim = argv[0];
4071 }
4072 }
4073 else if (2 <= argc) {
4074 rs = argv[0], lim = argv[1];
4075 if (!NIL_P(rs))
4076 StringValue(rs);
4077 }
4078 args->rs = rs;
4079 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4080}
4081
4082static void
4083check_getline_args(VALUE *rsp, long *limit, VALUE io)
4084{
4085 rb_io_t *fptr;
4086 VALUE rs = *rsp;
4087
4088 if (!NIL_P(rs)) {
4089 rb_encoding *enc_rs, *enc_io;
4090
4091 GetOpenFile(io, fptr);
4092 enc_rs = rb_enc_get(rs);
4093 enc_io = io_read_encoding(fptr);
4094 if (enc_io != enc_rs &&
4095 (!is_ascii_string(rs) ||
4096 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4097 if (rs == rb_default_rs) {
4098 rs = rb_enc_str_new(0, 0, enc_io);
4099 rb_str_buf_cat_ascii(rs, "\n");
4100 *rsp = rs;
4101 }
4102 else {
4103 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4104 rb_enc_name(enc_io),
4105 rb_enc_name(enc_rs));
4106 }
4107 }
4108 }
4109}
4110
4111static void
4112prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4113{
4114 VALUE opts;
4115 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4116 extract_getline_args(argc, argv, args);
4117 extract_getline_opts(opts, args);
4118 check_getline_args(&args->rs, &args->limit, io);
4119}
4120
4121static VALUE
4122rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4123{
4124 VALUE str = Qnil;
4125 int nolimit = 0;
4126 rb_encoding *enc;
4127
4128 rb_io_check_char_readable(fptr);
4129 if (NIL_P(rs) && limit < 0) {
4130 str = read_all(fptr, 0, Qnil);
4131 if (RSTRING_LEN(str) == 0) return Qnil;
4132 }
4133 else if (limit == 0) {
4134 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4135 }
4136 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4137 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4138 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4139 return rb_io_getline_fast(fptr, enc, chomp);
4140 }
4141 else {
4142 int c, newline = -1;
4143 const char *rsptr = 0;
4144 long rslen = 0;
4145 int rspara = 0;
4146 int extra_limit = 16;
4147 int chomp_cr = chomp;
4148
4149 SET_BINARY_MODE(fptr);
4150 enc = io_read_encoding(fptr);
4151
4152 if (!NIL_P(rs)) {
4153 rslen = RSTRING_LEN(rs);
4154 if (rslen == 0) {
4155 rsptr = "\n\n";
4156 rslen = 2;
4157 rspara = 1;
4158 swallow(fptr, '\n');
4159 rs = 0;
4160 if (!rb_enc_asciicompat(enc)) {
4161 rs = rb_usascii_str_new(rsptr, rslen);
4162 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
4163 OBJ_FREEZE(rs);
4164 rsptr = RSTRING_PTR(rs);
4165 rslen = RSTRING_LEN(rs);
4166 }
4167 newline = '\n';
4168 }
4169 else if (rb_enc_mbminlen(enc) == 1) {
4170 rsptr = RSTRING_PTR(rs);
4171 newline = (unsigned char)rsptr[rslen - 1];
4172 }
4173 else {
4174 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
4175 rsptr = RSTRING_PTR(rs);
4176 const char *e = rsptr + rslen;
4177 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4178 int n;
4179 newline = rb_enc_codepoint_len(last, e, &n, enc);
4180 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4181 }
4182 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4183 }
4184
4185 /* MS - Optimization */
4186 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4187 const char *s, *p, *pp, *e;
4188
4189 if (c == newline) {
4190 if (RSTRING_LEN(str) < rslen) continue;
4191 s = RSTRING_PTR(str);
4192 e = RSTRING_END(str);
4193 p = e - rslen;
4194 if (!at_char_boundary(s, p, e, enc)) continue;
4195 if (!rspara) rscheck(rsptr, rslen, rs);
4196 if (memcmp(p, rsptr, rslen) == 0) {
4197 if (chomp) {
4198 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4199 rb_str_set_len(str, p - s);
4200 }
4201 break;
4202 }
4203 }
4204 if (limit == 0) {
4205 s = RSTRING_PTR(str);
4206 p = RSTRING_END(str);
4207 pp = rb_enc_prev_char(s, p, p, enc);
4208 if (extra_limit && pp &&
4209 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4210 /* relax the limit while incomplete character.
4211 * extra_limit limits the relax length */
4212 limit = 1;
4213 extra_limit--;
4214 }
4215 else {
4216 nolimit = 1;
4217 break;
4218 }
4219 }
4220 }
4221
4222 if (rspara && c != EOF)
4223 swallow(fptr, '\n');
4224 if (!NIL_P(str))
4225 str = io_enc_str(str, fptr);
4226 }
4227
4228 if (!NIL_P(str) && !nolimit) {
4229 fptr->lineno++;
4230 }
4231
4232 return str;
4233}
4234
4235static VALUE
4236rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4237{
4238 rb_io_t *fptr;
4239 int old_lineno, new_lineno;
4240 VALUE str;
4241
4242 GetOpenFile(io, fptr);
4243 old_lineno = fptr->lineno;
4244 str = rb_io_getline_0(rs, limit, chomp, fptr);
4245 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4246 if (io == ARGF.current_file) {
4247 ARGF.lineno += new_lineno - old_lineno;
4248 ARGF.last_lineno = ARGF.lineno;
4249 }
4250 else {
4251 ARGF.last_lineno = new_lineno;
4252 }
4253 }
4254
4255 return str;
4256}
4257
4258static VALUE
4259rb_io_getline(int argc, VALUE *argv, VALUE io)
4260{
4261 struct getline_arg args;
4262
4263 prepare_getline_args(argc, argv, &args, io);
4264 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4265}
4266
4267 VALUE
4268rb_io_gets(VALUE io)
4269{
4270 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4271}
4272
4273 VALUE
4274rb_io_gets_internal(VALUE io)
4275{
4276 rb_io_t *fptr;
4277 GetOpenFile(io, fptr);
4278 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4279}
4280
4281/*
4282 * call-seq:
4283 * gets(sep = $/, chomp: false) -> string or nil
4284 * gets(limit, chomp: false) -> string or nil
4285 * gets(sep, limit, chomp: false) -> string or nil
4286 *
4287 * Reads and returns a line from the stream;
4288 * assigns the return value to <tt>$_</tt>.
4289 * See {Line IO}[rdoc-ref:IO@Line+IO].
4290 *
4291 * With no arguments given, returns the next line
4292 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4293 *
4294 * f = File.open('t.txt')
4295 * f.gets # => "First line\n"
4296 * $_ # => "First line\n"
4297 * f.gets # => "\n"
4298 * f.gets # => "Fourth line\n"
4299 * f.gets # => "Fifth line\n"
4300 * f.gets # => nil
4301 * f.close
4302 *
4303 * With only string argument +sep+ given,
4304 * returns the next line as determined by line separator +sep+,
4305 * or +nil+ if none;
4306 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4307 *
4308 * f = File.new('t.txt')
4309 * f.gets('l') # => "First l"
4310 * f.gets('li') # => "ine\nSecond li"
4311 * f.gets('lin') # => "ne\n\nFourth lin"
4312 * f.gets # => "e\n"
4313 * f.close
4314 *
4315 * The two special values for +sep+ are honored:
4316 *
4317 * f = File.new('t.txt')
4318 * # Get all.
4319 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4320 * f.rewind
4321 * # Get paragraph (up to two line separators).
4322 * f.gets('') # => "First line\nSecond line\n\n"
4323 * f.close
4324 *
4325 * With only integer argument +limit+ given,
4326 * limits the number of bytes in the line;
4327 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4328 *
4329 * # No more than one line.
4330 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4331 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4332 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4333 *
4334 * With arguments +sep+ and +limit+ given,
4335 * combines the two behaviors:
4336 *
4337 * - Returns the next line as determined by line separator +sep+,
4338 * or +nil+ if none.
4339 * - But returns no more bytes than are allowed by the limit.
4340 *
4341 * Optional keyword argument +chomp+ specifies whether line separators
4342 * are to be omitted:
4343 *
4344 * f = File.open('t.txt')
4345 * # Chomp the lines.
4346 * f.gets(chomp: true) # => "First line"
4347 * f.gets(chomp: true) # => "Second line"
4348 * f.gets(chomp: true) # => ""
4349 * f.gets(chomp: true) # => "Fourth line"
4350 * f.gets(chomp: true) # => "Fifth line"
4351 * f.gets(chomp: true) # => nil
4352 * f.close
4353 *
4354 */
4355
4356static VALUE
4357rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4358{
4359 VALUE str;
4360
4361 str = rb_io_getline(argc, argv, io);
4362 rb_lastline_set(str);
4363
4364 return str;
4365}
4366
4367/*
4368 * call-seq:
4369 * lineno -> integer
4370 *
4371 * Returns the current line number for the stream;
4372 * see {Line Number}[rdoc-ref:IO@Line+Number].
4373 *
4374 */
4375
4376static VALUE
4377rb_io_lineno(VALUE io)
4378{
4379 rb_io_t *fptr;
4380
4381 GetOpenFile(io, fptr);
4382 rb_io_check_char_readable(fptr);
4383 return INT2NUM(fptr->lineno);
4384}
4385
4386/*
4387 * call-seq:
4388 * lineno = integer -> integer
4389 *
4390 * Sets and returns the line number for the stream;
4391 * see {Line Number}[rdoc-ref:IO@Line+Number].
4392 *
4393 */
4394
4395static VALUE
4396rb_io_set_lineno(VALUE io, VALUE lineno)
4397{
4398 rb_io_t *fptr;
4399
4400 GetOpenFile(io, fptr);
4401 rb_io_check_char_readable(fptr);
4402 fptr->lineno = NUM2INT(lineno);
4403 return lineno;
4404}
4405
4406/* :nodoc: */
4407static VALUE
4408io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4409{
4410 long limit = -1;
4411 if (NIL_P(lim)) {
4412 VALUE tmp = Qnil;
4413 // If sep is specified, but it's not a string and not nil, then assume
4414 // it's the limit (it should be an integer)
4415 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4416 // If the user has specified a non-nil / non-string value
4417 // for the separator, we assume it's the limit and set the
4418 // separator to default: rb_rs.
4419 lim = sep;
4420 limit = NUM2LONG(lim);
4421 sep = rb_rs;
4422 }
4423 else {
4424 sep = tmp;
4425 }
4426 }
4427 else {
4428 if (!NIL_P(sep)) StringValue(sep);
4429 limit = NUM2LONG(lim);
4430 }
4431
4432 check_getline_args(&sep, &limit, io);
4433
4434 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4435 rb_lastline_set_up(line, 1);
4436
4437 if (NIL_P(line)) {
4438 rb_eof_error();
4439 }
4440 return line;
4441}
4442
4443static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4444
4445/*
4446 * call-seq:
4447 * readlines(sep = $/, chomp: false) -> array
4448 * readlines(limit, chomp: false) -> array
4449 * readlines(sep, limit, chomp: false) -> array
4450 *
4451 * Reads and returns all remaining line from the stream;
4452 * does not modify <tt>$_</tt>.
4453 * See {Line IO}[rdoc-ref:IO@Line+IO].
4454 *
4455 * With no arguments given, returns lines
4456 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4457 *
4458 * f = File.new('t.txt')
4459 * f.readlines
4460 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4461 * f.readlines # => []
4462 * f.close
4463 *
4464 * With only string argument +sep+ given,
4465 * returns lines as determined by line separator +sep+,
4466 * or +nil+ if none;
4467 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4468 *
4469 * f = File.new('t.txt')
4470 * f.readlines('li')
4471 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4472 * f.close
4473 *
4474 * The two special values for +sep+ are honored:
4475 *
4476 * f = File.new('t.txt')
4477 * # Get all into one string.
4478 * f.readlines(nil)
4479 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4480 * # Get paragraphs (up to two line separators).
4481 * f.rewind
4482 * f.readlines('')
4483 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4484 * f.close
4485 *
4486 * With only integer argument +limit+ given,
4487 * limits the number of bytes in each line;
4488 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4489 *
4490 * f = File.new('t.txt')
4491 * f.readlines(8)
4492 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4493 * f.close
4494 *
4495 * With arguments +sep+ and +limit+ given,
4496 * combines the two behaviors:
4497 *
4498 * - Returns lines as determined by line separator +sep+.
4499 * - But returns no more bytes in a line than are allowed by the limit.
4500 *
4501 * Optional keyword argument +chomp+ specifies whether line separators
4502 * are to be omitted:
4503 *
4504 * f = File.new('t.txt')
4505 * f.readlines(chomp: true)
4506 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4507 * f.close
4508 *
4509 */
4510
4511static VALUE
4512rb_io_readlines(int argc, VALUE *argv, VALUE io)
4513{
4514 struct getline_arg args;
4515
4516 prepare_getline_args(argc, argv, &args, io);
4517 return io_readlines(&args, io);
4518}
4519
4520static VALUE
4521io_readlines(const struct getline_arg *arg, VALUE io)
4522{
4523 VALUE line, ary;
4524
4525 if (arg->limit == 0)
4526 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4527 ary = rb_ary_new();
4528 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4529 rb_ary_push(ary, line);
4530 }
4531 return ary;
4532}
4533
4534/*
4535 * call-seq:
4536 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4537 * each_line(limit, chomp: false) {|line| ... } -> self
4538 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4539 * each_line -> enumerator
4540 *
4541 * Calls the block with each remaining line read from the stream;
4542 * returns +self+.
4543 * Does nothing if already at end-of-stream;
4544 * See {Line IO}[rdoc-ref:IO@Line+IO].
4545 *
4546 * With no arguments given, reads lines
4547 * as determined by line separator <tt>$/</tt>:
4548 *
4549 * f = File.new('t.txt')
4550 * f.each_line {|line| p line }
4551 * f.each_line {|line| fail 'Cannot happen' }
4552 * f.close
4553 *
4554 * Output:
4555 *
4556 * "First line\n"
4557 * "Second line\n"
4558 * "\n"
4559 * "Fourth line\n"
4560 * "Fifth line\n"
4561 *
4562 * With only string argument +sep+ given,
4563 * reads lines as determined by line separator +sep+;
4564 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4565 *
4566 * f = File.new('t.txt')
4567 * f.each_line('li') {|line| p line }
4568 * f.close
4569 *
4570 * Output:
4571 *
4572 * "First li"
4573 * "ne\nSecond li"
4574 * "ne\n\nFourth li"
4575 * "ne\nFifth li"
4576 * "ne\n"
4577 *
4578 * The two special values for +sep+ are honored:
4579 *
4580 * f = File.new('t.txt')
4581 * # Get all into one string.
4582 * f.each_line(nil) {|line| p line }
4583 * f.close
4584 *
4585 * Output:
4586 *
4587 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4588 *
4589 * f.rewind
4590 * # Get paragraphs (up to two line separators).
4591 * f.each_line('') {|line| p line }
4592 *
4593 * Output:
4594 *
4595 * "First line\nSecond line\n\n"
4596 * "Fourth line\nFifth line\n"
4597 *
4598 * With only integer argument +limit+ given,
4599 * limits the number of bytes in each line;
4600 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4601 *
4602 * f = File.new('t.txt')
4603 * f.each_line(8) {|line| p line }
4604 * f.close
4605 *
4606 * Output:
4607 *
4608 * "First li"
4609 * "ne\n"
4610 * "Second l"
4611 * "ine\n"
4612 * "\n"
4613 * "Fourth l"
4614 * "ine\n"
4615 * "Fifth li"
4616 * "ne\n"
4617 *
4618 * With arguments +sep+ and +limit+ given,
4619 * combines the two behaviors:
4620 *
4621 * - Calls with the next line as determined by line separator +sep+.
4622 * - But returns no more bytes than are allowed by the limit.
4623 *
4624 * Optional keyword argument +chomp+ specifies whether line separators
4625 * are to be omitted:
4626 *
4627 * f = File.new('t.txt')
4628 * f.each_line(chomp: true) {|line| p line }
4629 * f.close
4630 *
4631 * Output:
4632 *
4633 * "First line"
4634 * "Second line"
4635 * ""
4636 * "Fourth line"
4637 * "Fifth line"
4638 *
4639 * Returns an Enumerator if no block is given.
4640 */
4641
4642static VALUE
4643rb_io_each_line(int argc, VALUE *argv, VALUE io)
4644{
4645 VALUE str;
4646 struct getline_arg args;
4647
4648 RETURN_ENUMERATOR(io, argc, argv);
4649 prepare_getline_args(argc, argv, &args, io);
4650 if (args.limit == 0)
4651 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4652 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4653 rb_yield(str);
4654 }
4655 return io;
4656}
4657
4658/*
4659 * call-seq:
4660 * each_byte {|byte| ... } -> self
4661 * each_byte -> enumerator
4662 *
4663 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4664 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4665 *
4666 * f = File.new('t.rus')
4667 * a = []
4668 * f.each_byte {|b| a << b }
4669 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4670 * f.close
4671 *
4672 * Returns an Enumerator if no block is given.
4673 *
4674 * Related: IO#each_char, IO#each_codepoint.
4675 *
4676 */
4677
4678static VALUE
4679rb_io_each_byte(VALUE io)
4680{
4681 rb_io_t *fptr;
4682
4683 RETURN_ENUMERATOR(io, 0, 0);
4684 GetOpenFile(io, fptr);
4685
4686 do {
4687 while (fptr->rbuf.len > 0) {
4688 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4689 fptr->rbuf.len--;
4690 rb_yield(INT2FIX(*p & 0xff));
4691 rb_io_check_byte_readable(fptr);
4692 errno = 0;
4693 }
4694 READ_CHECK(fptr);
4695 } while (io_fillbuf(fptr) >= 0);
4696 return io;
4697}
4698
4699static VALUE
4700io_getc(rb_io_t *fptr, rb_encoding *enc)
4701{
4702 int r, n, cr = 0;
4703 VALUE str;
4704
4705 if (NEED_READCONV(fptr)) {
4706 rb_encoding *read_enc = io_read_encoding(fptr);
4707
4708 str = Qnil;
4709 SET_BINARY_MODE(fptr);
4710 make_readconv(fptr, 0);
4711
4712 while (1) {
4713 if (fptr->cbuf.len) {
4714 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4715 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4716 read_enc);
4717 if (!MBCLEN_NEEDMORE_P(r))
4718 break;
4719 if (fptr->cbuf.len == fptr->cbuf.capa) {
4720 rb_raise(rb_eIOError, "too long character");
4721 }
4722 }
4723
4724 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4725 if (fptr->cbuf.len == 0) {
4726 clear_readconv(fptr);
4727 return Qnil;
4728 }
4729 /* return an unit of an incomplete character just before EOF */
4730 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4731 fptr->cbuf.off += 1;
4732 fptr->cbuf.len -= 1;
4733 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4734 ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
4735 return str;
4736 }
4737 }
4738 if (MBCLEN_INVALID_P(r)) {
4739 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4740 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4741 read_enc);
4742 io_shift_cbuf(fptr, r, &str);
4743 cr = ENC_CODERANGE_BROKEN;
4744 }
4745 else {
4746 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4747 cr = ENC_CODERANGE_VALID;
4748 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4749 ISASCII(RSTRING_PTR(str)[0])) {
4750 cr = ENC_CODERANGE_7BIT;
4751 }
4752 }
4753 str = io_enc_str(str, fptr);
4754 ENC_CODERANGE_SET(str, cr);
4755 return str;
4756 }
4757
4758 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4759 if (io_fillbuf(fptr) < 0) {
4760 return Qnil;
4761 }
4762 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4763 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4764 fptr->rbuf.off += 1;
4765 fptr->rbuf.len -= 1;
4766 cr = ENC_CODERANGE_7BIT;
4767 }
4768 else {
4769 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4770 if (MBCLEN_CHARFOUND_P(r) &&
4771 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4772 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4773 fptr->rbuf.off += n;
4774 fptr->rbuf.len -= n;
4775 cr = ENC_CODERANGE_VALID;
4776 }
4777 else if (MBCLEN_NEEDMORE_P(r)) {
4778 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4779 fptr->rbuf.len = 0;
4780 getc_needmore:
4781 if (io_fillbuf(fptr) != -1) {
4782 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4783 fptr->rbuf.off++;
4784 fptr->rbuf.len--;
4785 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4786 if (MBCLEN_NEEDMORE_P(r)) {
4787 goto getc_needmore;
4788 }
4789 else if (MBCLEN_CHARFOUND_P(r)) {
4790 cr = ENC_CODERANGE_VALID;
4791 }
4792 }
4793 }
4794 else {
4795 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4796 fptr->rbuf.off++;
4797 fptr->rbuf.len--;
4798 }
4799 }
4800 if (!cr) cr = ENC_CODERANGE_BROKEN;
4801 str = io_enc_str(str, fptr);
4802 ENC_CODERANGE_SET(str, cr);
4803 return str;
4804}
4805
4806/*
4807 * call-seq:
4808 * each_char {|c| ... } -> self
4809 * each_char -> enumerator
4810 *
4811 * Calls the given block with each character in the stream; returns +self+.
4812 * See {Character IO}[rdoc-ref:IO@Character+IO].
4813 *
4814 * f = File.new('t.rus')
4815 * a = []
4816 * f.each_char {|c| a << c.ord }
4817 * a # => [1090, 1077, 1089, 1090]
4818 * f.close
4819 *
4820 * Returns an Enumerator if no block is given.
4821 *
4822 * Related: IO#each_byte, IO#each_codepoint.
4823 *
4824 */
4825
4826static VALUE
4827rb_io_each_char(VALUE io)
4828{
4829 rb_io_t *fptr;
4830 rb_encoding *enc;
4831 VALUE c;
4832
4833 RETURN_ENUMERATOR(io, 0, 0);
4834 GetOpenFile(io, fptr);
4835 rb_io_check_char_readable(fptr);
4836
4837 enc = io_input_encoding(fptr);
4838 READ_CHECK(fptr);
4839 while (!NIL_P(c = io_getc(fptr, enc))) {
4840 rb_yield(c);
4841 }
4842 return io;
4843}
4844
4845/*
4846 * call-seq:
4847 * each_codepoint {|c| ... } -> self
4848 * each_codepoint -> enumerator
4849 *
4850 * Calls the given block with each codepoint in the stream; returns +self+:
4851 *
4852 * f = File.new('t.rus')
4853 * a = []
4854 * f.each_codepoint {|c| a << c }
4855 * a # => [1090, 1077, 1089, 1090]
4856 * f.close
4857 *
4858 * Returns an Enumerator if no block is given.
4859 *
4860 * Related: IO#each_byte, IO#each_char.
4861 *
4862 */
4863
4864static VALUE
4865rb_io_each_codepoint(VALUE io)
4866{
4867 rb_io_t *fptr;
4868 rb_encoding *enc;
4869 unsigned int c;
4870 int r, n;
4871
4872 RETURN_ENUMERATOR(io, 0, 0);
4873 GetOpenFile(io, fptr);
4874 rb_io_check_char_readable(fptr);
4875
4876 READ_CHECK(fptr);
4877 if (NEED_READCONV(fptr)) {
4878 SET_BINARY_MODE(fptr);
4879 r = 1; /* no invalid char yet */
4880 for (;;) {
4881 make_readconv(fptr, 0);
4882 for (;;) {
4883 if (fptr->cbuf.len) {
4884 if (fptr->encs.enc)
4885 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4886 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4887 fptr->encs.enc);
4888 else
4889 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4890 if (!MBCLEN_NEEDMORE_P(r))
4891 break;
4892 if (fptr->cbuf.len == fptr->cbuf.capa) {
4893 rb_raise(rb_eIOError, "too long character");
4894 }
4895 }
4896 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4897 clear_readconv(fptr);
4898 if (!MBCLEN_CHARFOUND_P(r)) {
4899 enc = fptr->encs.enc;
4900 goto invalid;
4901 }
4902 return io;
4903 }
4904 }
4905 if (MBCLEN_INVALID_P(r)) {
4906 enc = fptr->encs.enc;
4907 goto invalid;
4908 }
4909 n = MBCLEN_CHARFOUND_LEN(r);
4910 if (fptr->encs.enc) {
4911 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4912 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4913 fptr->encs.enc);
4914 }
4915 else {
4916 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4917 }
4918 fptr->cbuf.off += n;
4919 fptr->cbuf.len -= n;
4920 rb_yield(UINT2NUM(c));
4921 rb_io_check_byte_readable(fptr);
4922 }
4923 }
4924 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4925 enc = io_input_encoding(fptr);
4926 while (io_fillbuf(fptr) >= 0) {
4927 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4928 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4929 if (MBCLEN_CHARFOUND_P(r) &&
4930 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4931 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4932 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4933 fptr->rbuf.off += n;
4934 fptr->rbuf.len -= n;
4935 rb_yield(UINT2NUM(c));
4936 }
4937 else if (MBCLEN_INVALID_P(r)) {
4938 goto invalid;
4939 }
4940 else if (MBCLEN_NEEDMORE_P(r)) {
4941 char cbuf[8], *p = cbuf;
4942 int more = MBCLEN_NEEDMORE_LEN(r);
4943 if (more > numberof(cbuf)) goto invalid;
4944 more += n = fptr->rbuf.len;
4945 if (more > numberof(cbuf)) goto invalid;
4946 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4947 (p += n, (more -= n) > 0)) {
4948 if (io_fillbuf(fptr) < 0) goto invalid;
4949 if ((n = fptr->rbuf.len) > more) n = more;
4950 }
4951 r = rb_enc_precise_mbclen(cbuf, p, enc);
4952 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4953 c = rb_enc_codepoint(cbuf, p, enc);
4954 rb_yield(UINT2NUM(c));
4955 }
4956 else {
4957 continue;
4958 }
4959 rb_io_check_byte_readable(fptr);
4960 }
4961 return io;
4962
4963 invalid:
4964 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4965 UNREACHABLE_RETURN(Qundef);
4966}
4967
4968/*
4969 * call-seq:
4970 * getc -> character or nil
4971 *
4972 * Reads and returns the next 1-character string from the stream;
4973 * returns +nil+ if already at end-of-stream.
4974 * See {Character IO}[rdoc-ref:IO@Character+IO].
4975 *
4976 * f = File.open('t.txt')
4977 * f.getc # => "F"
4978 * f.close
4979 * f = File.open('t.rus')
4980 * f.getc.ord # => 1090
4981 * f.close
4982 *
4983 * Related: IO#readchar (may raise EOFError).
4984 *
4985 */
4986
4987static VALUE
4988rb_io_getc(VALUE io)
4989{
4990 rb_io_t *fptr;
4991 rb_encoding *enc;
4992
4993 GetOpenFile(io, fptr);
4994 rb_io_check_char_readable(fptr);
4995
4996 enc = io_input_encoding(fptr);
4997 READ_CHECK(fptr);
4998 return io_getc(fptr, enc);
4999}
5000
5001/*
5002 * call-seq:
5003 * readchar -> string
5004 *
5005 * Reads and returns the next 1-character string from the stream;
5006 * raises EOFError if already at end-of-stream.
5007 * See {Character IO}[rdoc-ref:IO@Character+IO].
5008 *
5009 * f = File.open('t.txt')
5010 * f.readchar # => "F"
5011 * f.close
5012 * f = File.open('t.rus')
5013 * f.readchar.ord # => 1090
5014 * f.close
5015 *
5016 * Related: IO#getc (will not raise EOFError).
5017 *
5018 */
5019
5020static VALUE
5021rb_io_readchar(VALUE io)
5022{
5023 VALUE c = rb_io_getc(io);
5024
5025 if (NIL_P(c)) {
5026 rb_eof_error();
5027 }
5028 return c;
5029}
5030
5031/*
5032 * call-seq:
5033 * getbyte -> integer or nil
5034 *
5035 * Reads and returns the next byte (in range 0..255) from the stream;
5036 * returns +nil+ if already at end-of-stream.
5037 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5038 *
5039 * f = File.open('t.txt')
5040 * f.getbyte # => 70
5041 * f.close
5042 * f = File.open('t.rus')
5043 * f.getbyte # => 209
5044 * f.close
5045 *
5046 * Related: IO#readbyte (may raise EOFError).
5047 */
5048
5049 VALUE
5050rb_io_getbyte(VALUE io)
5051{
5052 rb_io_t *fptr;
5053 int c;
5054
5055 GetOpenFile(io, fptr);
5056 rb_io_check_byte_readable(fptr);
5057 READ_CHECK(fptr);
5058 VALUE r_stdout = rb_ractor_stdout();
5059 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5060 rb_io_t *ofp;
5061 GetOpenFile(r_stdout, ofp);
5062 if (ofp->mode & FMODE_TTY) {
5063 rb_io_flush(r_stdout);
5064 }
5065 }
5066 if (io_fillbuf(fptr) < 0) {
5067 return Qnil;
5068 }
5069 fptr->rbuf.off++;
5070 fptr->rbuf.len--;
5071 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5072 return INT2FIX(c & 0xff);
5073}
5074
5075/*
5076 * call-seq:
5077 * readbyte -> integer
5078 *
5079 * Reads and returns the next byte (in range 0..255) from the stream;
5080 * raises EOFError if already at end-of-stream.
5081 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5082 *
5083 * f = File.open('t.txt')
5084 * f.readbyte # => 70
5085 * f.close
5086 * f = File.open('t.rus')
5087 * f.readbyte # => 209
5088 * f.close
5089 *
5090 * Related: IO#getbyte (will not raise EOFError).
5091 *
5092 */
5093
5094static VALUE
5095rb_io_readbyte(VALUE io)
5096{
5097 VALUE c = rb_io_getbyte(io);
5098
5099 if (NIL_P(c)) {
5100 rb_eof_error();
5101 }
5102 return c;
5103}
5104
5105/*
5106 * call-seq:
5107 * ungetbyte(integer) -> nil
5108 * ungetbyte(string) -> nil
5109 *
5110 * Pushes back ("unshifts") the given data onto the stream's buffer,
5111 * placing the data so that it is next to be read; returns +nil+.
5112 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5113 *
5114 * Note that:
5115 *
5116 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5117 * - Calling #rewind on the stream discards the pushed-back data.
5118 *
5119 * When argument +integer+ is given, uses only its low-order byte:
5120 *
5121 * File.write('t.tmp', '012')
5122 * f = File.open('t.tmp')
5123 * f.ungetbyte(0x41) # => nil
5124 * f.read # => "A012"
5125 * f.rewind
5126 * f.ungetbyte(0x4243) # => nil
5127 * f.read # => "C012"
5128 * f.close
5129 *
5130 * When argument +string+ is given, uses all bytes:
5131 *
5132 * File.write('t.tmp', '012')
5133 * f = File.open('t.tmp')
5134 * f.ungetbyte('A') # => nil
5135 * f.read # => "A012"
5136 * f.rewind
5137 * f.ungetbyte('BCDE') # => nil
5138 * f.read # => "BCDE012"
5139 * f.close
5140 *
5141 */
5142
5143 VALUE
5144rb_io_ungetbyte(VALUE io, VALUE b)
5145{
5146 rb_io_t *fptr;
5147
5148 GetOpenFile(io, fptr);
5149 rb_io_check_byte_readable(fptr);
5150 switch (TYPE(b)) {
5151 case T_NIL:
5152 return Qnil;
5153 case T_FIXNUM:
5154 case T_BIGNUM: ;
5155 VALUE v = rb_int_modulo(b, INT2FIX(256));
5156 unsigned char c = NUM2INT(v) & 0xFF;
5157 b = rb_str_new((const char *)&c, 1);
5158 break;
5159 default:
5160 SafeStringValue(b);
5161 }
5162 io_ungetbyte(b, fptr);
5163 return Qnil;
5164}
5165
5166/*
5167 * call-seq:
5168 * ungetc(integer) -> nil
5169 * ungetc(string) -> nil
5170 *
5171 * Pushes back ("unshifts") the given data onto the stream's buffer,
5172 * placing the data so that it is next to be read; returns +nil+.
5173 * See {Character IO}[rdoc-ref:IO@Character+IO].
5174 *
5175 * Note that:
5176 *
5177 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5178 * - Calling #rewind on the stream discards the pushed-back data.
5179 *
5180 * When argument +integer+ is given, interprets the integer as a character:
5181 *
5182 * File.write('t.tmp', '012')
5183 * f = File.open('t.tmp')
5184 * f.ungetc(0x41) # => nil
5185 * f.read # => "A012"
5186 * f.rewind
5187 * f.ungetc(0x0442) # => nil
5188 * f.getc.ord # => 1090
5189 * f.close
5190 *
5191 * When argument +string+ is given, uses all characters:
5192 *
5193 * File.write('t.tmp', '012')
5194 * f = File.open('t.tmp')
5195 * f.ungetc('A') # => nil
5196 * f.read # => "A012"
5197 * f.rewind
5198 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5199 * f.getc.ord # => 1090
5200 * f.getc.ord # => 1077
5201 * f.getc.ord # => 1089
5202 * f.getc.ord # => 1090
5203 * f.close
5204 *
5205 */
5206
5207 VALUE
5208rb_io_ungetc(VALUE io, VALUE c)
5209{
5210 rb_io_t *fptr;
5211 long len;
5212
5213 GetOpenFile(io, fptr);
5214 rb_io_check_char_readable(fptr);
5215 if (FIXNUM_P(c)) {
5216 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5217 }
5218 else if (RB_BIGNUM_TYPE_P(c)) {
5219 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5220 }
5221 else {
5222 SafeStringValue(c);
5223 }
5224 if (NEED_READCONV(fptr)) {
5225 SET_BINARY_MODE(fptr);
5226 len = RSTRING_LEN(c);
5227#if SIZEOF_LONG > SIZEOF_INT
5228 if (len > INT_MAX)
5229 rb_raise(rb_eIOError, "ungetc failed");
5230#endif
5231 make_readconv(fptr, (int)len);
5232 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5233 rb_raise(rb_eIOError, "ungetc failed");
5234 if (fptr->cbuf.off < len) {
5235 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5236 fptr->cbuf.ptr+fptr->cbuf.off,
5237 char, fptr->cbuf.len);
5238 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5239 }
5240 fptr->cbuf.off -= (int)len;
5241 fptr->cbuf.len += (int)len;
5242 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5243 }
5244 else {
5245 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5246 io_ungetbyte(c, fptr);
5247 }
5248 return Qnil;
5249}
5250
5251/*
5252 * call-seq:
5253 * isatty -> true or false
5254 *
5255 * Returns +true+ if the stream is associated with a terminal device (tty),
5256 * +false+ otherwise:
5257 *
5258 * f = File.new('t.txt').isatty #=> false
5259 * f.close
5260 * f = File.new('/dev/tty').isatty #=> true
5261 * f.close
5262 *
5263 */
5264
5265static VALUE
5266rb_io_isatty(VALUE io)
5267{
5268 rb_io_t *fptr;
5269
5270 GetOpenFile(io, fptr);
5271 return RBOOL(isatty(fptr->fd) != 0);
5272}
5273
5274#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5275/*
5276 * call-seq:
5277 * close_on_exec? -> true or false
5278 *
5279 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5280 *
5281 * f = File.open('t.txt')
5282 * f.close_on_exec? # => true
5283 * f.close_on_exec = false
5284 * f.close_on_exec? # => false
5285 * f.close
5286 *
5287 */
5288
5289static VALUE
5290rb_io_close_on_exec_p(VALUE io)
5291{
5292 rb_io_t *fptr;
5293 VALUE write_io;
5294 int fd, ret;
5295
5296 write_io = GetWriteIO(io);
5297 if (io != write_io) {
5298 GetOpenFile(write_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)) return Qfalse;
5302 }
5303 }
5304
5305 GetOpenFile(io, fptr);
5306 if (fptr && 0 <= (fd = fptr->fd)) {
5307 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5308 if (!(ret & FD_CLOEXEC)) return Qfalse;
5309 }
5310 return Qtrue;
5311}
5312#else
5313#define rb_io_close_on_exec_p rb_f_notimplement
5314#endif
5315
5316#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5317/*
5318 * call-seq:
5319 * self.close_on_exec = bool -> true or false
5320 *
5321 * Sets a close-on-exec flag.
5322 *
5323 * f = File.open(File::NULL)
5324 * f.close_on_exec = true
5325 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5326 * f.closed? #=> false
5327 *
5328 * Ruby sets close-on-exec flags of all file descriptors by default
5329 * since Ruby 2.0.0.
5330 * So you don't need to set by yourself.
5331 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5332 * if another thread use fork() and exec() (via system() method for example).
5333 * If you really needs file descriptor inheritance to child process,
5334 * use spawn()'s argument such as fd=>fd.
5335 */
5336
5337static VALUE
5338rb_io_set_close_on_exec(VALUE io, VALUE arg)
5339{
5340 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5341 rb_io_t *fptr;
5342 VALUE write_io;
5343 int fd, ret;
5344
5345 write_io = GetWriteIO(io);
5346 if (io != write_io) {
5347 GetOpenFile(write_io, fptr);
5348 if (fptr && 0 <= (fd = fptr->fd)) {
5349 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5350 if ((ret & FD_CLOEXEC) != flag) {
5351 ret = (ret & ~FD_CLOEXEC) | flag;
5352 ret = fcntl(fd, F_SETFD, ret);
5353 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5354 }
5355 }
5356
5357 }
5358
5359 GetOpenFile(io, fptr);
5360 if (fptr && 0 <= (fd = fptr->fd)) {
5361 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5362 if ((ret & FD_CLOEXEC) != flag) {
5363 ret = (ret & ~FD_CLOEXEC) | flag;
5364 ret = fcntl(fd, F_SETFD, ret);
5365 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5366 }
5367 }
5368 return Qnil;
5369}
5370#else
5371#define rb_io_set_close_on_exec rb_f_notimplement
5372#endif
5373
5374#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5375#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5376
5377static VALUE
5378finish_writeconv(rb_io_t *fptr, int noalloc)
5379{
5380 unsigned char *ds, *dp, *de;
5381 rb_econv_result_t res;
5382
5383 if (!fptr->wbuf.ptr) {
5384 unsigned char buf[1024];
5385
5386 res = econv_destination_buffer_full;
5387 while (res == econv_destination_buffer_full) {
5388 ds = dp = buf;
5389 de = buf + sizeof(buf);
5390 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5391 while (dp-ds) {
5392 size_t remaining = dp-ds;
5393 long result = rb_io_write_memory(fptr, ds, remaining);
5394
5395 if (result > 0) {
5396 ds += result;
5397 if ((size_t)result == remaining) break;
5398 }
5399 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5400 if (fptr->fd < 0)
5401 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5402 }
5403 else {
5404 return noalloc ? Qtrue : INT2NUM(errno);
5405 }
5406 }
5407 if (res == econv_invalid_byte_sequence ||
5408 res == econv_incomplete_input ||
5409 res == econv_undefined_conversion) {
5410 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5411 }
5412 }
5413
5414 return Qnil;
5415 }
5416
5417 res = econv_destination_buffer_full;
5418 while (res == econv_destination_buffer_full) {
5419 if (fptr->wbuf.len == fptr->wbuf.capa) {
5420 if (io_fflush(fptr) < 0) {
5421 return noalloc ? Qtrue : INT2NUM(errno);
5422 }
5423 }
5424
5425 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5426 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5427 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5428 fptr->wbuf.len += (int)(dp - ds);
5429 if (res == econv_invalid_byte_sequence ||
5430 res == econv_incomplete_input ||
5431 res == econv_undefined_conversion) {
5432 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5433 }
5434 }
5435 return Qnil;
5436}
5437
5438 struct finish_writeconv_arg {
5439 rb_io_t *fptr;
5440 int noalloc;
5441};
5442
5443static VALUE
5444finish_writeconv_sync(VALUE arg)
5445{
5446 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5447 return finish_writeconv(p->fptr, p->noalloc);
5448}
5449
5450static void*
5451nogvl_close(void *ptr)
5452{
5453 int *fd = ptr;
5454
5455 return (void*)(intptr_t)close(*fd);
5456}
5457
5458static int
5459maygvl_close(int fd, int keepgvl)
5460{
5461 if (keepgvl)
5462 return close(fd);
5463
5464 /*
5465 * close() may block for certain file types (NFS, SO_LINGER sockets,
5466 * inotify), so let other threads run.
5467 */
5468 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
5469}
5470
5471static void*
5472nogvl_fclose(void *ptr)
5473{
5474 FILE *file = ptr;
5475
5476 return (void*)(intptr_t)fclose(file);
5477}
5478
5479static int
5480maygvl_fclose(FILE *file, int keepgvl)
5481{
5482 if (keepgvl)
5483 return fclose(file);
5484
5485 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
5486}
5487
5488static void free_io_buffer(rb_io_buffer_t *buf);
5489static void clear_codeconv(rb_io_t *fptr);
5490
5491static void
5492fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5493 struct rb_io_close_wait_list *busy)
5494{
5495 VALUE error = Qnil;
5496 int fd = fptr->fd;
5497 FILE *stdio_file = fptr->stdio_file;
5498 int mode = fptr->mode;
5499
5500 if (fptr->writeconv) {
5501 if (!NIL_P(fptr->write_lock) && !noraise) {
5502 struct finish_writeconv_arg arg;
5503 arg.fptr = fptr;
5504 arg.noalloc = noraise;
5505 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5506 }
5507 else {
5508 error = finish_writeconv(fptr, noraise);
5509 }
5510 }
5511 if (fptr->wbuf.len) {
5512 if (noraise) {
5513 io_flush_buffer_sync(fptr);
5514 }
5515 else {
5516 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5517 error = INT2NUM(errno);
5518 }
5519 }
5520 }
5521
5522 int done = 0;
5523
5524 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5525 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5526 done = 1;
5527 }
5528
5529 fptr->fd = -1;
5530 fptr->stdio_file = 0;
5531 fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
5532
5533 // Ensure waiting_fd users do not hit EBADF.
5534 if (busy) {
5535 // Wait for them to exit before we call close().
5536 rb_notify_fd_close_wait(busy);
5537 }
5538
5539 // Disable for now.
5540 // if (!done && fd >= 0) {
5541 // VALUE scheduler = rb_fiber_scheduler_current();
5542 // if (scheduler != Qnil) {
5543 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5544 // if (!UNDEF_P(result)) done = 1;
5545 // }
5546 // }
5547
5548 if (!done && stdio_file) {
5549 // stdio_file is deallocated anyway even if fclose failed.
5550 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5551 if (!noraise) {
5552 error = INT2NUM(errno);
5553 }
5554 }
5555
5556 done = 1;
5557 }
5558
5559 if (!done && fd >= 0) {
5560 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5561 // We assumes it is closed.
5562
5563 keepgvl |= !(mode & FMODE_WRITABLE);
5564 keepgvl |= noraise;
5565 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5566 if (!noraise) {
5567 error = INT2NUM(errno);
5568 }
5569 }
5570
5571 done = 1;
5572 }
5573
5574 if (!NIL_P(error) && !noraise) {
5575 if (RB_INTEGER_TYPE_P(error))
5576 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5577 else
5578 rb_exc_raise(error);
5579 }
5580}
5581
5582static void
5583fptr_finalize(rb_io_t *fptr, int noraise)
5584{
5585 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5586 free_io_buffer(&fptr->rbuf);
5587 free_io_buffer(&fptr->wbuf);
5588 clear_codeconv(fptr);
5589}
5590
5591static void
5592rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5593{
5594 if (fptr->finalize) {
5595 (*fptr->finalize)(fptr, noraise);
5596 }
5597 else {
5598 fptr_finalize(fptr, noraise);
5599 }
5600}
5601
5602static void
5603free_io_buffer(rb_io_buffer_t *buf)
5604{
5605 if (buf->ptr) {
5606 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5607 buf->ptr = NULL;
5608 }
5609}
5610
5611static void
5612clear_readconv(rb_io_t *fptr)
5613{
5614 if (fptr->readconv) {
5615 rb_econv_close(fptr->readconv);
5616 fptr->readconv = NULL;
5617 }
5618 free_io_buffer(&fptr->cbuf);
5619}
5620
5621static void
5622clear_writeconv(rb_io_t *fptr)
5623{
5624 if (fptr->writeconv) {
5625 rb_econv_close(fptr->writeconv);
5626 fptr->writeconv = NULL;
5627 }
5628 fptr->writeconv_initialized = 0;
5629}
5630
5631static void
5632clear_codeconv(rb_io_t *fptr)
5633{
5634 clear_readconv(fptr);
5635 clear_writeconv(fptr);
5636}
5637
5638static void
5639rb_io_fptr_cleanup_all(rb_io_t *fptr)
5640{
5641 fptr->pathv = Qnil;
5642 if (0 <= fptr->fd)
5643 rb_io_fptr_cleanup(fptr, TRUE);
5644 fptr->write_lock = Qnil;
5645 free_io_buffer(&fptr->rbuf);
5646 free_io_buffer(&fptr->wbuf);
5647 clear_codeconv(fptr);
5648}
5649
5650void
5651rb_io_fptr_finalize_internal(void *ptr)
5652{
5653 if (!ptr) return;
5654 rb_io_fptr_cleanup_all(ptr);
5655 free(ptr);
5656}
5657
5658#undef rb_io_fptr_finalize
5659int
5660rb_io_fptr_finalize(rb_io_t *fptr)
5661{
5662 if (!fptr) {
5663 return 0;
5664 }
5665 else {
5666 rb_io_fptr_finalize_internal(fptr);
5667 return 1;
5668 }
5669}
5670#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5671
5672RUBY_FUNC_EXPORTED size_t
5673rb_io_memsize(const rb_io_t *fptr)
5674{
5675 size_t size = sizeof(rb_io_t);
5676 size += fptr->rbuf.capa;
5677 size += fptr->wbuf.capa;
5678 size += fptr->cbuf.capa;
5679 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5680 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5681 return size;
5682}
5683
5684#ifdef _WIN32
5685/* keep GVL while closing to prevent crash on Windows */
5686# define KEEPGVL TRUE
5687#else
5688# define KEEPGVL FALSE
5689#endif
5690
5691static rb_io_t *
5692io_close_fptr(VALUE io)
5693{
5694 rb_io_t *fptr;
5695 VALUE write_io;
5696 rb_io_t *write_fptr;
5697 struct rb_io_close_wait_list busy;
5698
5699 write_io = GetWriteIO(io);
5700 if (io != write_io) {
5701 write_fptr = RFILE(write_io)->fptr;
5702 if (write_fptr && 0 <= write_fptr->fd) {
5703 rb_io_fptr_cleanup(write_fptr, TRUE);
5704 }
5705 }
5706
5707 fptr = RFILE(io)->fptr;
5708 if (!fptr) return 0;
5709 if (fptr->fd < 0) return 0;
5710
5711 if (rb_notify_fd_close(fptr->fd, &busy)) {
5712 /* calls close(fptr->fd): */
5713 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5714 }
5715 rb_io_fptr_cleanup(fptr, FALSE);
5716 return fptr;
5717}
5718
5719static void
5720fptr_waitpid(rb_io_t *fptr, int nohang)
5721{
5722 int status;
5723 if (fptr->pid) {
5724 rb_last_status_clear();
5725 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5726 fptr->pid = 0;
5727 }
5728}
5729
5730 VALUE
5731rb_io_close(VALUE io)
5732{
5733 rb_io_t *fptr = io_close_fptr(io);
5734 if (fptr) fptr_waitpid(fptr, 0);
5735 return Qnil;
5736}
5737
5738/*
5739 * call-seq:
5740 * close -> nil
5741 *
5742 * Closes the stream for both reading and writing
5743 * if open for either or both; returns +nil+.
5744 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5745 *
5746 * If the stream is open for writing, flushes any buffered writes
5747 * to the operating system before closing.
5748 *
5749 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5750 * (child exit status).
5751 *
5752 * Example:
5753 *
5754 * IO.popen('ruby', 'r+') do |pipe|
5755 * puts pipe.closed?
5756 * pipe.close
5757 * puts $?
5758 * puts pipe.closed?
5759 * end
5760 *
5761 * Output:
5762 *
5763 * false
5764 * pid 13760 exit 0
5765 * true
5766 *
5767 * Related: IO#close_read, IO#close_write, IO#closed?.
5768 */
5769
5770static VALUE
5771rb_io_close_m(VALUE io)
5772{
5773 rb_io_t *fptr = rb_io_get_fptr(io);
5774 if (fptr->fd < 0) {
5775 return Qnil;
5776 }
5777 rb_io_close(io);
5778 return Qnil;
5779}
5780
5781static VALUE
5782io_call_close(VALUE io)
5783{
5784 rb_check_funcall(io, rb_intern("close"), 0, 0);
5785 return io;
5786}
5787
5788static VALUE
5789ignore_closed_stream(VALUE io, VALUE exc)
5790{
5791 enum {mesg_len = sizeof(closed_stream)-1};
5792 VALUE mesg = rb_attr_get(exc, idMesg);
5793 if (!RB_TYPE_P(mesg, T_STRING) ||
5794 RSTRING_LEN(mesg) != mesg_len ||
5795 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5796 rb_exc_raise(exc);
5797 }
5798 return io;
5799}
5800
5801static VALUE
5802io_close(VALUE io)
5803{
5804 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5805 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5806 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5807 rb_eIOError, (VALUE)0);
5808 return io;
5809}
5810
5811/*
5812 * call-seq:
5813 * closed? -> true or false
5814 *
5815 * Returns +true+ if the stream is closed for both reading and writing,
5816 * +false+ otherwise.
5817 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5818 *
5819 * IO.popen('ruby', 'r+') do |pipe|
5820 * puts pipe.closed?
5821 * pipe.close_read
5822 * puts pipe.closed?
5823 * pipe.close_write
5824 * puts pipe.closed?
5825 * end
5826 *
5827 * Output:
5828 *
5829 * false
5830 * false
5831 * true
5832 *
5833 * Related: IO#close_read, IO#close_write, IO#close.
5834 */
5835 VALUE
5836rb_io_closed_p(VALUE io)
5837{
5838 rb_io_t *fptr;
5839 VALUE write_io;
5840 rb_io_t *write_fptr;
5841
5842 write_io = GetWriteIO(io);
5843 if (io != write_io) {
5844 write_fptr = RFILE(write_io)->fptr;
5845 if (write_fptr && 0 <= write_fptr->fd) {
5846 return Qfalse;
5847 }
5848 }
5849
5850 fptr = rb_io_get_fptr(io);
5851 return RBOOL(0 > fptr->fd);
5852}
5853
5854/*
5855 * call-seq:
5856 * close_read -> nil
5857 *
5858 * Closes the stream for reading if open for reading;
5859 * returns +nil+.
5860 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5861 *
5862 * If the stream was opened by IO.popen and is also closed for writing,
5863 * sets global variable <tt>$?</tt> (child exit status).
5864 *
5865 * Example:
5866 *
5867 * IO.popen('ruby', 'r+') do |pipe|
5868 * puts pipe.closed?
5869 * pipe.close_write
5870 * puts pipe.closed?
5871 * pipe.close_read
5872 * puts $?
5873 * puts pipe.closed?
5874 * end
5875 *
5876 * Output:
5877 *
5878 * false
5879 * false
5880 * pid 14748 exit 0
5881 * true
5882 *
5883 * Related: IO#close, IO#close_write, IO#closed?.
5884 */
5885
5886static VALUE
5887rb_io_close_read(VALUE io)
5888{
5889 rb_io_t *fptr;
5890 VALUE write_io;
5891
5892 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5893 if (fptr->fd < 0) return Qnil;
5894 if (is_socket(fptr->fd, fptr->pathv)) {
5895#ifndef SHUT_RD
5896# define SHUT_RD 0
5897#endif
5898 if (shutdown(fptr->fd, SHUT_RD) < 0)
5899 rb_sys_fail_path(fptr->pathv);
5900 fptr->mode &= ~FMODE_READABLE;
5901 if (!(fptr->mode & FMODE_WRITABLE))
5902 return rb_io_close(io);
5903 return Qnil;
5904 }
5905
5906 write_io = GetWriteIO(io);
5907 if (io != write_io) {
5908 rb_io_t *wfptr;
5909 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5910 wfptr->pid = fptr->pid;
5911 fptr->pid = 0;
5912 RFILE(io)->fptr = wfptr;
5913 /* bind to write_io temporarily to get rid of memory/fd leak */
5914 fptr->tied_io_for_writing = 0;
5915 RFILE(write_io)->fptr = fptr;
5916 rb_io_fptr_cleanup(fptr, FALSE);
5917 /* should not finalize fptr because another thread may be reading it */
5918 return Qnil;
5919 }
5920
5921 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5922 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5923 }
5924 return rb_io_close(io);
5925}
5926
5927/*
5928 * call-seq:
5929 * close_write -> nil
5930 *
5931 * Closes the stream for writing if open for writing;
5932 * returns +nil+.
5933 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5934 *
5935 * Flushes any buffered writes to the operating system before closing.
5936 *
5937 * If the stream was opened by IO.popen and is also closed for reading,
5938 * sets global variable <tt>$?</tt> (child exit status).
5939 *
5940 * IO.popen('ruby', 'r+') do |pipe|
5941 * puts pipe.closed?
5942 * pipe.close_read
5943 * puts pipe.closed?
5944 * pipe.close_write
5945 * puts $?
5946 * puts pipe.closed?
5947 * end
5948 *
5949 * Output:
5950 *
5951 * false
5952 * false
5953 * pid 15044 exit 0
5954 * true
5955 *
5956 * Related: IO#close, IO#close_read, IO#closed?.
5957 */
5958
5959static VALUE
5960rb_io_close_write(VALUE io)
5961{
5962 rb_io_t *fptr;
5963 VALUE write_io;
5964
5965 write_io = GetWriteIO(io);
5966 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5967 if (fptr->fd < 0) return Qnil;
5968 if (is_socket(fptr->fd, fptr->pathv)) {
5969#ifndef SHUT_WR
5970# define SHUT_WR 1
5971#endif
5972 if (shutdown(fptr->fd, SHUT_WR) < 0)
5973 rb_sys_fail_path(fptr->pathv);
5974 fptr->mode &= ~FMODE_WRITABLE;
5975 if (!(fptr->mode & FMODE_READABLE))
5976 return rb_io_close(write_io);
5977 return Qnil;
5978 }
5979
5980 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
5981 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
5982 }
5983
5984 if (io != write_io) {
5985 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5986 fptr->tied_io_for_writing = 0;
5987 }
5988 rb_io_close(write_io);
5989 return Qnil;
5990}
5991
5992/*
5993 * call-seq:
5994 * sysseek(offset, whence = IO::SEEK_SET) -> integer
5995 *
5996 * Behaves like IO#seek, except that it:
5997 *
5998 * - Uses low-level system functions.
5999 * - Returns the new position.
6000 *
6001 */
6002
6003static VALUE
6004rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6005{
6006 VALUE offset, ptrname;
6007 int whence = SEEK_SET;
6008 rb_io_t *fptr;
6009 rb_off_t pos;
6010
6011 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6012 whence = interpret_seek_whence(ptrname);
6013 }
6014 pos = NUM2OFFT(offset);
6015 GetOpenFile(io, fptr);
6016 if ((fptr->mode & FMODE_READABLE) &&
6017 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6018 rb_raise(rb_eIOError, "sysseek for buffered IO");
6019 }
6020 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6021 rb_warn("sysseek for buffered IO");
6022 }
6023 errno = 0;
6024 pos = lseek(fptr->fd, pos, whence);
6025 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6026
6027 return OFFT2NUM(pos);
6028}
6029
6030/*
6031 * call-seq:
6032 * syswrite(object) -> integer
6033 *
6034 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6035 * returns the number bytes written.
6036 * If +object+ is not a string is converted via method to_s:
6037 *
6038 * f = File.new('t.tmp', 'w')
6039 * f.syswrite('foo') # => 3
6040 * f.syswrite(30) # => 2
6041 * f.syswrite(:foo) # => 3
6042 * f.close
6043 *
6044 * This methods should not be used with other stream-writer methods.
6045 *
6046 */
6047
6048static VALUE
6049rb_io_syswrite(VALUE io, VALUE str)
6050{
6051 VALUE tmp;
6052 rb_io_t *fptr;
6053 long n, len;
6054 const char *ptr;
6055
6056 if (!RB_TYPE_P(str, T_STRING))
6057 str = rb_obj_as_string(str);
6058
6059 io = GetWriteIO(io);
6060 GetOpenFile(io, fptr);
6061 rb_io_check_writable(fptr);
6062
6063 if (fptr->wbuf.len) {
6064 rb_warn("syswrite for buffered IO");
6065 }
6066
6067 tmp = rb_str_tmp_frozen_acquire(str);
6068 RSTRING_GETMEM(tmp, ptr, len);
6069 n = rb_io_write_memory(fptr, ptr, len);
6070 if (n < 0) rb_sys_fail_path(fptr->pathv);
6071 rb_str_tmp_frozen_release(str, tmp);
6072
6073 return LONG2FIX(n);
6074}
6075
6076/*
6077 * call-seq:
6078 * sysread(maxlen) -> string
6079 * sysread(maxlen, out_string) -> string
6080 *
6081 * Behaves like IO#readpartial, except that it uses low-level system functions.
6082 *
6083 * This method should not be used with other stream-reader methods.
6084 *
6085 */
6086
6087static VALUE
6088rb_io_sysread(int argc, VALUE *argv, VALUE io)
6089{
6090 VALUE len, str;
6091 rb_io_t *fptr;
6092 long n, ilen;
6093 struct io_internal_read_struct iis;
6094 int shrinkable;
6095
6096 rb_scan_args(argc, argv, "11", &len, &str);
6097 ilen = NUM2LONG(len);
6098
6099 shrinkable = io_setstrbuf(&str, ilen);
6100 if (ilen == 0) return str;
6101
6102 GetOpenFile(io, fptr);
6103 rb_io_check_byte_readable(fptr);
6104
6105 if (READ_DATA_BUFFERED(fptr)) {
6106 rb_raise(rb_eIOError, "sysread for buffered IO");
6107 }
6108
6109 rb_io_check_closed(fptr);
6110
6111 io_setstrbuf(&str, ilen);
6112 iis.th = rb_thread_current();
6113 iis.fptr = fptr;
6114 iis.nonblock = 0;
6115 iis.fd = fptr->fd;
6116 iis.buf = RSTRING_PTR(str);
6117 iis.capa = ilen;
6118 iis.timeout = NULL;
6119 n = io_read_memory_locktmp(str, &iis);
6120
6121 if (n < 0) {
6122 rb_sys_fail_path(fptr->pathv);
6123 }
6124
6125 io_set_read_length(str, n, shrinkable);
6126
6127 if (n == 0 && ilen > 0) {
6128 rb_eof_error();
6129 }
6130
6131 return str;
6132}
6133
6134 struct prdwr_internal_arg {
6135 VALUE io;
6136 int fd;
6137 void *buf;
6138 size_t count;
6139 rb_off_t offset;
6140};
6141
6142static VALUE
6143internal_pread_func(void *_arg)
6144{
6145 struct prdwr_internal_arg *arg = _arg;
6146
6147 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6148}
6149
6150static VALUE
6151pread_internal_call(VALUE _arg)
6152{
6153 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6154
6155 VALUE scheduler = rb_fiber_scheduler_current();
6156 if (scheduler != Qnil) {
6157 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io, arg->offset, arg->buf, arg->count, 0);
6158
6159 if (!UNDEF_P(result)) {
6160 return rb_fiber_scheduler_io_result_apply(result);
6161 }
6162 }
6163
6164 return rb_thread_io_blocking_call(internal_pread_func, arg, arg->fd, RB_WAITFD_IN);
6165}
6166
6167/*
6168 * call-seq:
6169 * pread(maxlen, offset) -> string
6170 * pread(maxlen, offset, out_string) -> string
6171 *
6172 * Behaves like IO#readpartial, except that it:
6173 *
6174 * - Reads at the given +offset+ (in bytes).
6175 * - Disregards, and does not modify, the stream's position
6176 * (see {Position}[rdoc-ref:IO@Position]).
6177 * - Bypasses any user space buffering in the stream.
6178 *
6179 * Because this method does not disturb the stream's state
6180 * (its position, in particular), +pread+ allows multiple threads and processes
6181 * to use the same \IO object for reading at various offsets.
6182 *
6183 * f = File.open('t.txt')
6184 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6185 * f.pos # => 52
6186 * # Read 12 bytes at offset 0.
6187 * f.pread(12, 0) # => "First line\n"
6188 * # Read 9 bytes at offset 8.
6189 * f.pread(9, 8) # => "ne\nSecon"
6190 * f.close
6191 *
6192 * Not available on some platforms.
6193 *
6194 */
6195static VALUE
6196rb_io_pread(int argc, VALUE *argv, VALUE io)
6197{
6198 VALUE len, offset, str;
6199 rb_io_t *fptr;
6200 ssize_t n;
6201 struct prdwr_internal_arg arg = {.io = io};
6202 int shrinkable;
6203
6204 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6205 arg.count = NUM2SIZET(len);
6206 arg.offset = NUM2OFFT(offset);
6207
6208 shrinkable = io_setstrbuf(&str, (long)arg.count);
6209 if (arg.count == 0) return str;
6210 arg.buf = RSTRING_PTR(str);
6211
6212 GetOpenFile(io, fptr);
6213 rb_io_check_byte_readable(fptr);
6214
6215 arg.fd = fptr->fd;
6216 rb_io_check_closed(fptr);
6217
6218 rb_str_locktmp(str);
6219 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6220
6221 if (n < 0) {
6222 rb_sys_fail_path(fptr->pathv);
6223 }
6224 io_set_read_length(str, n, shrinkable);
6225 if (n == 0 && arg.count > 0) {
6226 rb_eof_error();
6227 }
6228
6229 return str;
6230}
6231
6232static VALUE
6233internal_pwrite_func(void *_arg)
6234{
6235 struct prdwr_internal_arg *arg = _arg;
6236
6237 VALUE scheduler = rb_fiber_scheduler_current();
6238 if (scheduler != Qnil) {
6239 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io, arg->offset, arg->buf, arg->count, 0);
6240
6241 if (!UNDEF_P(result)) {
6242 return rb_fiber_scheduler_io_result_apply(result);
6243 }
6244 }
6245
6246
6247 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6248}
6249
6250/*
6251 * call-seq:
6252 * pwrite(object, offset) -> integer
6253 *
6254 * Behaves like IO#write, except that it:
6255 *
6256 * - Writes at the given +offset+ (in bytes).
6257 * - Disregards, and does not modify, the stream's position
6258 * (see {Position}[rdoc-ref:IO@Position]).
6259 * - Bypasses any user space buffering in the stream.
6260 *
6261 * Because this method does not disturb the stream's state
6262 * (its position, in particular), +pwrite+ allows multiple threads and processes
6263 * to use the same \IO object for writing at various offsets.
6264 *
6265 * f = File.open('t.tmp', 'w+')
6266 * # Write 6 bytes at offset 3.
6267 * f.pwrite('ABCDEF', 3) # => 6
6268 * f.rewind
6269 * f.read # => "\u0000\u0000\u0000ABCDEF"
6270 * f.close
6271 *
6272 * Not available on some platforms.
6273 *
6274 */
6275static VALUE
6276rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6277{
6278 rb_io_t *fptr;
6279 ssize_t n;
6280 struct prdwr_internal_arg arg = {.io = io};
6281 VALUE tmp;
6282
6283 if (!RB_TYPE_P(str, T_STRING))
6284 str = rb_obj_as_string(str);
6285
6286 arg.offset = NUM2OFFT(offset);
6287
6288 io = GetWriteIO(io);
6289 GetOpenFile(io, fptr);
6290 rb_io_check_writable(fptr);
6291 arg.fd = fptr->fd;
6292
6293 tmp = rb_str_tmp_frozen_acquire(str);
6294 arg.buf = RSTRING_PTR(tmp);
6295 arg.count = (size_t)RSTRING_LEN(tmp);
6296
6297 n = (ssize_t)rb_thread_io_blocking_call(internal_pwrite_func, &arg, fptr->fd, RB_WAITFD_OUT);
6298 if (n < 0) rb_sys_fail_path(fptr->pathv);
6299 rb_str_tmp_frozen_release(str, tmp);
6300
6301 return SSIZET2NUM(n);
6302}
6303
6304 VALUE
6305rb_io_binmode(VALUE io)
6306{
6307 rb_io_t *fptr;
6308
6309 GetOpenFile(io, fptr);
6310 if (fptr->readconv)
6311 rb_econv_binmode(fptr->readconv);
6312 if (fptr->writeconv)
6313 rb_econv_binmode(fptr->writeconv);
6314 fptr->mode |= FMODE_BINMODE;
6315 fptr->mode &= ~FMODE_TEXTMODE;
6316 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6317#ifdef O_BINARY
6318 if (!fptr->readconv) {
6319 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6320 }
6321 else {
6322 setmode(fptr->fd, O_BINARY);
6323 }
6324#endif
6325 return io;
6326}
6327
6328static void
6329io_ascii8bit_binmode(rb_io_t *fptr)
6330{
6331 if (fptr->readconv) {
6332 rb_econv_close(fptr->readconv);
6333 fptr->readconv = NULL;
6334 }
6335 if (fptr->writeconv) {
6336 rb_econv_close(fptr->writeconv);
6337 fptr->writeconv = NULL;
6338 }
6339 fptr->mode |= FMODE_BINMODE;
6340 fptr->mode &= ~FMODE_TEXTMODE;
6341 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6342
6343 fptr->encs.enc = rb_ascii8bit_encoding();
6344 fptr->encs.enc2 = NULL;
6345 fptr->encs.ecflags = 0;
6346 fptr->encs.ecopts = Qnil;
6347 clear_codeconv(fptr);
6348}
6349
6350 VALUE
6351rb_io_ascii8bit_binmode(VALUE io)
6352{
6353 rb_io_t *fptr;
6354
6355 GetOpenFile(io, fptr);
6356 io_ascii8bit_binmode(fptr);
6357
6358 return io;
6359}
6360
6361/*
6362 * call-seq:
6363 * binmode -> self
6364 *
6365 * Sets the stream's data mode as binary
6366 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6367 *
6368 * A stream's data mode may not be changed from binary to text.
6369 *
6370 */
6371
6372static VALUE
6373rb_io_binmode_m(VALUE io)
6374{
6375 VALUE write_io;
6376
6377 rb_io_ascii8bit_binmode(io);
6378
6379 write_io = GetWriteIO(io);
6380 if (write_io != io)
6381 rb_io_ascii8bit_binmode(write_io);
6382 return io;
6383}
6384
6385/*
6386 * call-seq:
6387 * binmode? -> true or false
6388 *
6389 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6390 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6391 *
6392 */
6393static VALUE
6394rb_io_binmode_p(VALUE io)
6395{
6396 rb_io_t *fptr;
6397 GetOpenFile(io, fptr);
6398 return RBOOL(fptr->mode & FMODE_BINMODE);
6399}
6400
6401static const char*
6402rb_io_fmode_modestr(int fmode)
6403{
6404 if (fmode & FMODE_APPEND) {
6405 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6406 return MODE_BTMODE("a+", "ab+", "at+");
6407 }
6408 return MODE_BTMODE("a", "ab", "at");
6409 }
6410 switch (fmode & FMODE_READWRITE) {
6411 default:
6412 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6413 case FMODE_READABLE:
6414 return MODE_BTMODE("r", "rb", "rt");
6415 case FMODE_WRITABLE:
6416 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6417 case FMODE_READWRITE:
6418 if (fmode & FMODE_CREATE) {
6419 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6420 }
6421 return MODE_BTMODE("r+", "rb+", "rt+");
6422 }
6423}
6424
6425static const char bom_prefix[] = "bom|";
6426static const char utf_prefix[] = "utf-";
6427enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6428enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6429
6430static int
6431io_encname_bom_p(const char *name, long len)
6432{
6433 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6434}
6435
6436int
6437rb_io_modestr_fmode(const char *modestr)
6438{
6439 int fmode = 0;
6440 const char *m = modestr, *p = NULL;
6441
6442 switch (*m++) {
6443 case 'r':
6444 fmode |= FMODE_READABLE;
6445 break;
6446 case 'w':
6447 fmode |= FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE;
6448 break;
6449 case 'a':
6450 fmode |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
6451 break;
6452 default:
6453 goto error;
6454 }
6455
6456 while (*m) {
6457 switch (*m++) {
6458 case 'b':
6459 fmode |= FMODE_BINMODE;
6460 break;
6461 case 't':
6462 fmode |= FMODE_TEXTMODE;
6463 break;
6464 case '+':
6465 fmode |= FMODE_READWRITE;
6466 break;
6467 case 'x':
6468 if (modestr[0] != 'w')
6469 goto error;
6470 fmode |= FMODE_EXCL;
6471 break;
6472 default:
6473 goto error;
6474 case ':':
6475 p = strchr(m, ':');
6476 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6477 fmode |= FMODE_SETENC_BY_BOM;
6478 goto finished;
6479 }
6480 }
6481
6482 finished:
6483 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6484 goto error;
6485
6486 return fmode;
6487
6488 error:
6489 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6490 UNREACHABLE_RETURN(Qundef);
6491}
6492
6493int
6494rb_io_oflags_fmode(int oflags)
6495{
6496 int fmode = 0;
6497
6498 switch (oflags & O_ACCMODE) {
6499 case O_RDONLY:
6500 fmode = FMODE_READABLE;
6501 break;
6502 case O_WRONLY:
6503 fmode = FMODE_WRITABLE;
6504 break;
6505 case O_RDWR:
6506 fmode = FMODE_READWRITE;
6507 break;
6508 }
6509
6510 if (oflags & O_APPEND) {
6511 fmode |= FMODE_APPEND;
6512 }
6513 if (oflags & O_TRUNC) {
6514 fmode |= FMODE_TRUNC;
6515 }
6516 if (oflags & O_CREAT) {
6517 fmode |= FMODE_CREATE;
6518 }
6519 if (oflags & O_EXCL) {
6520 fmode |= FMODE_EXCL;
6521 }
6522#ifdef O_BINARY
6523 if (oflags & O_BINARY) {
6524 fmode |= FMODE_BINMODE;
6525 }
6526#endif
6527
6528 return fmode;
6529}
6530
6531static int
6532rb_io_fmode_oflags(int fmode)
6533{
6534 int oflags = 0;
6535
6536 switch (fmode & FMODE_READWRITE) {
6537 case FMODE_READABLE:
6538 oflags |= O_RDONLY;
6539 break;
6540 case FMODE_WRITABLE:
6541 oflags |= O_WRONLY;
6542 break;
6543 case FMODE_READWRITE:
6544 oflags |= O_RDWR;
6545 break;
6546 }
6547
6548 if (fmode & FMODE_APPEND) {
6549 oflags |= O_APPEND;
6550 }
6551 if (fmode & FMODE_TRUNC) {
6552 oflags |= O_TRUNC;
6553 }
6554 if (fmode & FMODE_CREATE) {
6555 oflags |= O_CREAT;
6556 }
6557 if (fmode & FMODE_EXCL) {
6558 oflags |= O_EXCL;
6559 }
6560#ifdef O_BINARY
6561 if (fmode & FMODE_BINMODE) {
6562 oflags |= O_BINARY;
6563 }
6564#endif
6565
6566 return oflags;
6567}
6568
6569int
6570rb_io_modestr_oflags(const char *modestr)
6571{
6572 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6573}
6574
6575static const char*
6576rb_io_oflags_modestr(int oflags)
6577{
6578#ifdef O_BINARY
6579# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6580#else
6581# define MODE_BINARY(a,b) (a)
6582#endif
6583 int accmode;
6584 if (oflags & O_EXCL) {
6585 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6586 }
6587 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6588 if (oflags & O_APPEND) {
6589 if (accmode == O_WRONLY) {
6590 return MODE_BINARY("a", "ab");
6591 }
6592 if (accmode == O_RDWR) {
6593 return MODE_BINARY("a+", "ab+");
6594 }
6595 }
6596 switch (accmode) {
6597 default:
6598 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6599 case O_RDONLY:
6600 return MODE_BINARY("r", "rb");
6601 case O_WRONLY:
6602 return MODE_BINARY("w", "wb");
6603 case O_RDWR:
6604 if (oflags & O_TRUNC) {
6605 return MODE_BINARY("w+", "wb+");
6606 }
6607 return MODE_BINARY("r+", "rb+");
6608 }
6609}
6610
6611/*
6612 * Convert external/internal encodings to enc/enc2
6613 * NULL => use default encoding
6614 * Qnil => no encoding specified (internal only)
6615 */
6616static void
6617rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6618{
6619 int default_ext = 0;
6620
6621 if (ext == NULL) {
6622 ext = rb_default_external_encoding();
6623 default_ext = 1;
6624 }
6625 if (rb_is_ascii8bit_enc(ext)) {
6626 /* If external is ASCII-8BIT, no transcoding */
6627 intern = NULL;
6628 }
6629 else if (intern == NULL) {
6630 intern = rb_default_internal_encoding();
6631 }
6632 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6633 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6634 /* No internal encoding => use external + no transcoding */
6635 *enc = (default_ext && intern != ext) ? NULL : ext;
6636 *enc2 = NULL;
6637 }
6638 else {
6639 *enc = intern;
6640 *enc2 = ext;
6641 }
6642}
6643
6644static void
6645unsupported_encoding(const char *name, rb_encoding *enc)
6646{
6647 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6648}
6649
6650static void
6651parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6652 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6653{
6654 const char *p;
6655 char encname[ENCODING_MAXNAMELEN+1];
6656 int idx, idx2;
6657 int fmode = fmode_p ? *fmode_p : 0;
6658 rb_encoding *ext_enc, *int_enc;
6659 long len;
6660
6661 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6662
6663 p = strrchr(estr, ':');
6664 len = p ? (p++ - estr) : (long)strlen(estr);
6665 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6666 estr += bom_prefix_len;
6667 len -= bom_prefix_len;
6668 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6669 fmode |= FMODE_SETENC_BY_BOM;
6670 }
6671 else {
6672 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6673 fmode &= ~FMODE_SETENC_BY_BOM;
6674 }
6675 }
6676 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6677 idx = -1;
6678 }
6679 else {
6680 if (p) {
6681 memcpy(encname, estr, len);
6682 encname[len] = '\0';
6683 estr = encname;
6684 }
6685 idx = rb_enc_find_index(estr);
6686 }
6687 if (fmode_p) *fmode_p = fmode;
6688
6689 if (idx >= 0)
6690 ext_enc = rb_enc_from_index(idx);
6691 else {
6692 if (idx != -2)
6693 unsupported_encoding(estr, estr_enc);
6694 ext_enc = NULL;
6695 }
6696
6697 int_enc = NULL;
6698 if (p) {
6699 if (*p == '-' && *(p+1) == '\0') {
6700 /* Special case - "-" => no transcoding */
6701 int_enc = (rb_encoding *)Qnil;
6702 }
6703 else {
6704 idx2 = rb_enc_find_index(p);
6705 if (idx2 < 0)
6706 unsupported_encoding(p, estr_enc);
6707 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6708 int_enc = (rb_encoding *)Qnil;
6709 }
6710 else
6711 int_enc = rb_enc_from_index(idx2);
6712 }
6713 }
6714
6715 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6716}
6717
6718int
6719rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6720{
6721 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6722 int extracted = 0;
6723 rb_encoding *extencoding = NULL;
6724 rb_encoding *intencoding = NULL;
6725
6726 if (!NIL_P(opt)) {
6727 VALUE v;
6728 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6729 if (v != Qnil) encoding = v;
6730 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6731 if (v != Qnil) extenc = v;
6732 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6733 if (!UNDEF_P(v)) intenc = v;
6734 }
6735 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6736 if (!NIL_P(ruby_verbose)) {
6737 int idx = rb_to_encoding_index(encoding);
6738 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6739 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6740 encoding, UNDEF_P(extenc) ? "internal" : "external");
6741 }
6742 encoding = Qnil;
6743 }
6744 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6745 extencoding = rb_to_encoding(extenc);
6746 }
6747 if (!UNDEF_P(intenc)) {
6748 if (NIL_P(intenc)) {
6749 /* internal_encoding: nil => no transcoding */
6750 intencoding = (rb_encoding *)Qnil;
6751 }
6752 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6753 char *p = StringValueCStr(tmp);
6754
6755 if (*p == '-' && *(p+1) == '\0') {
6756 /* Special case - "-" => no transcoding */
6757 intencoding = (rb_encoding *)Qnil;
6758 }
6759 else {
6760 intencoding = rb_to_encoding(intenc);
6761 }
6762 }
6763 else {
6764 intencoding = rb_to_encoding(intenc);
6765 }
6766 if (extencoding == intencoding) {
6767 intencoding = (rb_encoding *)Qnil;
6768 }
6769 }
6770 if (!NIL_P(encoding)) {
6771 extracted = 1;
6772 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6773 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6774 enc_p, enc2_p, fmode_p);
6775 }
6776 else {
6777 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6778 }
6779 }
6780 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6781 extracted = 1;
6782 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6783 }
6784 return extracted;
6785}
6786
6787static void
6788validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6789{
6790 int fmode = *fmode_p;
6791
6792 if ((fmode & FMODE_READABLE) &&
6793 !enc2 &&
6794 !(fmode & FMODE_BINMODE) &&
6795 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6796 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6797
6798 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6799 rb_raise(rb_eArgError, "newline decorator with binary mode");
6800 }
6801 if (!(fmode & FMODE_BINMODE) &&
6802 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6803 fmode |= FMODE_TEXTMODE;
6804 *fmode_p = fmode;
6805 }
6806#if !DEFAULT_TEXTMODE
6807 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6808 fmode &= ~FMODE_TEXTMODE;
6809 *fmode_p = fmode;
6810 }
6811#endif
6812}
6813
6814static void
6815extract_binmode(VALUE opthash, int *fmode)
6816{
6817 if (!NIL_P(opthash)) {
6818 VALUE v;
6819 v = rb_hash_aref(opthash, sym_textmode);
6820 if (!NIL_P(v)) {
6821 if (*fmode & FMODE_TEXTMODE)
6822 rb_raise(rb_eArgError, "textmode specified twice");
6823 if (*fmode & FMODE_BINMODE)
6824 rb_raise(rb_eArgError, "both textmode and binmode specified");
6825 if (RTEST(v))
6826 *fmode |= FMODE_TEXTMODE;
6827 }
6828 v = rb_hash_aref(opthash, sym_binmode);
6829 if (!NIL_P(v)) {
6830 if (*fmode & FMODE_BINMODE)
6831 rb_raise(rb_eArgError, "binmode specified twice");
6832 if (*fmode & FMODE_TEXTMODE)
6833 rb_raise(rb_eArgError, "both textmode and binmode specified");
6834 if (RTEST(v))
6835 *fmode |= FMODE_BINMODE;
6836 }
6837
6838 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6839 rb_raise(rb_eArgError, "both textmode and binmode specified");
6840 }
6841}
6842
6843void
6844rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6845 int *oflags_p, int *fmode_p, struct rb_io_encoding *convconfig_p)
6846{
6847 VALUE vmode;
6848 int oflags, fmode;
6849 rb_encoding *enc, *enc2;
6850 int ecflags;
6851 VALUE ecopts;
6852 int has_enc = 0, has_vmode = 0;
6853 VALUE intmode;
6854
6855 vmode = *vmode_p;
6856
6857 /* Set to defaults */
6858 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6859
6860 vmode_handle:
6861 if (NIL_P(vmode)) {
6862 fmode = FMODE_READABLE;
6863 oflags = O_RDONLY;
6864 }
6865 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6866 vmode = intmode;
6867 oflags = NUM2INT(intmode);
6868 fmode = rb_io_oflags_fmode(oflags);
6869 }
6870 else {
6871 const char *p;
6872
6873 SafeStringValue(vmode);
6874 p = StringValueCStr(vmode);
6875 fmode = rb_io_modestr_fmode(p);
6876 oflags = rb_io_fmode_oflags(fmode);
6877 p = strchr(p, ':');
6878 if (p) {
6879 has_enc = 1;
6880 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6881 }
6882 else {
6883 rb_encoding *e;
6884
6885 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6886 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6887 }
6888 }
6889
6890 if (NIL_P(opthash)) {
6891 ecflags = (fmode & FMODE_READABLE) ?
6892 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6893 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6894#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6895 ecflags |= (fmode & FMODE_WRITABLE) ?
6896 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6897 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6898#endif
6899 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6900 ecopts = Qnil;
6901 if (fmode & FMODE_BINMODE) {
6902#ifdef O_BINARY
6903 oflags |= O_BINARY;
6904#endif
6905 if (!has_enc)
6906 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6907 }
6908#if DEFAULT_TEXTMODE
6909 else if (NIL_P(vmode)) {
6910 fmode |= DEFAULT_TEXTMODE;
6911 }
6912#endif
6913 }
6914 else {
6915 VALUE v;
6916 if (!has_vmode) {
6917 v = rb_hash_aref(opthash, sym_mode);
6918 if (!NIL_P(v)) {
6919 if (!NIL_P(vmode)) {
6920 rb_raise(rb_eArgError, "mode specified twice");
6921 }
6922 has_vmode = 1;
6923 vmode = v;
6924 goto vmode_handle;
6925 }
6926 }
6927 v = rb_hash_aref(opthash, sym_flags);
6928 if (!NIL_P(v)) {
6929 v = rb_to_int(v);
6930 oflags |= NUM2INT(v);
6931 vmode = INT2NUM(oflags);
6932 fmode = rb_io_oflags_fmode(oflags);
6933 }
6934 extract_binmode(opthash, &fmode);
6935 if (fmode & FMODE_BINMODE) {
6936#ifdef O_BINARY
6937 oflags |= O_BINARY;
6938#endif
6939 if (!has_enc)
6940 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6941 }
6942#if DEFAULT_TEXTMODE
6943 else if (NIL_P(vmode)) {
6944 fmode |= DEFAULT_TEXTMODE;
6945 }
6946#endif
6947 v = rb_hash_aref(opthash, sym_perm);
6948 if (!NIL_P(v)) {
6949 if (vperm_p) {
6950 if (!NIL_P(*vperm_p)) {
6951 rb_raise(rb_eArgError, "perm specified twice");
6952 }
6953 *vperm_p = v;
6954 }
6955 else {
6956 /* perm no use, just ignore */
6957 }
6958 }
6959 ecflags = (fmode & FMODE_READABLE) ?
6960 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6961 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
6962#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6963 ecflags |= (fmode & FMODE_WRITABLE) ?
6964 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6965 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6966#endif
6967
6968 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6969 if (has_enc) {
6970 rb_raise(rb_eArgError, "encoding specified twice");
6971 }
6972 }
6973 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6974 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
6975 }
6976
6977 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6978
6979 *vmode_p = vmode;
6980
6981 *oflags_p = oflags;
6982 *fmode_p = fmode;
6983 convconfig_p->enc = enc;
6984 convconfig_p->enc2 = enc2;
6985 convconfig_p->ecflags = ecflags;
6986 convconfig_p->ecopts = ecopts;
6987}
6988
6989 struct sysopen_struct {
6990 VALUE fname;
6991 int oflags;
6992 mode_t perm;
6993};
6994
6995static void *
6996sysopen_func(void *ptr)
6997{
6998 const struct sysopen_struct *data = ptr;
6999 const char *fname = RSTRING_PTR(data->fname);
7000 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7001}
7002
7003static inline int
7004rb_sysopen_internal(struct sysopen_struct *data)
7005{
7006 int fd;
7007 fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
7008 if (0 <= fd)
7009 rb_update_max_fd(fd);
7010 return fd;
7011}
7012
7013static int
7014rb_sysopen(VALUE fname, int oflags, mode_t perm)
7015{
7016 int fd = -1;
7017 struct sysopen_struct data;
7018
7019 data.fname = rb_str_encode_ospath(fname);
7020 StringValueCStr(data.fname);
7021 data.oflags = oflags;
7022 data.perm = perm;
7023
7024 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7025 rb_syserr_fail_path(first_errno, fname);
7026 }
7027 return fd;
7028}
7029
7030static inline FILE *
7031fdopen_internal(int fd, const char *modestr)
7032{
7033 FILE *file;
7034
7035#if defined(__sun)
7036 errno = 0;
7037#endif
7038 file = fdopen(fd, modestr);
7039 if (!file) {
7040#ifdef _WIN32
7041 if (errno == 0) errno = EINVAL;
7042#elif defined(__sun)
7043 if (errno == 0) errno = EMFILE;
7044#endif
7045 }
7046 return file;
7047}
7048
7049FILE *
7050rb_fdopen(int fd, const char *modestr)
7051{
7052 FILE *file = 0;
7053
7054 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7055 rb_syserr_fail(first_errno, 0);
7056 }
7057
7058 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7059#ifdef USE_SETVBUF
7060 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7061 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7062#endif
7063 return file;
7064}
7065
7066static int
7067io_check_tty(rb_io_t *fptr)
7068{
7069 int t = isatty(fptr->fd);
7070 if (t)
7071 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7072 return t;
7073}
7074
7075static VALUE rb_io_internal_encoding(VALUE);
7076static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7077
7078static int
7079io_strip_bom(VALUE io)
7080{
7081 VALUE b1, b2, b3, b4;
7082 rb_io_t *fptr;
7083
7084 GetOpenFile(io, fptr);
7085 if (!(fptr->mode & FMODE_READABLE)) return 0;
7086 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7087 switch (b1) {
7088 case INT2FIX(0xEF):
7089 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7090 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7091 if (b3 == INT2FIX(0xBF)) {
7092 return rb_utf8_encindex();
7093 }
7094 rb_io_ungetbyte(io, b3);
7095 }
7096 rb_io_ungetbyte(io, b2);
7097 break;
7098
7099 case INT2FIX(0xFE):
7100 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7101 if (b2 == INT2FIX(0xFF)) {
7102 return ENCINDEX_UTF_16BE;
7103 }
7104 rb_io_ungetbyte(io, b2);
7105 break;
7106
7107 case INT2FIX(0xFF):
7108 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7109 if (b2 == INT2FIX(0xFE)) {
7110 b3 = rb_io_getbyte(io);
7111 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7112 if (b4 == INT2FIX(0)) {
7113 return ENCINDEX_UTF_32LE;
7114 }
7115 rb_io_ungetbyte(io, b4);
7116 }
7117 rb_io_ungetbyte(io, b3);
7118 return ENCINDEX_UTF_16LE;
7119 }
7120 rb_io_ungetbyte(io, b2);
7121 break;
7122
7123 case INT2FIX(0):
7124 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7125 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7126 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7127 if (b4 == INT2FIX(0xFF)) {
7128 return ENCINDEX_UTF_32BE;
7129 }
7130 rb_io_ungetbyte(io, b4);
7131 }
7132 rb_io_ungetbyte(io, b3);
7133 }
7134 rb_io_ungetbyte(io, b2);
7135 break;
7136 }
7137 rb_io_ungetbyte(io, b1);
7138 return 0;
7139}
7140
7141static rb_encoding *
7142io_set_encoding_by_bom(VALUE io)
7143{
7144 int idx = io_strip_bom(io);
7145 rb_io_t *fptr;
7146 rb_encoding *extenc = NULL;
7147
7148 GetOpenFile(io, fptr);
7149 if (idx) {
7150 extenc = rb_enc_from_index(idx);
7151 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7152 rb_io_internal_encoding(io), Qnil);
7153 }
7154 else {
7155 fptr->encs.enc2 = NULL;
7156 }
7157 return extenc;
7158}
7159
7160static VALUE
7161rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7162 const struct rb_io_encoding *convconfig, mode_t perm)
7163{
7164 VALUE pathv;
7165 rb_io_t *fptr;
7166 struct rb_io_encoding cc;
7167 if (!convconfig) {
7168 /* Set to default encodings */
7169 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7170 cc.ecflags = 0;
7171 cc.ecopts = Qnil;
7172 convconfig = &cc;
7173 }
7174 validate_enc_binmode(&fmode, convconfig->ecflags,
7175 convconfig->enc, convconfig->enc2);
7176
7177 MakeOpenFile(io, fptr);
7178 fptr->mode = fmode;
7179 fptr->encs = *convconfig;
7180 pathv = rb_str_new_frozen(filename);
7181#ifdef O_TMPFILE
7182 if (!(oflags & O_TMPFILE)) {
7183 fptr->pathv = pathv;
7184 }
7185#else
7186 fptr->pathv = pathv;
7187#endif
7188 fptr->fd = rb_sysopen(pathv, oflags, perm);
7189 io_check_tty(fptr);
7190 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7191
7192 return io;
7193}
7194
7195static VALUE
7196rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7197{
7198 int fmode = rb_io_modestr_fmode(modestr);
7199 const char *p = strchr(modestr, ':');
7200 struct rb_io_encoding convconfig;
7201
7202 if (p) {
7203 parse_mode_enc(p+1, rb_usascii_encoding(),
7204 &convconfig.enc, &convconfig.enc2, &fmode);
7205 convconfig.ecflags = 0;
7206 convconfig.ecopts = Qnil;
7207 }
7208 else {
7209 rb_encoding *e;
7210 /* Set to default encodings */
7211
7212 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7213 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7214 convconfig.ecflags = 0;
7215 convconfig.ecopts = Qnil;
7216 }
7217
7218 return rb_file_open_generic(io, filename,
7219 rb_io_fmode_oflags(fmode),
7220 fmode,
7221 &convconfig,
7222 0666);
7223}
7224
7225 VALUE
7226rb_file_open_str(VALUE fname, const char *modestr)
7227{
7228 FilePathValue(fname);
7229 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7230}
7231
7232 VALUE
7233rb_file_open(const char *fname, const char *modestr)
7234{
7235 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7236}
7237
7238#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7239 static struct pipe_list {
7240 rb_io_t *fptr;
7241 struct pipe_list *next;
7242} *pipe_list;
7243
7244static void
7245pipe_add_fptr(rb_io_t *fptr)
7246{
7247 struct pipe_list *list;
7248
7249 list = ALLOC(struct pipe_list);
7250 list->fptr = fptr;
7251 list->next = pipe_list;
7252 pipe_list = list;
7253}
7254
7255static void
7256pipe_del_fptr(rb_io_t *fptr)
7257{
7258 struct pipe_list **prev = &pipe_list;
7259 struct pipe_list *tmp;
7260
7261 while ((tmp = *prev) != 0) {
7262 if (tmp->fptr == fptr) {
7263 *prev = tmp->next;
7264 free(tmp);
7265 return;
7266 }
7267 prev = &tmp->next;
7268 }
7269}
7270
7271#if defined (_WIN32) || defined(__CYGWIN__)
7272static void
7273pipe_atexit(void)
7274{
7275 struct pipe_list *list = pipe_list;
7276 struct pipe_list *tmp;
7277
7278 while (list) {
7279 tmp = list->next;
7280 rb_io_fptr_finalize(list->fptr);
7281 list = tmp;
7282 }
7283}
7284#endif
7285
7286static void
7287pipe_finalize(rb_io_t *fptr, int noraise)
7288{
7289#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7290 int status = 0;
7291 if (fptr->stdio_file) {
7292 status = pclose(fptr->stdio_file);
7293 }
7294 fptr->fd = -1;
7295 fptr->stdio_file = 0;
7296 rb_last_status_set(status, fptr->pid);
7297#else
7298 fptr_finalize(fptr, noraise);
7299#endif
7300 pipe_del_fptr(fptr);
7301}
7302#endif
7303
7304static void
7305fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7306{
7307#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7308 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7309
7310 if (old_finalize == orig->finalize) return;
7311#endif
7312
7313 fptr->finalize = orig->finalize;
7314
7315#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7316 if (old_finalize != pipe_finalize) {
7317 struct pipe_list *list;
7318 for (list = pipe_list; list; list = list->next) {
7319 if (list->fptr == fptr) break;
7320 }
7321 if (!list) pipe_add_fptr(fptr);
7322 }
7323 else {
7324 pipe_del_fptr(fptr);
7325 }
7326#endif
7327}
7328
7329void
7330rb_io_synchronized(rb_io_t *fptr)
7331{
7332 rb_io_check_initialized(fptr);
7333 fptr->mode |= FMODE_SYNC;
7334}
7335
7336void
7337rb_io_unbuffered(rb_io_t *fptr)
7338{
7339 rb_io_synchronized(fptr);
7340}
7341
7342int
7343rb_pipe(int *pipes)
7344{
7345 int ret;
7346 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7347 if (ret == 0) {
7348 rb_update_max_fd(pipes[0]);
7349 rb_update_max_fd(pipes[1]);
7350 }
7351 return ret;
7352}
7353
7354#ifdef _WIN32
7355#define HAVE_SPAWNV 1
7356#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7357#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7358#endif
7359
7360#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7361struct popen_arg {
7362 VALUE execarg_obj;
7363 struct rb_execarg *eargp;
7364 int modef;
7365 int pair[2];
7366 int write_pair[2];
7367};
7368#endif
7369
7370#ifdef HAVE_WORKING_FORK
7371# ifndef __EMSCRIPTEN__
7372static void
7373popen_redirect(struct popen_arg *p)
7374{
7375 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7376 close(p->write_pair[1]);
7377 if (p->write_pair[0] != 0) {
7378 dup2(p->write_pair[0], 0);
7379 close(p->write_pair[0]);
7380 }
7381 close(p->pair[0]);
7382 if (p->pair[1] != 1) {
7383 dup2(p->pair[1], 1);
7384 close(p->pair[1]);
7385 }
7386 }
7387 else if (p->modef & FMODE_READABLE) {
7388 close(p->pair[0]);
7389 if (p->pair[1] != 1) {
7390 dup2(p->pair[1], 1);
7391 close(p->pair[1]);
7392 }
7393 }
7394 else {
7395 close(p->pair[1]);
7396 if (p->pair[0] != 0) {
7397 dup2(p->pair[0], 0);
7398 close(p->pair[0]);
7399 }
7400 }
7401}
7402# endif
7403
7404#if defined(__linux__)
7405/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7406 * Since /proc may not be available, linux_get_maxfd is just a hint.
7407 * This function, linux_get_maxfd, must be async-signal-safe.
7408 * I.e. opendir() is not usable.
7409 *
7410 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7411 * However they are easy to re-implement in async-signal-safe manner.
7412 * (Also note that there is missing/memcmp.c.)
7413 */
7414static int
7415linux_get_maxfd(void)
7416{
7417 int fd;
7418 char buf[4096], *p, *np, *e;
7419 ssize_t ss;
7420 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7421 if (fd < 0) return fd;
7422 ss = read(fd, buf, sizeof(buf));
7423 if (ss < 0) goto err;
7424 p = buf;
7425 e = buf + ss;
7426 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7427 (np = memchr(p, '\n', e-p)) != NULL) {
7428 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7429 int fdsize;
7430 p += sizeof("FDSize:")-1;
7431 *np = '\0';
7432 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7433 close(fd);
7434 return fdsize;
7435 }
7436 p = np+1;
7437 }
7438 /* fall through */
7439
7440 err:
7441 close(fd);
7442 return (int)ss;
7443}
7444#endif
7445
7446/* This function should be async-signal-safe. */
7447void
7448 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7449{
7450#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7451 int fd, ret;
7452 int max = (int)max_file_descriptor;
7453# ifdef F_MAXFD
7454 /* F_MAXFD is available since NetBSD 2.0. */
7455 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7456 if (ret != -1)
7457 maxhint = max = ret;
7458# elif defined(__linux__)
7459 ret = linux_get_maxfd();
7460 if (maxhint < ret)
7461 maxhint = ret;
7462 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7463# endif
7464 if (max < maxhint)
7465 max = maxhint;
7466 for (fd = lowfd; fd <= max; fd++) {
7467 if (!NIL_P(noclose_fds) &&
7468 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7469 continue;
7470 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7471 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7472 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7473 }
7474# define CONTIGUOUS_CLOSED_FDS 20
7475 if (ret != -1) {
7476 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7477 max = fd + CONTIGUOUS_CLOSED_FDS;
7478 }
7479 }
7480#endif
7481}
7482
7483# ifndef __EMSCRIPTEN__
7484static int
7485popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7486{
7487 struct popen_arg *p = (struct popen_arg*)pp;
7488
7489 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7490}
7491# endif
7492#endif
7493
7494#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7495static VALUE
7496rb_execarg_fixup_v(VALUE execarg_obj)
7497{
7498 rb_execarg_parent_start(execarg_obj);
7499 return Qnil;
7500}
7501#else
7502char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7503#endif
7504
7505#ifndef __EMSCRIPTEN__
7506static VALUE
7507pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7508 const struct rb_io_encoding *convconfig)
7509{
7510 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7511 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7512 rb_pid_t pid = 0;
7513 rb_io_t *fptr;
7514 VALUE port;
7515 rb_io_t *write_fptr;
7516 VALUE write_port;
7517#if defined(HAVE_WORKING_FORK)
7518 int status;
7519 char errmsg[80] = { '\0' };
7520#endif
7521#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7522 int state;
7523 struct popen_arg arg;
7524#endif
7525 int e = 0;
7526#if defined(HAVE_SPAWNV)
7527# if defined(HAVE_SPAWNVE)
7528# define DO_SPAWN(cmd, args, envp) ((args) ? \
7529 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7530 spawne(P_NOWAIT, (cmd), (envp)))
7531# else
7532# define DO_SPAWN(cmd, args, envp) ((args) ? \
7533 spawnv(P_NOWAIT, (cmd), (args)) : \
7534 spawn(P_NOWAIT, (cmd)))
7535# endif
7536# if !defined(HAVE_WORKING_FORK)
7537 char **args = NULL;
7538# if defined(HAVE_SPAWNVE)
7539 char **envp = NULL;
7540# endif
7541# endif
7542#endif
7543#if !defined(HAVE_WORKING_FORK)
7544 struct rb_execarg sarg, *sargp = &sarg;
7545#endif
7546 FILE *fp = 0;
7547 int fd = -1;
7548 int write_fd = -1;
7549#if !defined(HAVE_WORKING_FORK)
7550 const char *cmd = 0;
7551
7552 if (prog)
7553 cmd = StringValueCStr(prog);
7554#endif
7555
7556#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7557 arg.execarg_obj = execarg_obj;
7558 arg.eargp = eargp;
7559 arg.modef = fmode;
7560 arg.pair[0] = arg.pair[1] = -1;
7561 arg.write_pair[0] = arg.write_pair[1] = -1;
7562# if !defined(HAVE_WORKING_FORK)
7563 if (eargp && !eargp->use_shell) {
7564 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7565 }
7566# endif
7567 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7568 case FMODE_READABLE|FMODE_WRITABLE:
7569 if (rb_pipe(arg.write_pair) < 0)
7570 rb_sys_fail_str(prog);
7571 if (rb_pipe(arg.pair) < 0) {
7572 e = errno;
7573 close(arg.write_pair[0]);
7574 close(arg.write_pair[1]);
7575 rb_syserr_fail_str(e, prog);
7576 }
7577 if (eargp) {
7578 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7579 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7580 }
7581 break;
7582 case FMODE_READABLE:
7583 if (rb_pipe(arg.pair) < 0)
7584 rb_sys_fail_str(prog);
7585 if (eargp)
7586 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7587 break;
7588 case FMODE_WRITABLE:
7589 if (rb_pipe(arg.pair) < 0)
7590 rb_sys_fail_str(prog);
7591 if (eargp)
7592 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7593 break;
7594 default:
7595 rb_sys_fail_str(prog);
7596 }
7597 if (!NIL_P(execarg_obj)) {
7598 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7599 if (state) {
7600 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7601 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7602 if (0 <= arg.pair[0]) close(arg.pair[0]);
7603 if (0 <= arg.pair[1]) close(arg.pair[1]);
7604 rb_execarg_parent_end(execarg_obj);
7605 rb_jump_tag(state);
7606 }
7607
7608# if defined(HAVE_WORKING_FORK)
7609 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7610# else
7611 rb_execarg_run_options(eargp, sargp, NULL, 0);
7612# if defined(HAVE_SPAWNVE)
7613 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7614# endif
7615 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7616 /* exec failed */
7617 switch (e = errno) {
7618 case EAGAIN:
7619# if EWOULDBLOCK != EAGAIN
7620 case EWOULDBLOCK:
7621# endif
7622 rb_thread_sleep(1);
7623 continue;
7624 }
7625 break;
7626 }
7627 if (eargp)
7628 rb_execarg_run_options(sargp, NULL, NULL, 0);
7629# endif
7630 rb_execarg_parent_end(execarg_obj);
7631 }
7632 else {
7633# if defined(HAVE_WORKING_FORK)
7634 pid = rb_call_proc__fork();
7635 if (pid == 0) { /* child */
7636 popen_redirect(&arg);
7637 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7638 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7639 return Qnil;
7640 }
7641# else
7642 rb_notimplement();
7643# endif
7644 }
7645
7646 /* parent */
7647 if (pid < 0) {
7648# if defined(HAVE_WORKING_FORK)
7649 e = errno;
7650# endif
7651 close(arg.pair[0]);
7652 close(arg.pair[1]);
7653 if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) {
7654 close(arg.write_pair[0]);
7655 close(arg.write_pair[1]);
7656 }
7657# if defined(HAVE_WORKING_FORK)
7658 if (errmsg[0])
7659 rb_syserr_fail(e, errmsg);
7660# endif
7661 rb_syserr_fail_str(e, prog);
7662 }
7663 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7664 close(arg.pair[1]);
7665 fd = arg.pair[0];
7666 close(arg.write_pair[0]);
7667 write_fd = arg.write_pair[1];
7668 }
7669 else if (fmode & FMODE_READABLE) {
7670 close(arg.pair[1]);
7671 fd = arg.pair[0];
7672 }
7673 else {
7674 close(arg.pair[0]);
7675 fd = arg.pair[1];
7676 }
7677#else
7678 cmd = rb_execarg_commandline(eargp, &prog);
7679 if (!NIL_P(execarg_obj)) {
7680 rb_execarg_parent_start(execarg_obj);
7681 rb_execarg_run_options(eargp, sargp, NULL, 0);
7682 }
7683 fp = popen(cmd, modestr);
7684 e = errno;
7685 if (eargp) {
7686 rb_execarg_parent_end(execarg_obj);
7687 rb_execarg_run_options(sargp, NULL, NULL, 0);
7688 }
7689 if (!fp) rb_syserr_fail_path(e, prog);
7690 fd = fileno(fp);
7691#endif
7692
7693 port = io_alloc(rb_cIO);
7694 MakeOpenFile(port, fptr);
7695 fptr->fd = fd;
7696 fptr->stdio_file = fp;
7697 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7698 if (convconfig) {
7699 fptr->encs = *convconfig;
7700#if RUBY_CRLF_ENVIRONMENT
7701 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
7702 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7703 }
7704#endif
7705 }
7706 else {
7707 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7708 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
7709 }
7710#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7711 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7712 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7713 }
7714#endif
7715 }
7716 fptr->pid = pid;
7717
7718 if (0 <= write_fd) {
7719 write_port = io_alloc(rb_cIO);
7720 MakeOpenFile(write_port, write_fptr);
7721 write_fptr->fd = write_fd;
7722 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7723 fptr->mode &= ~FMODE_WRITABLE;
7724 fptr->tied_io_for_writing = write_port;
7725 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7726 }
7727
7728#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7729 fptr->finalize = pipe_finalize;
7730 pipe_add_fptr(fptr);
7731#endif
7732 return port;
7733}
7734#else
7735static VALUE
7736pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7737 const struct rb_io_encoding *convconfig)
7738{
7739 rb_raise(rb_eNotImpError, "popen() is not available");
7740}
7741#endif
7742
7743static int
7744is_popen_fork(VALUE prog)
7745{
7746 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7747#if !defined(HAVE_WORKING_FORK)
7748 rb_raise(rb_eNotImpError,
7749 "fork() function is unimplemented on this machine");
7750#else
7751 return TRUE;
7752#endif
7753 }
7754 return FALSE;
7755}
7756
7757static VALUE
7758pipe_open_s(VALUE prog, const char *modestr, int fmode,
7759 const struct rb_io_encoding *convconfig)
7760{
7761 int argc = 1;
7762 VALUE *argv = &prog;
7763 VALUE execarg_obj = Qnil;
7764
7765 if (!is_popen_fork(prog))
7766 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7767 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7768}
7769
7770static VALUE
7771pipe_close(VALUE io)
7772{
7773 rb_io_t *fptr = io_close_fptr(io);
7774 if (fptr) {
7775 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7776 }
7777 return Qnil;
7778}
7779
7780static VALUE popen_finish(VALUE port, VALUE klass);
7781
7782/*
7783 * call-seq:
7784 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7785 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7786 *
7787 * Executes the given command +cmd+ as a subprocess
7788 * whose $stdin and $stdout are connected to a new stream +io+.
7789 *
7790 * This method has potential security vulnerabilities if called with untrusted input;
7791 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7792 *
7793 * If no block is given, returns the new stream,
7794 * which depending on given +mode+ may be open for reading, writing, or both.
7795 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7796 *
7797 * If a block is given, the stream is passed to the block
7798 * (again, open for reading, writing, or both);
7799 * when the block exits, the stream is closed,
7800 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7801 *
7802 * Optional argument +mode+ may be any valid \IO mode.
7803 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7804 *
7805 * Required argument +cmd+ determines which of the following occurs:
7806 *
7807 * - The process forks.
7808 * - A specified program runs in a shell.
7809 * - A specified program runs with specified arguments.
7810 * - A specified program runs with specified arguments and a specified +argv0+.
7811 *
7812 * Each of these is detailed below.
7813 *
7814 * The optional hash argument +env+ specifies name/value pairs that are to be added
7815 * to the environment variables for the subprocess:
7816 *
7817 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7818 * pipe.puts 'puts ENV["FOO"]'
7819 * pipe.close_write
7820 * pipe.gets
7821 * end => "bar\n"
7822 *
7823 * Optional keyword arguments +opts+ specify:
7824 *
7825 * - {Open options}[rdoc-ref:IO@Open+Options].
7826 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7827 * - Options for Kernel#spawn.
7828 *
7829 * <b>Forked \Process</b>
7830 *
7831 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7832 * IO.popen('-') do |pipe|
7833 * if pipe
7834 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7835 * else
7836 * $stderr.puts "In child, pid is #{$$}\n"
7837 * end
7838 * end
7839 *
7840 * Output:
7841 *
7842 * In parent, child pid is 26253
7843 * In child, pid is 26253
7844 *
7845 * Note that this is not supported on all platforms.
7846 *
7847 * <b>Shell Subprocess</b>
7848 *
7849 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7850 * the program named +cmd+ is run as a shell command:
7851 *
7852 * IO.popen('uname') do |pipe|
7853 * pipe.readlines
7854 * end
7855 *
7856 * Output:
7857 *
7858 * ["Linux\n"]
7859 *
7860 * Another example:
7861 *
7862 * IO.popen('/bin/sh', 'r+') do |pipe|
7863 * pipe.puts('ls')
7864 * pipe.close_write
7865 * $stderr.puts pipe.readlines.size
7866 * end
7867 *
7868 * Output:
7869 *
7870 * 213
7871 *
7872 * <b>Program Subprocess</b>
7873 *
7874 * When argument +cmd+ is an array of strings,
7875 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7876 *
7877 * IO.popen(['du', '..', '.']) do |pipe|
7878 * $stderr.puts pipe.readlines.size
7879 * end
7880 *
7881 * Output:
7882 *
7883 * 1111
7884 *
7885 * <b>Program Subprocess with <tt>argv0</tt></b>
7886 *
7887 * When argument +cmd+ is an array whose first element is a 2-element string array
7888 * and whose remaining elements (if any) are strings:
7889 *
7890 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7891 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7892 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7893 *
7894 * Example (sets <tt>$0</tt> to 'foo'):
7895 *
7896 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7897 *
7898 * <b>Some Special Examples</b>
7899 *
7900 * # Set IO encoding.
7901 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7902 * euc_jp_string = nkf_io.read
7903 * }
7904 *
7905 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7906 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7907 * ls_result_with_error = io.read
7908 * end
7909 *
7910 * # Use mixture of spawn options and IO options.
7911 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7912 * ls_result_with_error = io.read
7913 * end
7914 *
7915 * f = IO.popen("uname")
7916 * p f.readlines
7917 * f.close
7918 * puts "Parent is #{Process.pid}"
7919 * IO.popen("date") {|f| puts f.gets }
7920 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7921 * p $?
7922 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7923 * f.puts "bar"; f.close_write; puts f.gets
7924 * }
7925 *
7926 * Output (from last section):
7927 *
7928 * ["Linux\n"]
7929 * Parent is 21346
7930 * Thu Jan 15 22:41:19 JST 2009
7931 * 21346 is here, f is #<IO:fd 3>
7932 * 21352 is here, f is nil
7933 * #<Process::Status: pid 21352 exit 0>
7934 * <foo>bar;zot;
7935 *
7936 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7937 *
7938 */
7939
7940static VALUE
7941rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7942{
7943 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7944
7945 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7946 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7947 switch (argc) {
7948 case 2:
7949 pmode = argv[1];
7950 case 1:
7951 pname = argv[0];
7952 break;
7953 default:
7954 {
7955 int ex = !NIL_P(opt);
7956 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7957 }
7958 }
7959 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7960}
7961
7962 VALUE
7963rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7964{
7965 const char *modestr;
7966 VALUE tmp, execarg_obj = Qnil;
7967 int oflags, fmode;
7968 struct rb_io_encoding convconfig;
7969
7970 tmp = rb_check_array_type(pname);
7971 if (!NIL_P(tmp)) {
7972 long len = RARRAY_LEN(tmp);
7973#if SIZEOF_LONG > SIZEOF_INT
7974 if (len > INT_MAX) {
7975 rb_raise(rb_eArgError, "too many arguments");
7976 }
7977#endif
7978 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7979 RB_GC_GUARD(tmp);
7980 }
7981 else {
7982 SafeStringValue(pname);
7983 execarg_obj = Qnil;
7984 if (!is_popen_fork(pname))
7985 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7986 }
7987 if (!NIL_P(execarg_obj)) {
7988 if (!NIL_P(opt))
7989 opt = rb_execarg_extract_options(execarg_obj, opt);
7990 if (!NIL_P(env))
7991 rb_execarg_setenv(execarg_obj, env);
7992 }
7993 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
7994 modestr = rb_io_oflags_modestr(oflags);
7995
7996 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7997}
7998
7999static VALUE
8000popen_finish(VALUE port, VALUE klass)
8001{
8002 if (NIL_P(port)) {
8003 /* child */
8004 if (rb_block_given_p()) {
8005 rb_protect(rb_yield, Qnil, NULL);
8006 rb_io_flush(rb_ractor_stdout());
8007 rb_io_flush(rb_ractor_stderr());
8008 _exit(0);
8009 }
8010 return Qnil;
8011 }
8012 RBASIC_SET_CLASS(port, klass);
8013 if (rb_block_given_p()) {
8014 return rb_ensure(rb_yield, port, pipe_close, port);
8015 }
8016 return port;
8017}
8018
8019#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8020struct popen_writer_arg {
8021 char *const *argv;
8022 struct popen_arg popen;
8023};
8024
8025static int
8026exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8027{
8028 struct popen_writer_arg *pw = arg;
8029 pw->popen.modef = FMODE_WRITABLE;
8030 popen_redirect(&pw->popen);
8031 execv(pw->argv[0], pw->argv);
8032 strlcpy(errmsg, strerror(errno), buflen);
8033 return -1;
8034}
8035#endif
8036
8037FILE *
8038ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8039{
8040#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8041# ifdef HAVE_WORKING_FORK
8042 struct popen_writer_arg pw;
8043 int *const write_pair = pw.popen.pair;
8044# else
8045 int write_pair[2];
8046# endif
8047
8048 int result = rb_cloexec_pipe(write_pair);
8049 *pid = -1;
8050 if (result == 0) {
8051# ifdef HAVE_WORKING_FORK
8052 pw.argv = argv;
8053 int status;
8054 char errmsg[80] = {'\0'};
8055 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8056# else
8057 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8058 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8059# endif
8060 close(write_pair[0]);
8061 if (*pid < 0) {
8062 close(write_pair[1]);
8063 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8064 }
8065 else {
8066 return fdopen(write_pair[1], "w");
8067 }
8068 }
8069#endif
8070 return NULL;
8071}
8072
8073static void
8074rb_scan_open_args(int argc, const VALUE *argv,
8075 VALUE *fname_p, int *oflags_p, int *fmode_p,
8076 struct rb_io_encoding *convconfig_p, mode_t *perm_p)
8077{
8078 VALUE opt, fname, vmode, vperm;
8079 int oflags, fmode;
8080 mode_t perm;
8081
8082 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
8083 FilePathValue(fname);
8084
8085 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
8086
8087 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8088
8089 *fname_p = fname;
8090 *oflags_p = oflags;
8091 *fmode_p = fmode;
8092 *perm_p = perm;
8093}
8094
8095static VALUE
8096rb_open_file(int argc, const VALUE *argv, VALUE io)
8097{
8098 VALUE fname;
8099 int oflags, fmode;
8100 struct rb_io_encoding convconfig;
8101 mode_t perm;
8102
8103 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
8104 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8105
8106 return io;
8107}
8108
8109/*
8110 * Document-method: File::open
8111 *
8112 * call-seq:
8113 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8114 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8115 *
8116 * Creates a new File object, via File.new with the given arguments.
8117 *
8118 * With no block given, returns the File object.
8119 *
8120 * With a block given, calls the block with the File object
8121 * and returns the block's value.
8122 *
8123 */
8124
8125/*
8126 * Document-method: IO::open
8127 *
8128 * call-seq:
8129 * IO.open(fd, mode = 'r', **opts) -> io
8130 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8131 *
8132 * Creates a new \IO object, via IO.new with the given arguments.
8133 *
8134 * With no block given, returns the \IO object.
8135 *
8136 * With a block given, calls the block with the \IO object
8137 * and returns the block's value.
8138 *
8139 */
8140
8141static VALUE
8142rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8143{
8144 VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
8145
8146 if (rb_block_given_p()) {
8147 return rb_ensure(rb_yield, io, io_close, io);
8148 }
8149
8150 return io;
8151}
8152
8153/*
8154 * call-seq:
8155 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8156 *
8157 * Opens the file at the given path with the given mode and permissions;
8158 * returns the integer file descriptor.
8159 *
8160 * If the file is to be readable, it must exist;
8161 * if the file is to be writable and does not exist,
8162 * it is created with the given permissions:
8163 *
8164 * File.write('t.tmp', '') # => 0
8165 * IO.sysopen('t.tmp') # => 8
8166 * IO.sysopen('t.tmp', 'w') # => 9
8167 *
8168 *
8169 */
8170
8171static VALUE
8172rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8173{
8174 VALUE fname, vmode, vperm;
8175 VALUE intmode;
8176 int oflags, fd;
8177 mode_t perm;
8178
8179 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8180 FilePathValue(fname);
8181
8182 if (NIL_P(vmode))
8183 oflags = O_RDONLY;
8184 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8185 oflags = NUM2INT(intmode);
8186 else {
8187 SafeStringValue(vmode);
8188 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8189 }
8190 if (NIL_P(vperm)) perm = 0666;
8191 else perm = NUM2MODET(vperm);
8192
8193 RB_GC_GUARD(fname) = rb_str_new4(fname);
8194 fd = rb_sysopen(fname, oflags, perm);
8195 return INT2NUM(fd);
8196}
8197
8198static VALUE
8199check_pipe_command(VALUE filename_or_command)
8200{
8201 char *s = RSTRING_PTR(filename_or_command);
8202 long l = RSTRING_LEN(filename_or_command);
8203 char *e = s + l;
8204 int chlen;
8205
8206 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8207 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8208 return cmd;
8209 }
8210 return Qnil;
8211}
8212
8213/*
8214 * call-seq:
8215 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8216 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8217 *
8218 * Creates an IO object connected to the given file.
8219 *
8220 * This method has potential security vulnerabilities if called with untrusted input;
8221 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8222 *
8223 * With no block given, file stream is returned:
8224 *
8225 * open('t.txt') # => #<File:t.txt>
8226 *
8227 * With a block given, calls the block with the open file stream,
8228 * then closes the stream:
8229 *
8230 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8231 *
8232 * Output:
8233 *
8234 * #<File:t.txt>
8235 *
8236 * See File.open for details.
8237 *
8238 */
8239
8240static VALUE
8241rb_f_open(int argc, VALUE *argv, VALUE _)
8242{
8243 ID to_open = 0;
8244 int redirect = FALSE;
8245
8246 if (argc >= 1) {
8247 CONST_ID(to_open, "to_open");
8248 if (rb_respond_to(argv[0], to_open)) {
8249 redirect = TRUE;
8250 }
8251 else {
8252 VALUE tmp = argv[0];
8253 FilePathValue(tmp);
8254 if (NIL_P(tmp)) {
8255 redirect = TRUE;
8256 }
8257 else {
8258 VALUE cmd = check_pipe_command(tmp);
8259 if (!NIL_P(cmd)) {
8260 // TODO: when removed in 4.0, update command_injection.rdoc
8261 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8262 argv[0] = cmd;
8263 return rb_io_s_popen(argc, argv, rb_cIO);
8264 }
8265 }
8266 }
8267 }
8268 if (redirect) {
8269 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8270
8271 if (rb_block_given_p()) {
8272 return rb_ensure(rb_yield, io, io_close, io);
8273 }
8274 return io;
8275 }
8276 return rb_io_s_open(argc, argv, rb_cFile);
8277}
8278
8279static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const struct rb_io_encoding *, mode_t);
8280
8281static VALUE
8282rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8283{
8284 int oflags, fmode;
8285 struct rb_io_encoding convconfig;
8286 mode_t perm;
8287
8288 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8289 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8290 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8291}
8292
8293static VALUE
8294rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8295 const struct rb_io_encoding *convconfig, mode_t perm)
8296{
8297 VALUE cmd;
8298 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8299 // TODO: when removed in 4.0, update command_injection.rdoc
8300 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8301 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8302 }
8303 else {
8304 return rb_file_open_generic(io_alloc(klass), filename,
8305 oflags, fmode, convconfig, perm);
8306 }
8307}
8308
8309static VALUE
8310io_reopen(VALUE io, VALUE nfile)
8311{
8312 rb_io_t *fptr, *orig;
8313 int fd, fd2;
8314 rb_off_t pos = 0;
8315
8316 nfile = rb_io_get_io(nfile);
8317 GetOpenFile(io, fptr);
8318 GetOpenFile(nfile, orig);
8319
8320 if (fptr == orig) return io;
8321 if (RUBY_IO_EXTERNAL_P(fptr)) {
8322 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8323 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8324 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8325 rb_raise(rb_eArgError,
8326 "%s can't change access mode from \"%s\" to \"%s\"",
8327 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8328 rb_io_fmode_modestr(orig->mode));
8329 }
8330 }
8331 if (fptr->mode & FMODE_WRITABLE) {
8332 if (io_fflush(fptr) < 0)
8333 rb_sys_fail_on_write(fptr);
8334 }
8335 else {
8336 flush_before_seek(fptr);
8337 }
8338 if (orig->mode & FMODE_READABLE) {
8339 pos = io_tell(orig);
8340 }
8341 if (orig->mode & FMODE_WRITABLE) {
8342 if (io_fflush(orig) < 0)
8343 rb_sys_fail_on_write(fptr);
8344 }
8345
8346 /* copy rb_io_t structure */
8347 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8348 fptr->pid = orig->pid;
8349 fptr->lineno = orig->lineno;
8350 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8351 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8352 fptr_copy_finalizer(fptr, orig);
8353
8354 fd = fptr->fd;
8355 fd2 = orig->fd;
8356 if (fd != fd2) {
8357 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8358 /* need to keep FILE objects of stdin, stdout and stderr */
8359 if (rb_cloexec_dup2(fd2, fd) < 0)
8360 rb_sys_fail_path(orig->pathv);
8361 rb_update_max_fd(fd);
8362 }
8363 else {
8364 fclose(fptr->stdio_file);
8365 fptr->stdio_file = 0;
8366 fptr->fd = -1;
8367 if (rb_cloexec_dup2(fd2, fd) < 0)
8368 rb_sys_fail_path(orig->pathv);
8369 rb_update_max_fd(fd);
8370 fptr->fd = fd;
8371 }
8372 rb_thread_fd_close(fd);
8373 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8374 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8375 rb_sys_fail_path(fptr->pathv);
8376 }
8377 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8378 rb_sys_fail_path(orig->pathv);
8379 }
8380 }
8381 }
8382
8383 if (fptr->mode & FMODE_BINMODE) {
8384 rb_io_binmode(io);
8385 }
8386
8387 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8388 return io;
8389}
8390
8391#ifdef _WIN32
8392int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8393#else
8394static int
8395rb_freopen(VALUE fname, const char *mode, FILE *fp)
8396{
8397 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8398 RB_GC_GUARD(fname);
8399 return errno;
8400 }
8401 return 0;
8402}
8403#endif
8404
8405/*
8406 * call-seq:
8407 * reopen(other_io) -> self
8408 * reopen(path, mode = 'r', **opts) -> self
8409 *
8410 * Reassociates the stream with another stream,
8411 * which may be of a different class.
8412 * This method may be used to redirect an existing stream
8413 * to a new destination.
8414 *
8415 * With argument +other_io+ given, reassociates with that stream:
8416 *
8417 * # Redirect $stdin from a file.
8418 * f = File.open('t.txt')
8419 * $stdin.reopen(f)
8420 * f.close
8421 *
8422 * # Redirect $stdout to a file.
8423 * f = File.open('t.tmp', 'w')
8424 * $stdout.reopen(f)
8425 * f.close
8426 *
8427 * With argument +path+ given, reassociates with a new stream to that file path:
8428 *
8429 * $stdin.reopen('t.txt')
8430 * $stdout.reopen('t.tmp', 'w')
8431 *
8432 * Optional keyword arguments +opts+ specify:
8433 *
8434 * - {Open Options}[rdoc-ref:IO@Open+Options].
8435 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8436 *
8437 */
8438
8439static VALUE
8440rb_io_reopen(int argc, VALUE *argv, VALUE file)
8441{
8442 VALUE fname, nmode, opt;
8443 int oflags;
8444 rb_io_t *fptr;
8445
8446 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8447 VALUE tmp = rb_io_check_io(fname);
8448 if (!NIL_P(tmp)) {
8449 return io_reopen(file, tmp);
8450 }
8451 }
8452
8453 FilePathValue(fname);
8454 rb_io_taint_check(file);
8455 fptr = RFILE(file)->fptr;
8456 if (!fptr) {
8457 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8458 }
8459
8460 if (!NIL_P(nmode) || !NIL_P(opt)) {
8461 int fmode;
8462 struct rb_io_encoding convconfig;
8463
8464 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8465 if (RUBY_IO_EXTERNAL_P(fptr) &&
8466 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8467 (fptr->mode & FMODE_READWRITE)) {
8468 rb_raise(rb_eArgError,
8469 "%s can't change access mode from \"%s\" to \"%s\"",
8470 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8471 rb_io_fmode_modestr(fmode));
8472 }
8473 fptr->mode = fmode;
8474 fptr->encs = convconfig;
8475 }
8476 else {
8477 oflags = rb_io_fmode_oflags(fptr->mode);
8478 }
8479
8480 fptr->pathv = fname;
8481 if (fptr->fd < 0) {
8482 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8483 fptr->stdio_file = 0;
8484 return file;
8485 }
8486
8487 if (fptr->mode & FMODE_WRITABLE) {
8488 if (io_fflush(fptr) < 0)
8489 rb_sys_fail_on_write(fptr);
8490 }
8491 fptr->rbuf.off = fptr->rbuf.len = 0;
8492
8493 if (fptr->stdio_file) {
8494 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8495 rb_io_oflags_modestr(oflags),
8496 fptr->stdio_file);
8497 if (e) rb_syserr_fail_path(e, fptr->pathv);
8498 fptr->fd = fileno(fptr->stdio_file);
8499 rb_fd_fix_cloexec(fptr->fd);
8500#ifdef USE_SETVBUF
8501 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8502 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8503#endif
8504 if (fptr->stdio_file == stderr) {
8505 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8506 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8507 }
8508 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8509 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8510 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8511 }
8512 }
8513 else {
8514 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8515 int err = 0;
8516 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8517 err = errno;
8518 (void)close(tmpfd);
8519 if (err) {
8520 rb_syserr_fail_path(err, fptr->pathv);
8521 }
8522 }
8523
8524 return file;
8525}
8526
8527/* :nodoc: */
8528static VALUE
8529rb_io_init_copy(VALUE dest, VALUE io)
8530{
8531 rb_io_t *fptr, *orig;
8532 int fd;
8533 VALUE write_io;
8534 rb_off_t pos;
8535
8536 io = rb_io_get_io(io);
8537 if (!OBJ_INIT_COPY(dest, io)) return dest;
8538 GetOpenFile(io, orig);
8539 MakeOpenFile(dest, fptr);
8540
8541 rb_io_flush(io);
8542
8543 /* copy rb_io_t structure */
8544 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8545 fptr->encs = orig->encs;
8546 fptr->pid = orig->pid;
8547 fptr->lineno = orig->lineno;
8548 fptr->timeout = orig->timeout;
8549 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8550 fptr_copy_finalizer(fptr, orig);
8551
8552 fd = ruby_dup(orig->fd);
8553 fptr->fd = fd;
8554 pos = io_tell(orig);
8555 if (0 <= pos)
8556 io_seek(fptr, pos, SEEK_SET);
8557 if (fptr->mode & FMODE_BINMODE) {
8558 rb_io_binmode(dest);
8559 }
8560
8561 write_io = GetWriteIO(io);
8562 if (io != write_io) {
8563 write_io = rb_obj_dup(write_io);
8564 fptr->tied_io_for_writing = write_io;
8565 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8566 }
8567
8568 return dest;
8569}
8570
8571/*
8572 * call-seq:
8573 * printf(format_string, *objects) -> nil
8574 *
8575 * Formats and writes +objects+ to the stream.
8576 *
8577 * For details on +format_string+, see
8578 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8579 *
8580 */
8581
8582 VALUE
8583rb_io_printf(int argc, const VALUE *argv, VALUE out)
8584{
8585 rb_io_write(out, rb_f_sprintf(argc, argv));
8586 return Qnil;
8587}
8588
8589/*
8590 * call-seq:
8591 * printf(format_string, *objects) -> nil
8592 * printf(io, format_string, *objects) -> nil
8593 *
8594 * Equivalent to:
8595 *
8596 * io.write(sprintf(format_string, *objects))
8597 *
8598 * For details on +format_string+, see
8599 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8600 *
8601 * With the single argument +format_string+, formats +objects+ into the string,
8602 * then writes the formatted string to $stdout:
8603 *
8604 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8605 *
8606 * Output (on $stdout):
8607 *
8608 * 0024 24 24.00#
8609 *
8610 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8611 * then writes the formatted string to +io+:
8612 *
8613 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8614 *
8615 * Output (on $stderr):
8616 *
8617 * 0024 24 24.00# => nil
8618 *
8619 * With no arguments, does nothing.
8620 *
8621 */
8622
8623static VALUE
8624rb_f_printf(int argc, VALUE *argv, VALUE _)
8625{
8626 VALUE out;
8627
8628 if (argc == 0) return Qnil;
8629 if (RB_TYPE_P(argv[0], T_STRING)) {
8630 out = rb_ractor_stdout();
8631 }
8632 else {
8633 out = argv[0];
8634 argv++;
8635 argc--;
8636 }
8637 rb_io_write(out, rb_f_sprintf(argc, argv));
8638
8639 return Qnil;
8640}
8641
8642static void
8643deprecated_str_setter(VALUE val, ID id, VALUE *var)
8644{
8645 rb_str_setter(val, id, &val);
8646 if (!NIL_P(val)) {
8647 rb_warn_deprecated("`%s'", NULL, rb_id2name(id));
8648 }
8649 *var = val;
8650}
8651
8652/*
8653 * call-seq:
8654 * print(*objects) -> nil
8655 *
8656 * Writes the given objects to the stream; returns +nil+.
8657 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8658 * (<tt>$\</tt>), if it is not +nil+.
8659 * See {Line IO}[rdoc-ref:IO@Line+IO].
8660 *
8661 * With argument +objects+ given, for each object:
8662 *
8663 * - Converts via its method +to_s+ if not a string.
8664 * - Writes to the stream.
8665 * - If not the last object, writes the output field separator
8666 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8667 *
8668 * With default separators:
8669 *
8670 * f = File.open('t.tmp', 'w+')
8671 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8672 * p $OUTPUT_RECORD_SEPARATOR
8673 * p $OUTPUT_FIELD_SEPARATOR
8674 * f.print(*objects)
8675 * f.rewind
8676 * p f.read
8677 * f.close
8678 *
8679 * Output:
8680 *
8681 * nil
8682 * nil
8683 * "00.00/10+0izerozero"
8684 *
8685 * With specified separators:
8686 *
8687 * $\ = "\n"
8688 * $, = ','
8689 * f.rewind
8690 * f.print(*objects)
8691 * f.rewind
8692 * p f.read
8693 *
8694 * Output:
8695 *
8696 * "0,0.0,0/1,0+0i,zero,zero\n"
8697 *
8698 * With no argument given, writes the content of <tt>$_</tt>
8699 * (which is usually the most recent user input):
8700 *
8701 * f = File.open('t.tmp', 'w+')
8702 * gets # Sets $_ to the most recent user input.
8703 * f.print
8704 * f.close
8705 *
8706 */
8707
8708 VALUE
8709rb_io_print(int argc, const VALUE *argv, VALUE out)
8710{
8711 int i;
8712 VALUE line;
8713
8714 /* if no argument given, print `$_' */
8715 if (argc == 0) {
8716 argc = 1;
8717 line = rb_lastline_get();
8718 argv = &line;
8719 }
8720 if (argc > 1 && !NIL_P(rb_output_fs)) {
8721 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8722 }
8723 for (i=0; i<argc; i++) {
8724 if (!NIL_P(rb_output_fs) && i>0) {
8725 rb_io_write(out, rb_output_fs);
8726 }
8727 rb_io_write(out, argv[i]);
8728 }
8729 if (argc > 0 && !NIL_P(rb_output_rs)) {
8730 rb_io_write(out, rb_output_rs);
8731 }
8732
8733 return Qnil;
8734}
8735
8736/*
8737 * call-seq:
8738 * print(*objects) -> nil
8739 *
8740 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8741 * this method is the straightforward way to write to <tt>$stdout</tt>.
8742 *
8743 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8744 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8745 * <tt>$\</tt>), if it is not +nil+.
8746 *
8747 * With argument +objects+ given, for each object:
8748 *
8749 * - Converts via its method +to_s+ if not a string.
8750 * - Writes to <tt>stdout</tt>.
8751 * - If not the last object, writes the output field separator
8752 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8753 *
8754 * With default separators:
8755 *
8756 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8757 * $OUTPUT_RECORD_SEPARATOR
8758 * $OUTPUT_FIELD_SEPARATOR
8759 * print(*objects)
8760 *
8761 * Output:
8762 *
8763 * nil
8764 * nil
8765 * 00.00/10+0izerozero
8766 *
8767 * With specified separators:
8768 *
8769 * $OUTPUT_RECORD_SEPARATOR = "\n"
8770 * $OUTPUT_FIELD_SEPARATOR = ','
8771 * print(*objects)
8772 *
8773 * Output:
8774 *
8775 * 0,0.0,0/1,0+0i,zero,zero
8776 *
8777 * With no argument given, writes the content of <tt>$_</tt>
8778 * (which is usually the most recent user input):
8779 *
8780 * gets # Sets $_ to the most recent user input.
8781 * print # Prints $_.
8782 *
8783 */
8784
8785static VALUE
8786rb_f_print(int argc, const VALUE *argv, VALUE _)
8787{
8788 rb_io_print(argc, argv, rb_ractor_stdout());
8789 return Qnil;
8790}
8791
8792/*
8793 * call-seq:
8794 * putc(object) -> object
8795 *
8796 * Writes a character to the stream.
8797 * See {Character IO}[rdoc-ref:IO@Character+IO].
8798 *
8799 * If +object+ is numeric, converts to integer if necessary,
8800 * then writes the character whose code is the
8801 * least significant byte;
8802 * if +object+ is a string, writes the first character:
8803 *
8804 * $stdout.putc "A"
8805 * $stdout.putc 65
8806 *
8807 * Output:
8808 *
8809 * AA
8810 *
8811 */
8812
8813static VALUE
8814rb_io_putc(VALUE io, VALUE ch)
8815{
8816 VALUE str;
8817 if (RB_TYPE_P(ch, T_STRING)) {
8818 str = rb_str_substr(ch, 0, 1);
8819 }
8820 else {
8821 char c = NUM2CHR(ch);
8822 str = rb_str_new(&c, 1);
8823 }
8824 rb_io_write(io, str);
8825 return ch;
8826}
8827
8828#define forward(obj, id, argc, argv) \
8829 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8830#define forward_public(obj, id, argc, argv) \
8831 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8832#define forward_current(id, argc, argv) \
8833 forward_public(ARGF.current_file, id, argc, argv)
8834
8835/*
8836 * call-seq:
8837 * putc(int) -> int
8838 *
8839 * Equivalent to:
8840 *
8841 * $stdout.putc(int)
8842 *
8843 * See IO#putc for important information regarding multi-byte characters.
8844 *
8845 */
8846
8847static VALUE
8848rb_f_putc(VALUE recv, VALUE ch)
8849{
8850 VALUE r_stdout = rb_ractor_stdout();
8851 if (recv == r_stdout) {
8852 return rb_io_putc(recv, ch);
8853 }
8854 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8855}
8856
8857
8858int
8859rb_str_end_with_asciichar(VALUE str, int c)
8860{
8861 long len = RSTRING_LEN(str);
8862 const char *ptr = RSTRING_PTR(str);
8863 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8864 int n;
8865
8866 if (len == 0) return 0;
8867 if ((n = rb_enc_mbminlen(enc)) == 1) {
8868 return ptr[len - 1] == c;
8869 }
8870 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8871}
8872
8873static VALUE
8874io_puts_ary(VALUE ary, VALUE out, int recur)
8875{
8876 VALUE tmp;
8877 long i;
8878
8879 if (recur) {
8880 tmp = rb_str_new2("[...]");
8881 rb_io_puts(1, &tmp, out);
8882 return Qtrue;
8883 }
8884 ary = rb_check_array_type(ary);
8885 if (NIL_P(ary)) return Qfalse;
8886 for (i=0; i<RARRAY_LEN(ary); i++) {
8887 tmp = RARRAY_AREF(ary, i);
8888 rb_io_puts(1, &tmp, out);
8889 }
8890 return Qtrue;
8891}
8892
8893/*
8894 * call-seq:
8895 * puts(*objects) -> nil
8896 *
8897 * Writes the given +objects+ to the stream, which must be open for writing;
8898 * returns +nil+.\
8899 * Writes a newline after each that does not already end with a newline sequence.
8900 * If called without arguments, writes a newline.
8901 * See {Line IO}[rdoc-ref:IO@Line+IO].
8902 *
8903 * Note that each added newline is the character <tt>"\n"<//tt>,
8904 * not the output record separator (<tt>$\</tt>).
8905 *
8906 * Treatment for each object:
8907 *
8908 * - String: writes the string.
8909 * - Neither string nor array: writes <tt>object.to_s</tt>.
8910 * - Array: writes each element of the array; arrays may be nested.
8911 *
8912 * To keep these examples brief, we define this helper method:
8913 *
8914 * def show(*objects)
8915 * # Puts objects to file.
8916 * f = File.new('t.tmp', 'w+')
8917 * f.puts(objects)
8918 * # Return file content.
8919 * f.rewind
8920 * p f.read
8921 * f.close
8922 * end
8923 *
8924 * # Strings without newlines.
8925 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8926 * # Strings, some with newlines.
8927 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8928 *
8929 * # Neither strings nor arrays:
8930 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8931 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8932 *
8933 * # Array of strings.
8934 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8935 * # Nested arrays.
8936 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8937 *
8938 */
8939
8940 VALUE
8941rb_io_puts(int argc, const VALUE *argv, VALUE out)
8942{
8943 VALUE line, args[2];
8944
8945 /* if no argument given, print newline. */
8946 if (argc == 0) {
8947 rb_io_write(out, rb_default_rs);
8948 return Qnil;
8949 }
8950 for (int i = 0; i < argc; i++) {
8951 // Convert the argument to a string:
8952 if (RB_TYPE_P(argv[i], T_STRING)) {
8953 line = argv[i];
8954 }
8955 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8956 continue;
8957 }
8958 else {
8959 line = rb_obj_as_string(argv[i]);
8960 }
8961
8962 // Write the line:
8963 int n = 0;
8964 if (RSTRING_LEN(line) == 0) {
8965 args[n++] = rb_default_rs;
8966 }
8967 else {
8968 args[n++] = line;
8969 if (!rb_str_end_with_asciichar(line, '\n')) {
8970 args[n++] = rb_default_rs;
8971 }
8972 }
8973
8974 rb_io_writev(out, n, args);
8975 }
8976
8977 return Qnil;
8978}
8979
8980/*
8981 * call-seq:
8982 * puts(*objects) -> nil
8983 *
8984 * Equivalent to
8985 *
8986 * $stdout.puts(objects)
8987 */
8988
8989static VALUE
8990rb_f_puts(int argc, VALUE *argv, VALUE recv)
8991{
8992 VALUE r_stdout = rb_ractor_stdout();
8993 if (recv == r_stdout) {
8994 return rb_io_puts(argc, argv, recv);
8995 }
8996 return forward(r_stdout, rb_intern("puts"), argc, argv);
8997}
8998
8999static VALUE
9000rb_p_write(VALUE str)
9001{
9002 VALUE args[2];
9003 args[0] = str;
9004 args[1] = rb_default_rs;
9005 VALUE r_stdout = rb_ractor_stdout();
9006 if (RB_TYPE_P(r_stdout, T_FILE) &&
9007 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9008 io_writev(2, args, r_stdout);
9009 }
9010 else {
9011 rb_io_writev(r_stdout, 2, args);
9012 }
9013 return Qnil;
9014}
9015
9016void
9017rb_p(VALUE obj) /* for debug print within C code */
9018{
9019 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9020}
9021
9022static VALUE
9023rb_p_result(int argc, const VALUE *argv)
9024{
9025 VALUE ret = Qnil;
9026
9027 if (argc == 1) {
9028 ret = argv[0];
9029 }
9030 else if (argc > 1) {
9031 ret = rb_ary_new4(argc, argv);
9032 }
9033 VALUE r_stdout = rb_ractor_stdout();
9034 if (RB_TYPE_P(r_stdout, T_FILE)) {
9035 rb_uninterruptible(rb_io_flush, r_stdout);
9036 }
9037 return ret;
9038}
9039
9040/*
9041 * call-seq:
9042 * p(object) -> obj
9043 * p(*objects) -> array of objects
9044 * p -> nil
9045 *
9046 * For each object +obj+, executes:
9047 *
9048 * $stdout.write(obj.inspect, "\n")
9049 *
9050 * With one object given, returns the object;
9051 * with multiple objects given, returns an array containing the objects;
9052 * with no object given, returns +nil+.
9053 *
9054 * Examples:
9055 *
9056 * r = Range.new(0, 4)
9057 * p r # => 0..4
9058 * p [r, r, r] # => [0..4, 0..4, 0..4]
9059 * p # => nil
9060 *
9061 * Output:
9062 *
9063 * 0..4
9064 * [0..4, 0..4, 0..4]
9065 *
9066 * Kernel#p is designed for debugging purposes.
9067 * Ruby implementations may define Kernel#p to be uninterruptible
9068 * in whole or in part.
9069 * On CRuby, Kernel#p's writing of data is uninterruptible.
9070 */
9071
9072static VALUE
9073rb_f_p(int argc, VALUE *argv, VALUE self)
9074{
9075 int i;
9076 for (i=0; i<argc; i++) {
9077 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9078 rb_uninterruptible(rb_p_write, inspected);
9079 }
9080 return rb_p_result(argc, argv);
9081}
9082
9083/*
9084 * call-seq:
9085 * display(port = $>) -> nil
9086 *
9087 * Writes +self+ on the given port:
9088 *
9089 * 1.display
9090 * "cat".display
9091 * [ 4, 5, 6 ].display
9092 * puts
9093 *
9094 * Output:
9095 *
9096 * 1cat[4, 5, 6]
9097 *
9098 */
9099
9100static VALUE
9101rb_obj_display(int argc, VALUE *argv, VALUE self)
9102{
9103 VALUE out;
9104
9105 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9106 rb_io_write(out, self);
9107
9108 return Qnil;
9109}
9110
9111static int
9112rb_stderr_to_original_p(VALUE err)
9113{
9114 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9115}
9116
9117void
9118rb_write_error2(const char *mesg, long len)
9119{
9120 VALUE out = rb_ractor_stderr();
9121 if (rb_stderr_to_original_p(out)) {
9122#ifdef _WIN32
9123 if (isatty(fileno(stderr))) {
9124 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9125 }
9126#endif
9127 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9128 /* failed to write to stderr, what can we do? */
9129 return;
9130 }
9131 }
9132 else {
9133 rb_io_write(out, rb_str_new(mesg, len));
9134 }
9135}
9136
9137void
9138rb_write_error(const char *mesg)
9139{
9140 rb_write_error2(mesg, strlen(mesg));
9141}
9142
9143void
9144rb_write_error_str(VALUE mesg)
9145{
9146 VALUE out = rb_ractor_stderr();
9147 /* a stopgap measure for the time being */
9148 if (rb_stderr_to_original_p(out)) {
9149 size_t len = (size_t)RSTRING_LEN(mesg);
9150#ifdef _WIN32
9151 if (isatty(fileno(stderr))) {
9152 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9153 }
9154#endif
9155 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9156 RB_GC_GUARD(mesg);
9157 return;
9158 }
9159 }
9160 else {
9161 /* may unlock GVL, and */
9162 rb_io_write(out, mesg);
9163 }
9164}
9165
9166int
9167rb_stderr_tty_p(void)
9168{
9169 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9170 return isatty(fileno(stderr));
9171 return 0;
9172}
9173
9174static void
9175must_respond_to(ID mid, VALUE val, ID id)
9176{
9177 if (!rb_respond_to(val, mid)) {
9178 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9179 rb_id2str(id), rb_id2str(mid),
9180 rb_obj_class(val));
9181 }
9182}
9183
9184static void
9185stdin_setter(VALUE val, ID id, VALUE *ptr)
9186{
9187 rb_ractor_stdin_set(val);
9188}
9189
9190static VALUE
9191stdin_getter(ID id, VALUE *ptr)
9192{
9193 return rb_ractor_stdin();
9194}
9195
9196static void
9197stdout_setter(VALUE val, ID id, VALUE *ptr)
9198{
9199 must_respond_to(id_write, val, id);
9200 rb_ractor_stdout_set(val);
9201}
9202
9203static VALUE
9204stdout_getter(ID id, VALUE *ptr)
9205{
9206 return rb_ractor_stdout();
9207}
9208
9209static void
9210stderr_setter(VALUE val, ID id, VALUE *ptr)
9211{
9212 must_respond_to(id_write, val, id);
9213 rb_ractor_stderr_set(val);
9214}
9215
9216static VALUE
9217stderr_getter(ID id, VALUE *ptr)
9218{
9219 return rb_ractor_stderr();
9220}
9221
9222static VALUE
9223allocate_and_open_new_file(VALUE klass)
9224{
9225 VALUE self = io_alloc(klass);
9226 rb_io_make_open_file(self);
9227 return self;
9228}
9229
9230 VALUE
9231rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9232{
9233 int state;
9234 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9235 if (state) {
9236 /* if we raised an exception allocating an IO object, but the caller
9237 intended to transfer ownership of this FD to us, close the fd before
9238 raising the exception. Otherwise, we would leak a FD - the caller
9239 expects GC to close the file, but we never got around to assigning
9240 it to a rb_io. */
9241 if (!(mode & FMODE_EXTERNAL)) {
9242 maygvl_close(descriptor, 0);
9243 }
9244 rb_jump_tag(state);
9245 }
9246
9247
9248 rb_io_t *io = RFILE(self)->fptr;
9249 io->self = self;
9250 io->fd = descriptor;
9251 io->mode = mode;
9252
9253 /* At this point, Ruby fully owns the descriptor, and will close it when
9254 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9255 in the rest of this method. */
9256
9257 if (NIL_P(path)) {
9258 io->pathv = Qnil;
9259 }
9260 else {
9261 StringValue(path);
9262 io->pathv = rb_str_new_frozen(path);
9263 }
9264
9265 io->timeout = timeout;
9266
9267 if (encoding) {
9268 io->encs = *encoding;
9269 }
9270
9271 rb_update_max_fd(descriptor);
9272
9273 return self;
9274}
9275
9276static VALUE
9277prep_io(int fd, int fmode, VALUE klass, const char *path)
9278{
9279 VALUE path_value = Qnil;
9280 if (path) {
9281 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9282 }
9283
9284 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, NULL);
9285 rb_io_t*io = RFILE(self)->fptr;
9286
9287 if (!io_check_tty(io)) {
9288#ifdef __CYGWIN__
9289 io->mode |= FMODE_BINMODE;
9290 setmode(fd, O_BINARY);
9291#endif
9292 }
9293
9294 return self;
9295}
9296
9297 VALUE
9298rb_io_fdopen(int fd, int oflags, const char *path)
9299{
9300 VALUE klass = rb_cIO;
9301
9302 if (path && strcmp(path, "-")) klass = rb_cFile;
9303 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9304}
9305
9306static VALUE
9307prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9308{
9309 rb_io_t *fptr;
9310 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9311
9312 GetOpenFile(io, fptr);
9313 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
9314#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9315 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9316 if (fmode & FMODE_READABLE) {
9317 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
9318 }
9319#endif
9320 fptr->stdio_file = f;
9321
9322 return io;
9323}
9324
9325 VALUE
9326rb_io_prep_stdin(void)
9327{
9328 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9329}
9330
9331 VALUE
9332rb_io_prep_stdout(void)
9333{
9334 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9335}
9336
9337 VALUE
9338rb_io_prep_stderr(void)
9339{
9340 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9341}
9342
9343FILE *
9344rb_io_stdio_file(rb_io_t *fptr)
9345{
9346 if (!fptr->stdio_file) {
9347 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9348 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9349 }
9350 return fptr->stdio_file;
9351}
9352
9353static inline void
9354rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9355{
9356 buf->ptr = NULL;
9357 buf->off = 0;
9358 buf->len = 0;
9359 buf->capa = 0;
9360}
9361
9362static inline rb_io_t *
9363rb_io_fptr_new(void)
9364{
9365 rb_io_t *fp = ALLOC(rb_io_t);
9366 fp->self = Qnil;
9367 fp->fd = -1;
9368 fp->stdio_file = NULL;
9369 fp->mode = 0;
9370 fp->pid = 0;
9371 fp->lineno = 0;
9372 fp->pathv = Qnil;
9373 fp->finalize = 0;
9374 rb_io_buffer_init(&fp->wbuf);
9375 rb_io_buffer_init(&fp->rbuf);
9376 rb_io_buffer_init(&fp->cbuf);
9377 fp->readconv = NULL;
9378 fp->writeconv = NULL;
9379 fp->writeconv_asciicompat = Qnil;
9380 fp->writeconv_pre_ecflags = 0;
9381 fp->writeconv_pre_ecopts = Qnil;
9382 fp->writeconv_initialized = 0;
9383 fp->tied_io_for_writing = 0;
9384 fp->encs.enc = NULL;
9385 fp->encs.enc2 = NULL;
9386 fp->encs.ecflags = 0;
9387 fp->encs.ecopts = Qnil;
9388 fp->write_lock = Qnil;
9389 fp->timeout = Qnil;
9390 return fp;
9391}
9392
9393rb_io_t *
9394rb_io_make_open_file(VALUE obj)
9395{
9396 rb_io_t *fp = 0;
9397
9398 Check_Type(obj, T_FILE);
9399 if (RFILE(obj)->fptr) {
9400 rb_io_close(obj);
9401 rb_io_fptr_finalize(RFILE(obj)->fptr);
9402 RFILE(obj)->fptr = 0;
9403 }
9404 fp = rb_io_fptr_new();
9405 fp->self = obj;
9406 RFILE(obj)->fptr = fp;
9407 return fp;
9408}
9409
9410/*
9411 * call-seq:
9412 * IO.new(fd, mode = 'r', **opts) -> io
9413 *
9414 * Creates and returns a new \IO object (file stream) from a file descriptor.
9415 *
9416 * \IO.new may be useful for interaction with low-level libraries.
9417 * For higher-level interactions, it may be simpler to create
9418 * the file stream using File.open.
9419 *
9420 * Argument +fd+ must be a valid file descriptor (integer):
9421 *
9422 * path = 't.tmp'
9423 * fd = IO.sysopen(path) # => 3
9424 * IO.new(fd) # => #<IO:fd 3>
9425 *
9426 * The new \IO object does not inherit encoding
9427 * (because the integer file descriptor does not have an encoding):
9428 *
9429 * fd = IO.sysopen('t.rus', 'rb')
9430 * io = IO.new(fd)
9431 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9432 *
9433 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9434 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9435 *
9436 * IO.new(fd, 'w') # => #<IO:fd 3>
9437 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9438 *
9439 * Optional keyword arguments +opts+ specify:
9440 *
9441 * - {Open Options}[rdoc-ref:IO@Open+Options].
9442 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9443 *
9444 * Examples:
9445 *
9446 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9447 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9448 *
9449 */
9450
9451static VALUE
9452rb_io_initialize(int argc, VALUE *argv, VALUE io)
9453{
9454 VALUE fnum, vmode;
9455 rb_io_t *fp;
9456 int fd, fmode, oflags = O_RDONLY;
9457 struct rb_io_encoding convconfig;
9458 VALUE opt;
9459#if defined(HAVE_FCNTL) && defined(F_GETFL)
9460 int ofmode;
9461#else
9462 struct stat st;
9463#endif
9464
9465
9466 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9467 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9468
9469 fd = NUM2INT(fnum);
9470 if (rb_reserved_fd_p(fd)) {
9471 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9472 }
9473#if defined(HAVE_FCNTL) && defined(F_GETFL)
9474 oflags = fcntl(fd, F_GETFL);
9475 if (oflags == -1) rb_sys_fail(0);
9476#else
9477 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9478#endif
9479 rb_update_max_fd(fd);
9480#if defined(HAVE_FCNTL) && defined(F_GETFL)
9481 ofmode = rb_io_oflags_fmode(oflags);
9482 if (NIL_P(vmode)) {
9483 fmode = ofmode;
9484 }
9485 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9486 VALUE error = INT2FIX(EINVAL);
9487 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
9488 }
9489#endif
9490 VALUE path = Qnil;
9491
9492 if (!NIL_P(opt)) {
9493 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9494 fmode |= FMODE_EXTERNAL;
9495 }
9496
9497 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9498 if (!NIL_P(path)) {
9499 StringValue(path);
9500 path = rb_str_new_frozen(path);
9501 }
9502 }
9503
9504 MakeOpenFile(io, fp);
9505 fp->self = io;
9506 fp->fd = fd;
9507 fp->mode = fmode;
9508 fp->encs = convconfig;
9509 fp->pathv = path;
9510 fp->timeout = Qnil;
9511 clear_codeconv(fp);
9512 io_check_tty(fp);
9513 if (fileno(stdin) == fd)
9514 fp->stdio_file = stdin;
9515 else if (fileno(stdout) == fd)
9516 fp->stdio_file = stdout;
9517 else if (fileno(stderr) == fd)
9518 fp->stdio_file = stderr;
9519
9520 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9521 return io;
9522}
9523
9524/*
9525 * call-seq:
9526 * set_encoding_by_bom -> encoding or nil
9527 *
9528 * If the stream begins with a BOM
9529 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9530 * consumes the BOM and sets the external encoding accordingly;
9531 * returns the result encoding if found, or +nil+ otherwise:
9532 *
9533 * File.write('t.tmp', "\u{FEFF}abc")
9534 * io = File.open('t.tmp', 'rb')
9535 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9536 * io.close
9537 *
9538 * File.write('t.tmp', 'abc')
9539 * io = File.open('t.tmp', 'rb')
9540 * io.set_encoding_by_bom # => nil
9541 * io.close
9542 *
9543 * Raises an exception if the stream is not binmode
9544 * or its encoding has already been set.
9545 *
9546 */
9547
9548static VALUE
9549rb_io_set_encoding_by_bom(VALUE io)
9550{
9551 rb_io_t *fptr;
9552
9553 GetOpenFile(io, fptr);
9554 if (!(fptr->mode & FMODE_BINMODE)) {
9555 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9556 }
9557 if (fptr->encs.enc2) {
9558 rb_raise(rb_eArgError, "encoding conversion is set");
9559 }
9560 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9561 rb_raise(rb_eArgError, "encoding is set to %s already",
9562 rb_enc_name(fptr->encs.enc));
9563 }
9564 if (!io_set_encoding_by_bom(io)) return Qnil;
9565 return rb_enc_from_encoding(fptr->encs.enc);
9566}
9567
9568/*
9569 * call-seq:
9570 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9571 *
9572 * Opens the file at the given +path+ according to the given +mode+;
9573 * creates and returns a new File object for that file.
9574 *
9575 * The new File object is buffered mode (or non-sync mode), unless
9576 * +filename+ is a tty.
9577 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9578 *
9579 * Argument +path+ must be a valid file path:
9580 *
9581 * f = File.new('/etc/fstab')
9582 * f.close
9583 * f = File.new('t.txt')
9584 * f.close
9585 *
9586 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9587 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9588 *
9589 * f = File.new('t.tmp', 'w')
9590 * f.close
9591 * f = File.new('t.tmp', File::RDONLY)
9592 * f.close
9593 *
9594 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9595 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9596 *
9597 * f = File.new('t.tmp', File::CREAT, 0644)
9598 * f.close
9599 * f = File.new('t.tmp', File::CREAT, 0444)
9600 * f.close
9601 *
9602 * Optional keyword arguments +opts+ specify:
9603 *
9604 * - {Open Options}[rdoc-ref:IO@Open+Options].
9605 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9606 *
9607 */
9608
9609static VALUE
9610rb_file_initialize(int argc, VALUE *argv, VALUE io)
9611{
9612 if (RFILE(io)->fptr) {
9613 rb_raise(rb_eRuntimeError, "reinitializing File");
9614 }
9615 if (0 < argc && argc < 3) {
9616 VALUE fd = rb_check_to_int(argv[0]);
9617
9618 if (!NIL_P(fd)) {
9619 argv[0] = fd;
9620 return rb_io_initialize(argc, argv, io);
9621 }
9622 }
9623 rb_open_file(argc, argv, io);
9624
9625 return io;
9626}
9627
9628/* :nodoc: */
9629static VALUE
9630rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9631{
9632 if (rb_block_given_p()) {
9633 VALUE cname = rb_obj_as_string(klass);
9634
9635 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9636 cname, cname);
9637 }
9638 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9639}
9640
9641
9642/*
9643 * call-seq:
9644 * IO.for_fd(fd, mode = 'r', **opts) -> io
9645 *
9646 * Synonym for IO.new.
9647 *
9648 */
9649
9650static VALUE
9651rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9652{
9653 VALUE io = rb_obj_alloc(klass);
9654 rb_io_initialize(argc, argv, io);
9655 return io;
9656}
9657
9658/*
9659 * call-seq:
9660 * ios.autoclose? -> true or false
9661 *
9662 * Returns +true+ if the underlying file descriptor of _ios_ will be
9663 * closed at its finalization or at calling #close, otherwise +false+.
9664 */
9665
9666static VALUE
9667rb_io_autoclose_p(VALUE io)
9668{
9669 rb_io_t *fptr = RFILE(io)->fptr;
9670 rb_io_check_closed(fptr);
9671 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9672}
9673
9674/*
9675 * call-seq:
9676 * io.autoclose = bool -> true or false
9677 *
9678 * Sets auto-close flag.
9679 *
9680 * f = File.open(File::NULL)
9681 * IO.for_fd(f.fileno).close
9682 * f.gets # raises Errno::EBADF
9683 *
9684 * f = File.open(File::NULL)
9685 * g = IO.for_fd(f.fileno)
9686 * g.autoclose = false
9687 * g.close
9688 * f.gets # won't cause Errno::EBADF
9689 */
9690
9691static VALUE
9692rb_io_set_autoclose(VALUE io, VALUE autoclose)
9693{
9694 rb_io_t *fptr;
9695 GetOpenFile(io, fptr);
9696 if (!RTEST(autoclose))
9697 fptr->mode |= FMODE_EXTERNAL;
9698 else
9699 fptr->mode &= ~FMODE_EXTERNAL;
9700 return autoclose;
9701}
9702
9703static VALUE
9704io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9705{
9706 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9707
9708 if (!RB_TEST(result)) {
9709 return Qnil;
9710 }
9711
9712 int mask = RB_NUM2INT(result);
9713
9714 if (mask & event) {
9715 if (return_io)
9716 return io;
9717 else
9718 return result;
9719 }
9720 else {
9721 return Qfalse;
9722 }
9723}
9724
9725/*
9726 * call-seq:
9727 * io.wait_readable -> truthy or falsy
9728 * io.wait_readable(timeout) -> truthy or falsy
9729 *
9730 * Waits until IO is readable and returns a truthy value, or a falsy
9731 * value when times out. Returns a truthy value immediately when
9732 * buffered data is available.
9733 */
9734
9735static VALUE
9736io_wait_readable(int argc, VALUE *argv, VALUE io)
9737{
9738 rb_io_t *fptr;
9739
9740 RB_IO_POINTER(io, fptr);
9741 rb_io_check_readable(fptr);
9742
9743 if (rb_io_read_pending(fptr)) return Qtrue;
9744
9745 rb_check_arity(argc, 0, 1);
9746 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9747
9748 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9749}
9750
9751/*
9752 * call-seq:
9753 * io.wait_writable -> truthy or falsy
9754 * io.wait_writable(timeout) -> truthy or falsy
9755 *
9756 * Waits until IO is writable and returns a truthy value or a falsy
9757 * value when times out.
9758 */
9759static VALUE
9760io_wait_writable(int argc, VALUE *argv, VALUE io)
9761{
9762 rb_io_t *fptr;
9763
9764 RB_IO_POINTER(io, fptr);
9765 rb_io_check_writable(fptr);
9766
9767 rb_check_arity(argc, 0, 1);
9768 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9769
9770 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9771}
9772
9773/*
9774 * call-seq:
9775 * io.wait_priority -> truthy or falsy
9776 * io.wait_priority(timeout) -> truthy or falsy
9777 *
9778 * Waits until IO is priority and returns a truthy value or a falsy
9779 * value when times out. Priority data is sent and received using
9780 * the Socket::MSG_OOB flag and is typically limited to streams.
9781 */
9782static VALUE
9783io_wait_priority(int argc, VALUE *argv, VALUE io)
9784{
9785 rb_io_t *fptr = NULL;
9786
9787 RB_IO_POINTER(io, fptr);
9788 rb_io_check_readable(fptr);
9789
9790 if (rb_io_read_pending(fptr)) return Qtrue;
9791
9792 rb_check_arity(argc, 0, 1);
9793 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9794
9795 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9796}
9797
9798static int
9799wait_mode_sym(VALUE mode)
9800{
9801 if (mode == ID2SYM(rb_intern("r"))) {
9802 return RB_WAITFD_IN;
9803 }
9804 if (mode == ID2SYM(rb_intern("read"))) {
9805 return RB_WAITFD_IN;
9806 }
9807 if (mode == ID2SYM(rb_intern("readable"))) {
9808 return RB_WAITFD_IN;
9809 }
9810 if (mode == ID2SYM(rb_intern("w"))) {
9811 return RB_WAITFD_OUT;
9812 }
9813 if (mode == ID2SYM(rb_intern("write"))) {
9814 return RB_WAITFD_OUT;
9815 }
9816 if (mode == ID2SYM(rb_intern("writable"))) {
9817 return RB_WAITFD_OUT;
9818 }
9819 if (mode == ID2SYM(rb_intern("rw"))) {
9820 return RB_WAITFD_IN|RB_WAITFD_OUT;
9821 }
9822 if (mode == ID2SYM(rb_intern("read_write"))) {
9823 return RB_WAITFD_IN|RB_WAITFD_OUT;
9824 }
9825 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9826 return RB_WAITFD_IN|RB_WAITFD_OUT;
9827 }
9828
9829 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9830}
9831
9832static inline enum rb_io_event
9833io_event_from_value(VALUE value)
9834{
9835 int events = RB_NUM2INT(value);
9836
9837 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9838
9839 return events;
9840}
9841
9842/*
9843 * call-seq:
9844 * io.wait(events, timeout) -> event mask, false or nil
9845 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9846 *
9847 * Waits until the IO becomes ready for the specified events and returns the
9848 * subset of events that become ready, or a falsy value when times out.
9849 *
9850 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9851 * +IO::PRIORITY+.
9852 *
9853 * Returns an event mask (truthy value) immediately when buffered data is available.
9854 *
9855 * Optional parameter +mode+ is one of +:read+, +:write+, or
9856 * +:read_write+.
9857 */
9858
9859static VALUE
9860io_wait(int argc, VALUE *argv, VALUE io)
9861{
9862 VALUE timeout = Qundef;
9863 enum rb_io_event events = 0;
9864 int return_io = 0;
9865
9866 // The documented signature for this method is actually incorrect.
9867 // A single timeout is allowed in any position, and multiple symbols can be given.
9868 // Whether this is intentional or not, I don't know, and as such I consider this to
9869 // be a legacy/slow path.
9870 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9871 // We'd prefer to return the actual mask, but this form would return the io itself:
9872 return_io = 1;
9873
9874 // Slow/messy path:
9875 for (int i = 0; i < argc; i += 1) {
9876 if (RB_SYMBOL_P(argv[i])) {
9877 events |= wait_mode_sym(argv[i]);
9878 }
9879 else if (UNDEF_P(timeout)) {
9880 rb_time_interval(timeout = argv[i]);
9881 }
9882 else {
9883 rb_raise(rb_eArgError, "timeout given more than once");
9884 }
9885 }
9886
9887 if (UNDEF_P(timeout)) timeout = Qnil;
9888
9889 if (events == 0) {
9890 events = RUBY_IO_READABLE;
9891 }
9892 }
9893 else /* argc == 2 and neither are symbols */ {
9894 // This is the fast path:
9895 events = io_event_from_value(argv[0]);
9896 timeout = argv[1];
9897 }
9898
9899 if (events & RUBY_IO_READABLE) {
9900 rb_io_t *fptr = NULL;
9901 RB_IO_POINTER(io, fptr);
9902
9903 if (rb_io_read_pending(fptr)) {
9904 // This was the original behaviour:
9905 if (return_io) return Qtrue;
9906 // New behaviour always returns an event mask:
9907 else return RB_INT2NUM(RUBY_IO_READABLE);
9908 }
9909 }
9910
9911 return io_wait_event(io, events, timeout, return_io);
9912}
9913
9914static void
9915argf_mark(void *ptr)
9916{
9917 struct argf *p = ptr;
9918 rb_gc_mark(p->filename);
9919 rb_gc_mark(p->current_file);
9920 rb_gc_mark(p->argv);
9921 rb_gc_mark(p->inplace);
9922 rb_gc_mark(p->encs.ecopts);
9923}
9924
9925static size_t
9926argf_memsize(const void *ptr)
9927{
9928 const struct argf *p = ptr;
9929 size_t size = sizeof(*p);
9930 return size;
9931}
9932
9933static const rb_data_type_t argf_type = {
9934 "ARGF",
9935 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9936 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9937};
9938
9939static inline void
9940argf_init(struct argf *p, VALUE v)
9941{
9942 p->filename = Qnil;
9943 p->current_file = Qnil;
9944 p->lineno = 0;
9945 p->argv = v;
9946}
9947
9948static VALUE
9949argf_alloc(VALUE klass)
9950{
9951 struct argf *p;
9952 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9953
9954 argf_init(p, Qnil);
9955 return argf;
9956}
9957
9958#undef rb_argv
9959
9960/* :nodoc: */
9961static VALUE
9962argf_initialize(VALUE argf, VALUE argv)
9963{
9964 memset(&ARGF, 0, sizeof(ARGF));
9965 argf_init(&ARGF, argv);
9966
9967 return argf;
9968}
9969
9970/* :nodoc: */
9971static VALUE
9972argf_initialize_copy(VALUE argf, VALUE orig)
9973{
9974 if (!OBJ_INIT_COPY(argf, orig)) return argf;
9975 ARGF = argf_of(orig);
9976 ARGF.argv = rb_obj_dup(ARGF.argv);
9977 return argf;
9978}
9979
9980/*
9981 * call-seq:
9982 * ARGF.lineno = integer -> integer
9983 *
9984 * Sets the line number of ARGF as a whole to the given Integer.
9985 *
9986 * ARGF sets the line number automatically as you read data, so normally
9987 * you will not need to set it explicitly. To access the current line number
9988 * use ARGF.lineno.
9989 *
9990 * For example:
9991 *
9992 * ARGF.lineno #=> 0
9993 * ARGF.readline #=> "This is line 1\n"
9994 * ARGF.lineno #=> 1
9995 * ARGF.lineno = 0 #=> 0
9996 * ARGF.lineno #=> 0
9997 */
9998static VALUE
9999argf_set_lineno(VALUE argf, VALUE val)
10000{
10001 ARGF.lineno = NUM2INT(val);
10002 ARGF.last_lineno = ARGF.lineno;
10003 return val;
10004}
10005
10006/*
10007 * call-seq:
10008 * ARGF.lineno -> integer
10009 *
10010 * Returns the current line number of ARGF as a whole. This value
10011 * can be set manually with ARGF.lineno=.
10012 *
10013 * For example:
10014 *
10015 * ARGF.lineno #=> 0
10016 * ARGF.readline #=> "This is line 1\n"
10017 * ARGF.lineno #=> 1
10018 */
10019static VALUE
10020argf_lineno(VALUE argf)
10021{
10022 return INT2FIX(ARGF.lineno);
10023}
10024
10025static VALUE
10026argf_forward(int argc, VALUE *argv, VALUE argf)
10027{
10028 return forward_current(rb_frame_this_func(), argc, argv);
10029}
10030
10031#define next_argv() argf_next_argv(argf)
10032#define ARGF_GENERIC_INPUT_P() \
10033 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10034#define ARGF_FORWARD(argc, argv) do {\
10035 if (ARGF_GENERIC_INPUT_P())\
10036 return argf_forward((argc), (argv), argf);\
10037} while (0)
10038#define NEXT_ARGF_FORWARD(argc, argv) do {\
10039 if (!next_argv()) return Qnil;\
10040 ARGF_FORWARD((argc), (argv));\
10041} while (0)
10042
10043static void
10044argf_close(VALUE argf)
10045{
10046 VALUE file = ARGF.current_file;
10047 if (file == rb_stdin) return;
10048 if (RB_TYPE_P(file, T_FILE)) {
10049 rb_io_set_write_io(file, Qnil);
10050 }
10051 io_close(file);
10052 ARGF.init_p = -1;
10053}
10054
10055static int
10056argf_next_argv(VALUE argf)
10057{
10058 char *fn;
10059 rb_io_t *fptr;
10060 int stdout_binmode = 0;
10061 int fmode;
10062
10063 VALUE r_stdout = rb_ractor_stdout();
10064
10065 if (RB_TYPE_P(r_stdout, T_FILE)) {
10066 GetOpenFile(r_stdout, fptr);
10067 if (fptr->mode & FMODE_BINMODE)
10068 stdout_binmode = 1;
10069 }
10070
10071 if (ARGF.init_p == 0) {
10072 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10073 ARGF.next_p = 1;
10074 }
10075 else {
10076 ARGF.next_p = -1;
10077 }
10078 ARGF.init_p = 1;
10079 }
10080 else {
10081 if (NIL_P(ARGF.argv)) {
10082 ARGF.next_p = -1;
10083 }
10084 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10085 ARGF.next_p = 1;
10086 }
10087 }
10088
10089 if (ARGF.next_p == 1) {
10090 if (ARGF.init_p == 1) argf_close(argf);
10091 retry:
10092 if (RARRAY_LEN(ARGF.argv) > 0) {
10093 VALUE filename = rb_ary_shift(ARGF.argv);
10094 FilePathValue(filename);
10095 ARGF.filename = filename;
10096 filename = rb_str_encode_ospath(filename);
10097 fn = StringValueCStr(filename);
10098 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10099 ARGF.current_file = rb_stdin;
10100 if (ARGF.inplace) {
10101 rb_warn("Can't do inplace edit for stdio; skipping");
10102 goto retry;
10103 }
10104 }
10105 else {
10106 VALUE write_io = Qnil;
10107 int fr = rb_sysopen(filename, O_RDONLY, 0);
10108
10109 if (ARGF.inplace) {
10110 struct stat st;
10111#ifndef NO_SAFE_RENAME
10112 struct stat st2;
10113#endif
10114 VALUE str;
10115 int fw;
10116
10117 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10118 rb_io_close(r_stdout);
10119 }
10120 fstat(fr, &st);
10121 str = filename;
10122 if (!NIL_P(ARGF.inplace)) {
10123 VALUE suffix = ARGF.inplace;
10124 str = rb_str_dup(str);
10125 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10126 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10127 rb_enc_get(suffix), 0, Qnil))) {
10128 rb_str_append(str, suffix);
10129 }
10130#ifdef NO_SAFE_RENAME
10131 (void)close(fr);
10132 (void)unlink(RSTRING_PTR(str));
10133 if (rename(fn, RSTRING_PTR(str)) < 0) {
10134 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10135 filename, str, strerror(errno));
10136 goto retry;
10137 }
10138 fr = rb_sysopen(str, O_RDONLY, 0);
10139#else
10140 if (rename(fn, RSTRING_PTR(str)) < 0) {
10141 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10142 filename, str, strerror(errno));
10143 close(fr);
10144 goto retry;
10145 }
10146#endif
10147 }
10148 else {
10149#ifdef NO_SAFE_RENAME
10150 rb_fatal("Can't do inplace edit without backup");
10151#else
10152 if (unlink(fn) < 0) {
10153 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10154 filename, strerror(errno));
10155 close(fr);
10156 goto retry;
10157 }
10158#endif
10159 }
10160 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10161#ifndef NO_SAFE_RENAME
10162 fstat(fw, &st2);
10163#ifdef HAVE_FCHMOD
10164 fchmod(fw, st.st_mode);
10165#else
10166 chmod(fn, st.st_mode);
10167#endif
10168 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10169 int err;
10170#ifdef HAVE_FCHOWN
10171 err = fchown(fw, st.st_uid, st.st_gid);
10172#else
10173 err = chown(fn, st.st_uid, st.st_gid);
10174#endif
10175 if (err && getuid() == 0 && st2.st_uid == 0) {
10176 const char *wkfn = RSTRING_PTR(filename);
10177 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10178 filename, str, strerror(errno));
10179 (void)close(fr);
10180 (void)close(fw);
10181 (void)unlink(wkfn);
10182 goto retry;
10183 }
10184 }
10185#endif
10186 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10187 rb_ractor_stdout_set(write_io);
10188 if (stdout_binmode) rb_io_binmode(rb_stdout);
10189 }
10190 fmode = FMODE_READABLE;
10191 if (!ARGF.binmode) {
10192 fmode |= DEFAULT_TEXTMODE;
10193 }
10194 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10195 if (!NIL_P(write_io)) {
10196 rb_io_set_write_io(ARGF.current_file, write_io);
10197 }
10198 RB_GC_GUARD(filename);
10199 }
10200 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10201 GetOpenFile(ARGF.current_file, fptr);
10202 if (ARGF.encs.enc) {
10203 fptr->encs = ARGF.encs;
10204 clear_codeconv(fptr);
10205 }
10206 else {
10207 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10208 if (!ARGF.binmode) {
10209 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
10210#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10211 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10212#endif
10213 }
10214 }
10215 ARGF.next_p = 0;
10216 }
10217 else {
10218 ARGF.next_p = 1;
10219 return FALSE;
10220 }
10221 }
10222 else if (ARGF.next_p == -1) {
10223 ARGF.current_file = rb_stdin;
10224 ARGF.filename = rb_str_new2("-");
10225 if (ARGF.inplace) {
10226 rb_warn("Can't do inplace edit for stdio");
10227 rb_ractor_stdout_set(orig_stdout);
10228 }
10229 }
10230 if (ARGF.init_p == -1) ARGF.init_p = 1;
10231 return TRUE;
10232}
10233
10234static VALUE
10235argf_getline(int argc, VALUE *argv, VALUE argf)
10236{
10237 VALUE line;
10238 long lineno = ARGF.lineno;
10239
10240 retry:
10241 if (!next_argv()) return Qnil;
10242 if (ARGF_GENERIC_INPUT_P()) {
10243 line = forward_current(idGets, argc, argv);
10244 }
10245 else {
10246 if (argc == 0 && rb_rs == rb_default_rs) {
10247 line = rb_io_gets(ARGF.current_file);
10248 }
10249 else {
10250 line = rb_io_getline(argc, argv, ARGF.current_file);
10251 }
10252 if (NIL_P(line) && ARGF.next_p != -1) {
10253 argf_close(argf);
10254 ARGF.next_p = 1;
10255 goto retry;
10256 }
10257 }
10258 if (!NIL_P(line)) {
10259 ARGF.lineno = ++lineno;
10260 ARGF.last_lineno = ARGF.lineno;
10261 }
10262 return line;
10263}
10264
10265static VALUE
10266argf_lineno_getter(ID id, VALUE *var)
10267{
10268 VALUE argf = *var;
10269 return INT2FIX(ARGF.last_lineno);
10270}
10271
10272static void
10273argf_lineno_setter(VALUE val, ID id, VALUE *var)
10274{
10275 VALUE argf = *var;
10276 int n = NUM2INT(val);
10277 ARGF.last_lineno = ARGF.lineno = n;
10278}
10279
10280void
10281rb_reset_argf_lineno(long n)
10282{
10283 ARGF.last_lineno = ARGF.lineno = n;
10284}
10285
10286static VALUE argf_gets(int, VALUE *, VALUE);
10287
10288/*
10289 * call-seq:
10290 * gets(sep=$/ [, getline_args]) -> string or nil
10291 * gets(limit [, getline_args]) -> string or nil
10292 * gets(sep, limit [, getline_args]) -> string or nil
10293 *
10294 * Returns (and assigns to <code>$_</code>) the next line from the list
10295 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10296 * no files are present on the command line. Returns +nil+ at end of
10297 * file. The optional argument specifies the record separator. The
10298 * separator is included with the contents of each record. A separator
10299 * of +nil+ reads the entire contents, and a zero-length separator
10300 * reads the input one paragraph at a time, where paragraphs are
10301 * divided by two consecutive newlines. If the first argument is an
10302 * integer, or optional second argument is given, the returning string
10303 * would not be longer than the given value in bytes. If multiple
10304 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10305 * the contents one file at a time.
10306 *
10307 * ARGV << "testfile"
10308 * print while gets
10309 *
10310 * <em>produces:</em>
10311 *
10312 * This is line one
10313 * This is line two
10314 * This is line three
10315 * And so on...
10316 *
10317 * The style of programming using <code>$_</code> as an implicit
10318 * parameter is gradually losing favor in the Ruby community.
10319 */
10320
10321static VALUE
10322rb_f_gets(int argc, VALUE *argv, VALUE recv)
10323{
10324 if (recv == argf) {
10325 return argf_gets(argc, argv, argf);
10326 }
10327 return forward(argf, idGets, argc, argv);
10328}
10329
10330/*
10331 * call-seq:
10332 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10333 * ARGF.gets(limit [, getline_args]) -> string or nil
10334 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10335 *
10336 * Returns the next line from the current file in ARGF.
10337 *
10338 * By default lines are assumed to be separated by <code>$/</code>;
10339 * to use a different character as a separator, supply it as a String
10340 * for the _sep_ argument.
10341 *
10342 * The optional _limit_ argument specifies how many characters of each line
10343 * to return. By default all characters are returned.
10344 *
10345 * See IO.readlines for details about getline_args.
10346 *
10347 */
10348static VALUE
10349argf_gets(int argc, VALUE *argv, VALUE argf)
10350{
10351 VALUE line;
10352
10353 line = argf_getline(argc, argv, argf);
10354 rb_lastline_set(line);
10355
10356 return line;
10357}
10358
10359 VALUE
10360rb_gets(void)
10361{
10362 VALUE line;
10363
10364 if (rb_rs != rb_default_rs) {
10365 return rb_f_gets(0, 0, argf);
10366 }
10367
10368 retry:
10369 if (!next_argv()) return Qnil;
10370 line = rb_io_gets(ARGF.current_file);
10371 if (NIL_P(line) && ARGF.next_p != -1) {
10372 rb_io_close(ARGF.current_file);
10373 ARGF.next_p = 1;
10374 goto retry;
10375 }
10376 rb_lastline_set(line);
10377 if (!NIL_P(line)) {
10378 ARGF.lineno++;
10379 ARGF.last_lineno = ARGF.lineno;
10380 }
10381
10382 return line;
10383}
10384
10385static VALUE argf_readline(int, VALUE *, VALUE);
10386
10387/*
10388 * call-seq:
10389 * readline(sep = $/, chomp: false) -> string
10390 * readline(limit, chomp: false) -> string
10391 * readline(sep, limit, chomp: false) -> string
10392 *
10393 * Equivalent to method Kernel#gets, except that it raises an exception
10394 * if called at end-of-stream:
10395 *
10396 * $ cat t.txt | ruby -e "p readlines; readline"
10397 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10398 * in `readline': end of file reached (EOFError)
10399 *
10400 * Optional keyword argument +chomp+ specifies whether line separators
10401 * are to be omitted.
10402 */
10403
10404static VALUE
10405rb_f_readline(int argc, VALUE *argv, VALUE recv)
10406{
10407 if (recv == argf) {
10408 return argf_readline(argc, argv, argf);
10409 }
10410 return forward(argf, rb_intern("readline"), argc, argv);
10411}
10412
10413
10414/*
10415 * call-seq:
10416 * ARGF.readline(sep=$/) -> string
10417 * ARGF.readline(limit) -> string
10418 * ARGF.readline(sep, limit) -> string
10419 *
10420 * Returns the next line from the current file in ARGF.
10421 *
10422 * By default lines are assumed to be separated by <code>$/</code>;
10423 * to use a different character as a separator, supply it as a String
10424 * for the _sep_ argument.
10425 *
10426 * The optional _limit_ argument specifies how many characters of each line
10427 * to return. By default all characters are returned.
10428 *
10429 * An EOFError is raised at the end of the file.
10430 */
10431static VALUE
10432argf_readline(int argc, VALUE *argv, VALUE argf)
10433{
10434 VALUE line;
10435
10436 if (!next_argv()) rb_eof_error();
10437 ARGF_FORWARD(argc, argv);
10438 line = argf_gets(argc, argv, argf);
10439 if (NIL_P(line)) {
10440 rb_eof_error();
10441 }
10442
10443 return line;
10444}
10445
10446static VALUE argf_readlines(int, VALUE *, VALUE);
10447
10448/*
10449 * call-seq:
10450 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10451 * readlines(limit, chomp: false, **enc_opts) -> array
10452 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10453 *
10454 * Returns an array containing the lines returned by calling
10455 * Kernel#gets until the end-of-stream is reached;
10456 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10457 *
10458 * With only string argument +sep+ given,
10459 * returns the remaining lines as determined by line separator +sep+,
10460 * or +nil+ if none;
10461 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10462 *
10463 * # Default separator.
10464 * $ cat t.txt | ruby -e "p readlines"
10465 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10466 *
10467 * # Specified separator.
10468 * $ cat t.txt | ruby -e "p readlines 'li'"
10469 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10470 *
10471 * # Get-all separator.
10472 * $ cat t.txt | ruby -e "p readlines nil"
10473 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10474 *
10475 * # Get-paragraph separator.
10476 * $ cat t.txt | ruby -e "p readlines ''"
10477 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10478 *
10479 * With only integer argument +limit+ given,
10480 * limits the number of bytes in the line;
10481 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10482 *
10483 * $cat t.txt | ruby -e "p readlines 10"
10484 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10485 *
10486 * $cat t.txt | ruby -e "p readlines 11"
10487 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10488 *
10489 * $cat t.txt | ruby -e "p readlines 12"
10490 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10491 *
10492 * With arguments +sep+ and +limit+ given, combines the two behaviors;
10493 * see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit].
10494 *
10495 * Optional keyword argument +chomp+ specifies whether line separators
10496 * are to be omitted:
10497 *
10498 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10499 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10500 *
10501 * Optional keyword arguments +enc_opts+ specify encoding options;
10502 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10503 *
10504 */
10505
10506static VALUE
10507rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10508{
10509 if (recv == argf) {
10510 return argf_readlines(argc, argv, argf);
10511 }
10512 return forward(argf, rb_intern("readlines"), argc, argv);
10513}
10514
10515/*
10516 * call-seq:
10517 * ARGF.readlines(sep = $/, chomp: false) -> array
10518 * ARGF.readlines(limit, chomp: false) -> array
10519 * ARGF.readlines(sep, limit, chomp: false) -> array
10520 *
10521 * ARGF.to_a(sep = $/, chomp: false) -> array
10522 * ARGF.to_a(limit, chomp: false) -> array
10523 * ARGF.to_a(sep, limit, chomp: false) -> array
10524 *
10525 * Reads each file in ARGF in its entirety, returning an Array containing
10526 * lines from the files. Lines are assumed to be separated by _sep_.
10527 *
10528 * lines = ARGF.readlines
10529 * lines[0] #=> "This is line one\n"
10530 *
10531 * See +IO.readlines+ for a full description of all options.
10532 */
10533static VALUE
10534argf_readlines(int argc, VALUE *argv, VALUE argf)
10535{
10536 long lineno = ARGF.lineno;
10537 VALUE lines, ary;
10538
10539 ary = rb_ary_new();
10540 while (next_argv()) {
10541 if (ARGF_GENERIC_INPUT_P()) {
10542 lines = forward_current(rb_intern("readlines"), argc, argv);
10543 }
10544 else {
10545 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10546 argf_close(argf);
10547 }
10548 ARGF.next_p = 1;
10549 rb_ary_concat(ary, lines);
10550 ARGF.lineno = lineno + RARRAY_LEN(ary);
10551 ARGF.last_lineno = ARGF.lineno;
10552 }
10553 ARGF.init_p = 0;
10554 return ary;
10555}
10556
10557/*
10558 * call-seq:
10559 * `command` -> string
10560 *
10561 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10562 * sets global variable <tt>$?</tt> to the process status.
10563 *
10564 * This method has potential security vulnerabilities if called with untrusted input;
10565 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10566 *
10567 * Examples:
10568 *
10569 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10570 * $ `echo oops && exit 99` # => "oops\n"
10571 * $ $? # => #<Process::Status: pid 17088 exit 99>
10572 * $ $?.status # => 99>
10573 *
10574 * The built-in syntax <tt>%x{...}</tt> uses this method.
10575 *
10576 */
10577
10578static VALUE
10579rb_f_backquote(VALUE obj, VALUE str)
10580{
10581 VALUE port;
10582 VALUE result;
10583 rb_io_t *fptr;
10584
10585 SafeStringValue(str);
10586 rb_last_status_clear();
10587 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10588 if (NIL_P(port)) return rb_str_new(0,0);
10589
10590 GetOpenFile(port, fptr);
10591 result = read_all(fptr, remain_size(fptr), Qnil);
10592 rb_io_close(port);
10593 rb_io_fptr_cleanup_all(fptr);
10594 RB_GC_GUARD(port);
10595
10596 return result;
10597}
10598
10599#ifdef HAVE_SYS_SELECT_H
10600#include <sys/select.h>
10601#endif
10602
10603static VALUE
10604select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10605{
10606 VALUE res, list;
10607 rb_fdset_t *rp, *wp, *ep;
10608 rb_io_t *fptr;
10609 long i;
10610 int max = 0, n;
10611 int pending = 0;
10612 struct timeval timerec;
10613
10614 if (!NIL_P(read)) {
10615 Check_Type(read, T_ARRAY);
10616 for (i=0; i<RARRAY_LEN(read); i++) {
10617 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10618 rb_fd_set(fptr->fd, &fds[0]);
10619 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10620 pending++;
10621 rb_fd_set(fptr->fd, &fds[3]);
10622 }
10623 if (max < fptr->fd) max = fptr->fd;
10624 }
10625 if (pending) { /* no blocking if there's buffered data */
10626 timerec.tv_sec = timerec.tv_usec = 0;
10627 tp = &timerec;
10628 }
10629 rp = &fds[0];
10630 }
10631 else
10632 rp = 0;
10633
10634 if (!NIL_P(write)) {
10635 Check_Type(write, T_ARRAY);
10636 for (i=0; i<RARRAY_LEN(write); i++) {
10637 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10638 GetOpenFile(write_io, fptr);
10639 rb_fd_set(fptr->fd, &fds[1]);
10640 if (max < fptr->fd) max = fptr->fd;
10641 }
10642 wp = &fds[1];
10643 }
10644 else
10645 wp = 0;
10646
10647 if (!NIL_P(except)) {
10648 Check_Type(except, T_ARRAY);
10649 for (i=0; i<RARRAY_LEN(except); i++) {
10650 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10651 VALUE write_io = GetWriteIO(io);
10652 GetOpenFile(io, fptr);
10653 rb_fd_set(fptr->fd, &fds[2]);
10654 if (max < fptr->fd) max = fptr->fd;
10655 if (io != write_io) {
10656 GetOpenFile(write_io, fptr);
10657 rb_fd_set(fptr->fd, &fds[2]);
10658 if (max < fptr->fd) max = fptr->fd;
10659 }
10660 }
10661 ep = &fds[2];
10662 }
10663 else {
10664 ep = 0;
10665 }
10666
10667 max++;
10668
10669 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10670 if (n < 0) {
10671 rb_sys_fail(0);
10672 }
10673 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10674
10675 res = rb_ary_new2(3);
10676 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10677 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10678 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10679
10680 if (rp) {
10681 list = RARRAY_AREF(res, 0);
10682 for (i=0; i< RARRAY_LEN(read); i++) {
10683 VALUE obj = rb_ary_entry(read, i);
10684 VALUE io = rb_io_get_io(obj);
10685 GetOpenFile(io, fptr);
10686 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10687 rb_fd_isset(fptr->fd, &fds[3])) {
10688 rb_ary_push(list, obj);
10689 }
10690 }
10691 }
10692
10693 if (wp) {
10694 list = RARRAY_AREF(res, 1);
10695 for (i=0; i< RARRAY_LEN(write); i++) {
10696 VALUE obj = rb_ary_entry(write, i);
10697 VALUE io = rb_io_get_io(obj);
10698 VALUE write_io = GetWriteIO(io);
10699 GetOpenFile(write_io, fptr);
10700 if (rb_fd_isset(fptr->fd, &fds[1])) {
10701 rb_ary_push(list, obj);
10702 }
10703 }
10704 }
10705
10706 if (ep) {
10707 list = RARRAY_AREF(res, 2);
10708 for (i=0; i< RARRAY_LEN(except); i++) {
10709 VALUE obj = rb_ary_entry(except, i);
10710 VALUE io = rb_io_get_io(obj);
10711 VALUE write_io = GetWriteIO(io);
10712 GetOpenFile(io, fptr);
10713 if (rb_fd_isset(fptr->fd, &fds[2])) {
10714 rb_ary_push(list, obj);
10715 }
10716 else if (io != write_io) {
10717 GetOpenFile(write_io, fptr);
10718 if (rb_fd_isset(fptr->fd, &fds[2])) {
10719 rb_ary_push(list, obj);
10720 }
10721 }
10722 }
10723 }
10724
10725 return res; /* returns an empty array on interrupt */
10726}
10727
10728 struct select_args {
10729 VALUE read, write, except;
10730 struct timeval *timeout;
10731 rb_fdset_t fdsets[4];
10732};
10733
10734static VALUE
10735select_call(VALUE arg)
10736{
10737 struct select_args *p = (struct select_args *)arg;
10738
10739 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10740}
10741
10742static VALUE
10743select_end(VALUE arg)
10744{
10745 struct select_args *p = (struct select_args *)arg;
10746 int i;
10747
10748 for (i = 0; i < numberof(p->fdsets); ++i)
10749 rb_fd_term(&p->fdsets[i]);
10750 return Qnil;
10751}
10752
10753static VALUE sym_normal, sym_sequential, sym_random,
10754 sym_willneed, sym_dontneed, sym_noreuse;
10755
10756#ifdef HAVE_POSIX_FADVISE
10757struct io_advise_struct {
10758 int fd;
10759 int advice;
10760 rb_off_t offset;
10761 rb_off_t len;
10762};
10763
10764static VALUE
10765io_advise_internal(void *arg)
10766{
10767 struct io_advise_struct *ptr = arg;
10768 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10769}
10770
10771static VALUE
10772io_advise_sym_to_const(VALUE sym)
10773{
10774#ifdef POSIX_FADV_NORMAL
10775 if (sym == sym_normal)
10776 return INT2NUM(POSIX_FADV_NORMAL);
10777#endif
10778
10779#ifdef POSIX_FADV_RANDOM
10780 if (sym == sym_random)
10781 return INT2NUM(POSIX_FADV_RANDOM);
10782#endif
10783
10784#ifdef POSIX_FADV_SEQUENTIAL
10785 if (sym == sym_sequential)
10786 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10787#endif
10788
10789#ifdef POSIX_FADV_WILLNEED
10790 if (sym == sym_willneed)
10791 return INT2NUM(POSIX_FADV_WILLNEED);
10792#endif
10793
10794#ifdef POSIX_FADV_DONTNEED
10795 if (sym == sym_dontneed)
10796 return INT2NUM(POSIX_FADV_DONTNEED);
10797#endif
10798
10799#ifdef POSIX_FADV_NOREUSE
10800 if (sym == sym_noreuse)
10801 return INT2NUM(POSIX_FADV_NOREUSE);
10802#endif
10803
10804 return Qnil;
10805}
10806
10807static VALUE
10808do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10809{
10810 int rv;
10811 struct io_advise_struct ias;
10812 VALUE num_adv;
10813
10814 num_adv = io_advise_sym_to_const(advice);
10815
10816 /*
10817 * The platform doesn't support this hint. We don't raise exception, instead
10818 * silently ignore it. Because IO::advise is only hint.
10819 */
10820 if (NIL_P(num_adv))
10821 return Qnil;
10822
10823 ias.fd = fptr->fd;
10824 ias.advice = NUM2INT(num_adv);
10825 ias.offset = offset;
10826 ias.len = len;
10827
10828 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
10829 if (rv && rv != ENOSYS) {
10830 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10831 it returns the error code. */
10832 VALUE message = rb_sprintf("%"PRIsVALUE" "
10833 "(%"PRI_OFFT_PREFIX"d, "
10834 "%"PRI_OFFT_PREFIX"d, "
10835 "%"PRIsVALUE")",
10836 fptr->pathv, offset, len, advice);
10837 rb_syserr_fail_str(rv, message);
10838 }
10839
10840 return Qnil;
10841}
10842
10843#endif /* HAVE_POSIX_FADVISE */
10844
10845static void
10846advice_arg_check(VALUE advice)
10847{
10848 if (!SYMBOL_P(advice))
10849 rb_raise(rb_eTypeError, "advice must be a Symbol");
10850
10851 if (advice != sym_normal &&
10852 advice != sym_sequential &&
10853 advice != sym_random &&
10854 advice != sym_willneed &&
10855 advice != sym_dontneed &&
10856 advice != sym_noreuse) {
10857 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10858 }
10859}
10860
10861/*
10862 * call-seq:
10863 * advise(advice, offset = 0, len = 0) -> nil
10864 *
10865 * Invokes Posix system call
10866 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10867 * which announces an intention to access data from the current file
10868 * in a particular manner.
10869 *
10870 * The arguments and results are platform-dependent.
10871 *
10872 * The relevant data is specified by:
10873 *
10874 * - +offset+: The offset of the first byte of data.
10875 * - +len+: The number of bytes to be accessed;
10876 * if +len+ is zero, or is larger than the number of bytes remaining,
10877 * all remaining bytes will be accessed.
10878 *
10879 * Argument +advice+ is one of the following symbols:
10880 *
10881 * - +:normal+: The application has no advice to give
10882 * about its access pattern for the specified data.
10883 * If no advice is given for an open file, this is the default assumption.
10884 * - +:sequential+: The application expects to access the specified data sequentially
10885 * (with lower offsets read before higher ones).
10886 * - +:random+: The specified data will be accessed in random order.
10887 * - +:noreuse+: The specified data will be accessed only once.
10888 * - +:willneed+: The specified data will be accessed in the near future.
10889 * - +:dontneed+: The specified data will not be accessed in the near future.
10890 *
10891 * Not implemented on all platforms.
10892 *
10893 */
10894static VALUE
10895rb_io_advise(int argc, VALUE *argv, VALUE io)
10896{
10897 VALUE advice, offset, len;
10898 rb_off_t off, l;
10899 rb_io_t *fptr;
10900
10901 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10902 advice_arg_check(advice);
10903
10904 io = GetWriteIO(io);
10905 GetOpenFile(io, fptr);
10906
10907 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10908 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10909
10910#ifdef HAVE_POSIX_FADVISE
10911 return do_io_advise(fptr, advice, off, l);
10912#else
10913 ((void)off, (void)l); /* Ignore all hint */
10914 return Qnil;
10915#endif
10916}
10917
10918/*
10919 * call-seq:
10920 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10921 *
10922 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10923 * which monitors multiple file descriptors,
10924 * waiting until one or more of the file descriptors
10925 * becomes ready for some class of I/O operation.
10926 *
10927 * Not implemented on all platforms.
10928 *
10929 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10930 * is an array of IO objects.
10931 *
10932 * Argument +timeout+ is an integer timeout interval in seconds.
10933 *
10934 * The method monitors the \IO objects given in all three arrays,
10935 * waiting for some to be ready;
10936 * returns a 3-element array whose elements are:
10937 *
10938 * - An array of the objects in +read_ios+ that are ready for reading.
10939 * - An array of the objects in +write_ios+ that are ready for writing.
10940 * - An array of the objects in +error_ios+ have pending exceptions.
10941 *
10942 * If no object becomes ready within the given +timeout+, +nil+ is returned.
10943 *
10944 * \IO.select peeks the buffer of \IO objects for testing readability.
10945 * If the \IO buffer is not empty, \IO.select immediately notifies
10946 * readability. This "peek" only happens for \IO objects. It does not
10947 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10948 *
10949 * The best way to use \IO.select is invoking it after non-blocking
10950 * methods such as #read_nonblock, #write_nonblock, etc. The methods
10951 * raise an exception which is extended by IO::WaitReadable or
10952 * IO::WaitWritable. The modules notify how the caller should wait
10953 * with \IO.select. If IO::WaitReadable is raised, the caller should
10954 * wait for reading. If IO::WaitWritable is raised, the caller should
10955 * wait for writing.
10956 *
10957 * So, blocking read (#readpartial) can be emulated using
10958 * #read_nonblock and \IO.select as follows:
10959 *
10960 * begin
10961 * result = io_like.read_nonblock(maxlen)
10962 * rescue IO::WaitReadable
10963 * IO.select([io_like])
10964 * retry
10965 * rescue IO::WaitWritable
10966 * IO.select(nil, [io_like])
10967 * retry
10968 * end
10969 *
10970 * Especially, the combination of non-blocking methods and \IO.select is
10971 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
10972 * has #to_io method to return underlying IO object. IO.select calls
10973 * #to_io to obtain the file descriptor to wait.
10974 *
10975 * This means that readability notified by \IO.select doesn't mean
10976 * readability from OpenSSL::SSL::SSLSocket object.
10977 *
10978 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
10979 * some data. \IO.select doesn't see the buffer. So \IO.select can
10980 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
10981 *
10982 * However, several more complicated situations exist.
10983 *
10984 * SSL is a protocol which is sequence of records.
10985 * The record consists of multiple bytes.
10986 * So, the remote side of SSL sends a partial record, IO.select
10987 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
10988 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
10989 *
10990 * Also, the remote side can request SSL renegotiation which forces
10991 * the local SSL engine to write some data.
10992 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
10993 * system call and it can block.
10994 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
10995 * IO::WaitWritable instead of blocking.
10996 * So, the caller should wait for ready for writability as above
10997 * example.
10998 *
10999 * The combination of non-blocking methods and \IO.select is also useful
11000 * for streams such as tty, pipe socket socket when multiple processes
11001 * read from a stream.
11002 *
11003 * Finally, Linux kernel developers don't guarantee that
11004 * readability of select(2) means readability of following read(2) even
11005 * for a single process;
11006 * see {select(2)}[https://linux.die.net/man/2/select]
11007 *
11008 * Invoking \IO.select before IO#readpartial works well as usual.
11009 * However it is not the best way to use \IO.select.
11010 *
11011 * The writability notified by select(2) doesn't show
11012 * how many bytes are writable.
11013 * IO#write method blocks until given whole string is written.
11014 * So, <tt>IO#write(two or more bytes)</tt> can block after
11015 * writability is notified by \IO.select. IO#write_nonblock is required
11016 * to avoid the blocking.
11017 *
11018 * Blocking write (#write) can be emulated using #write_nonblock and
11019 * IO.select as follows: IO::WaitReadable should also be rescued for
11020 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11021 *
11022 * while 0 < string.bytesize
11023 * begin
11024 * written = io_like.write_nonblock(string)
11025 * rescue IO::WaitReadable
11026 * IO.select([io_like])
11027 * retry
11028 * rescue IO::WaitWritable
11029 * IO.select(nil, [io_like])
11030 * retry
11031 * end
11032 * string = string.byteslice(written..-1)
11033 * end
11034 *
11035 * Example:
11036 *
11037 * rp, wp = IO.pipe
11038 * mesg = "ping "
11039 * 100.times {
11040 * # IO.select follows IO#read. Not the best way to use IO.select.
11041 * rs, ws, = IO.select([rp], [wp])
11042 * if r = rs[0]
11043 * ret = r.read(5)
11044 * print ret
11045 * case ret
11046 * when /ping/
11047 * mesg = "pong\n"
11048 * when /pong/
11049 * mesg = "ping "
11050 * end
11051 * end
11052 * if w = ws[0]
11053 * w.write(mesg)
11054 * end
11055 * }
11056 *
11057 * Output:
11058 *
11059 * ping pong
11060 * ping pong
11061 * ping pong
11062 * (snipped)
11063 * ping
11064 *
11065 */
11066
11067static VALUE
11068rb_f_select(int argc, VALUE *argv, VALUE obj)
11069{
11070 VALUE scheduler = rb_fiber_scheduler_current();
11071 if (scheduler != Qnil) {
11072 // It's optionally supported.
11073 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11074 if (!UNDEF_P(result)) return result;
11075 }
11076
11077 VALUE timeout;
11078 struct select_args args;
11079 struct timeval timerec;
11080 int i;
11081
11082 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11083 if (NIL_P(timeout)) {
11084 args.timeout = 0;
11085 }
11086 else {
11087 timerec = rb_time_interval(timeout);
11088 args.timeout = &timerec;
11089 }
11090
11091 for (i = 0; i < numberof(args.fdsets); ++i)
11092 rb_fd_init(&args.fdsets[i]);
11093
11094 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11095}
11096
11097#ifdef IOCTL_REQ_TYPE
11098 typedef IOCTL_REQ_TYPE ioctl_req_t;
11099#else
11100 typedef int ioctl_req_t;
11101# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11102#endif
11103
11104#ifdef HAVE_IOCTL
11105struct ioctl_arg {
11106 int fd;
11107 ioctl_req_t cmd;
11108 long narg;
11109};
11110
11111static VALUE
11112nogvl_ioctl(void *ptr)
11113{
11114 struct ioctl_arg *arg = ptr;
11115
11116 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11117}
11118
11119static int
11120do_ioctl(int fd, ioctl_req_t cmd, long narg)
11121{
11122 int retval;
11123 struct ioctl_arg arg;
11124
11125 arg.fd = fd;
11126 arg.cmd = cmd;
11127 arg.narg = narg;
11128
11129 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
11130
11131 return retval;
11132}
11133#endif
11134
11135#define DEFAULT_IOCTL_NARG_LEN (256)
11136
11137#if defined(__linux__) && defined(_IOC_SIZE)
11138static long
11139linux_iocparm_len(ioctl_req_t cmd)
11140{
11141 long len;
11142
11143 if ((cmd & 0xFFFF0000) == 0) {
11144 /* legacy and unstructured ioctl number. */
11145 return DEFAULT_IOCTL_NARG_LEN;
11146 }
11147
11148 len = _IOC_SIZE(cmd);
11149
11150 /* paranoia check for silly drivers which don't keep ioctl convention */
11151 if (len < DEFAULT_IOCTL_NARG_LEN)
11152 len = DEFAULT_IOCTL_NARG_LEN;
11153
11154 return len;
11155}
11156#endif
11157
11158#ifdef HAVE_IOCTL
11159static long
11160ioctl_narg_len(ioctl_req_t cmd)
11161{
11162 long len;
11163
11164#ifdef IOCPARM_MASK
11165#ifndef IOCPARM_LEN
11166#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11167#endif
11168#endif
11169#ifdef IOCPARM_LEN
11170 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11171#elif defined(__linux__) && defined(_IOC_SIZE)
11172 len = linux_iocparm_len(cmd);
11173#else
11174 /* otherwise guess at what's safe */
11175 len = DEFAULT_IOCTL_NARG_LEN;
11176#endif
11177
11178 return len;
11179}
11180#endif
11181
11182#ifdef HAVE_FCNTL
11183#ifdef __linux__
11184typedef long fcntl_arg_t;
11185#else
11186/* posix */
11187typedef int fcntl_arg_t;
11188#endif
11189
11190static long
11191fcntl_narg_len(ioctl_req_t cmd)
11192{
11193 long len;
11194
11195 switch (cmd) {
11196#ifdef F_DUPFD
11197 case F_DUPFD:
11198 len = sizeof(fcntl_arg_t);
11199 break;
11200#endif
11201#ifdef F_DUP2FD /* bsd specific */
11202 case F_DUP2FD:
11203 len = sizeof(int);
11204 break;
11205#endif
11206#ifdef F_DUPFD_CLOEXEC /* linux specific */
11207 case F_DUPFD_CLOEXEC:
11208 len = sizeof(fcntl_arg_t);
11209 break;
11210#endif
11211#ifdef F_GETFD
11212 case F_GETFD:
11213 len = 1;
11214 break;
11215#endif
11216#ifdef F_SETFD
11217 case F_SETFD:
11218 len = sizeof(fcntl_arg_t);
11219 break;
11220#endif
11221#ifdef F_GETFL
11222 case F_GETFL:
11223 len = 1;
11224 break;
11225#endif
11226#ifdef F_SETFL
11227 case F_SETFL:
11228 len = sizeof(fcntl_arg_t);
11229 break;
11230#endif
11231#ifdef F_GETOWN
11232 case F_GETOWN:
11233 len = 1;
11234 break;
11235#endif
11236#ifdef F_SETOWN
11237 case F_SETOWN:
11238 len = sizeof(fcntl_arg_t);
11239 break;
11240#endif
11241#ifdef F_GETOWN_EX /* linux specific */
11242 case F_GETOWN_EX:
11243 len = sizeof(struct f_owner_ex);
11244 break;
11245#endif
11246#ifdef F_SETOWN_EX /* linux specific */
11247 case F_SETOWN_EX:
11248 len = sizeof(struct f_owner_ex);
11249 break;
11250#endif
11251#ifdef F_GETLK
11252 case F_GETLK:
11253 len = sizeof(struct flock);
11254 break;
11255#endif
11256#ifdef F_SETLK
11257 case F_SETLK:
11258 len = sizeof(struct flock);
11259 break;
11260#endif
11261#ifdef F_SETLKW
11262 case F_SETLKW:
11263 len = sizeof(struct flock);
11264 break;
11265#endif
11266#ifdef F_READAHEAD /* bsd specific */
11267 case F_READAHEAD:
11268 len = sizeof(int);
11269 break;
11270#endif
11271#ifdef F_RDAHEAD /* Darwin specific */
11272 case F_RDAHEAD:
11273 len = sizeof(int);
11274 break;
11275#endif
11276#ifdef F_GETSIG /* linux specific */
11277 case F_GETSIG:
11278 len = 1;
11279 break;
11280#endif
11281#ifdef F_SETSIG /* linux specific */
11282 case F_SETSIG:
11283 len = sizeof(fcntl_arg_t);
11284 break;
11285#endif
11286#ifdef F_GETLEASE /* linux specific */
11287 case F_GETLEASE:
11288 len = 1;
11289 break;
11290#endif
11291#ifdef F_SETLEASE /* linux specific */
11292 case F_SETLEASE:
11293 len = sizeof(fcntl_arg_t);
11294 break;
11295#endif
11296#ifdef F_NOTIFY /* linux specific */
11297 case F_NOTIFY:
11298 len = sizeof(fcntl_arg_t);
11299 break;
11300#endif
11301
11302 default:
11303 len = 256;
11304 break;
11305 }
11306
11307 return len;
11308}
11309#else /* HAVE_FCNTL */
11310static long
11311fcntl_narg_len(ioctl_req_t cmd)
11312{
11313 return 0;
11314}
11315#endif /* HAVE_FCNTL */
11316
11317#define NARG_SENTINEL 17
11318
11319static long
11320setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11321{
11322 long narg = 0;
11323 VALUE arg = *argp;
11324
11325 if (!RTEST(arg)) {
11326 narg = 0;
11327 }
11328 else if (FIXNUM_P(arg)) {
11329 narg = FIX2LONG(arg);
11330 }
11331 else if (arg == Qtrue) {
11332 narg = 1;
11333 }
11334 else {
11335 VALUE tmp = rb_check_string_type(arg);
11336
11337 if (NIL_P(tmp)) {
11338 narg = NUM2LONG(arg);
11339 }
11340 else {
11341 char *ptr;
11342 long len, slen;
11343
11344 *argp = arg = tmp;
11345 len = narg_len(cmd);
11346 rb_str_modify(arg);
11347
11348 slen = RSTRING_LEN(arg);
11349 /* expand for data + sentinel. */
11350 if (slen < len+1) {
11351 rb_str_resize(arg, len+1);
11352 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11353 slen = len+1;
11354 }
11355 /* a little sanity check here */
11356 ptr = RSTRING_PTR(arg);
11357 ptr[slen - 1] = NARG_SENTINEL;
11358 narg = (long)(SIGNED_VALUE)ptr;
11359 }
11360 }
11361
11362 return narg;
11363}
11364
11365static VALUE
11366finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11367{
11368 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11369 if (RB_TYPE_P(arg, T_STRING)) {
11370 char *ptr;
11371 long slen;
11372 RSTRING_GETMEM(arg, ptr, slen);
11373 if (ptr[slen-1] != NARG_SENTINEL)
11374 rb_raise(rb_eArgError, "return value overflowed string");
11375 ptr[slen-1] = '\0';
11376 }
11377
11378 return INT2NUM(retval);
11379}
11380
11381#ifdef HAVE_IOCTL
11382static VALUE
11383rb_ioctl(VALUE io, VALUE req, VALUE arg)
11384{
11385 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11386 rb_io_t *fptr;
11387 long narg;
11388 int retval;
11389
11390 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11391 GetOpenFile(io, fptr);
11392 retval = do_ioctl(fptr->fd, cmd, narg);
11393 return finish_narg(retval, arg, fptr);
11394}
11395
11396/*
11397 * call-seq:
11398 * ioctl(integer_cmd, argument) -> integer
11399 *
11400 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11401 * which issues a low-level command to an I/O device.
11402 *
11403 * Issues a low-level command to an I/O device.
11404 * The arguments and returned value are platform-dependent.
11405 * The effect of the call is platform-dependent.
11406 *
11407 * If argument +argument+ is an integer, it is passed directly;
11408 * if it is a string, it is interpreted as a binary sequence of bytes.
11409 *
11410 * Not implemented on all platforms.
11411 *
11412 */
11413
11414static VALUE
11415rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11416{
11417 VALUE req, arg;
11418
11419 rb_scan_args(argc, argv, "11", &req, &arg);
11420 return rb_ioctl(io, req, arg);
11421}
11422#else
11423#define rb_io_ioctl rb_f_notimplement
11424#endif
11425
11426#ifdef HAVE_FCNTL
11427struct fcntl_arg {
11428 int fd;
11429 int cmd;
11430 long narg;
11431};
11432
11433static VALUE
11434nogvl_fcntl(void *ptr)
11435{
11436 struct fcntl_arg *arg = ptr;
11437
11438#if defined(F_DUPFD)
11439 if (arg->cmd == F_DUPFD)
11440 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11441#endif
11442 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11443}
11444
11445static int
11446do_fcntl(int fd, int cmd, long narg)
11447{
11448 int retval;
11449 struct fcntl_arg arg;
11450
11451 arg.fd = fd;
11452 arg.cmd = cmd;
11453 arg.narg = narg;
11454
11455 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
11456 if (retval != -1) {
11457 switch (cmd) {
11458#if defined(F_DUPFD)
11459 case F_DUPFD:
11460#endif
11461#if defined(F_DUPFD_CLOEXEC)
11462 case F_DUPFD_CLOEXEC:
11463#endif
11464 rb_update_max_fd(retval);
11465 }
11466 }
11467
11468 return retval;
11469}
11470
11471static VALUE
11472rb_fcntl(VALUE io, VALUE req, VALUE arg)
11473{
11474 int cmd = NUM2INT(req);
11475 rb_io_t *fptr;
11476 long narg;
11477 int retval;
11478
11479 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11480 GetOpenFile(io, fptr);
11481 retval = do_fcntl(fptr->fd, cmd, narg);
11482 return finish_narg(retval, arg, fptr);
11483}
11484
11485/*
11486 * call-seq:
11487 * fcntl(integer_cmd, argument) -> integer
11488 *
11489 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11490 * which provides a mechanism for issuing low-level commands to control or query
11491 * a file-oriented I/O stream. Arguments and results are platform
11492 * dependent.
11493 *
11494 * If +argument+ is a number, its value is passed directly;
11495 * if it is a string, it is interpreted as a binary sequence of bytes.
11496 * (Array#pack might be a useful way to build this string.)
11497 *
11498 * Not implemented on all platforms.
11499 *
11500 */
11501
11502static VALUE
11503rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11504{
11505 VALUE req, arg;
11506
11507 rb_scan_args(argc, argv, "11", &req, &arg);
11508 return rb_fcntl(io, req, arg);
11509}
11510#else
11511#define rb_io_fcntl rb_f_notimplement
11512#endif
11513
11514#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11515/*
11516 * call-seq:
11517 * syscall(integer_callno, *arguments) -> integer
11518 *
11519 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11520 * which calls a specified function.
11521 *
11522 * Calls the operating system function identified by +integer_callno+;
11523 * returns the result of the function or raises SystemCallError if it failed.
11524 * The effect of the call is platform-dependent.
11525 * The arguments and returned value are platform-dependent.
11526 *
11527 * For each of +arguments+: if it is an integer, it is passed directly;
11528 * if it is a string, it is interpreted as a binary sequence of bytes.
11529 * There may be as many as nine such arguments.
11530 *
11531 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11532 * are platform-dependent.
11533 *
11534 * Note: Method +syscall+ is essentially unsafe and unportable.
11535 * The DL (Fiddle) library is preferred for safer and a bit
11536 * more portable programming.
11537 *
11538 * Not implemented on all platforms.
11539 *
11540 */
11541
11542static VALUE
11543rb_f_syscall(int argc, VALUE *argv, VALUE _)
11544{
11545 VALUE arg[8];
11546#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11547# define SYSCALL __syscall
11548# define NUM2SYSCALLID(x) NUM2LONG(x)
11549# define RETVAL2NUM(x) LONG2NUM(x)
11550# if SIZEOF_LONG == 8
11551 long num, retval = -1;
11552# elif SIZEOF_LONG_LONG == 8
11553 long long num, retval = -1;
11554# else
11555# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11556# endif
11557#elif defined(__linux__)
11558# define SYSCALL syscall
11559# define NUM2SYSCALLID(x) NUM2LONG(x)
11560# define RETVAL2NUM(x) LONG2NUM(x)
11561 /*
11562 * Linux man page says, syscall(2) function prototype is below.
11563 *
11564 * int syscall(int number, ...);
11565 *
11566 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11567 */
11568 long num, retval = -1;
11569#else
11570# define SYSCALL syscall
11571# define NUM2SYSCALLID(x) NUM2INT(x)
11572# define RETVAL2NUM(x) INT2NUM(x)
11573 int num, retval = -1;
11574#endif
11575 int i;
11576
11577 if (RTEST(ruby_verbose)) {
11578 rb_category_warning(RB_WARN_CATEGORY_DEPRECATED,
11579 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11580 }
11581
11582 if (argc == 0)
11583 rb_raise(rb_eArgError, "too few arguments for syscall");
11584 if (argc > numberof(arg))
11585 rb_raise(rb_eArgError, "too many arguments for syscall");
11586 num = NUM2SYSCALLID(argv[0]); ++argv;
11587 for (i = argc - 1; i--; ) {
11588 VALUE v = rb_check_string_type(argv[i]);
11589
11590 if (!NIL_P(v)) {
11591 SafeStringValue(v);
11592 rb_str_modify(v);
11593 arg[i] = (VALUE)StringValueCStr(v);
11594 }
11595 else {
11596 arg[i] = (VALUE)NUM2LONG(argv[i]);
11597 }
11598 }
11599
11600 switch (argc) {
11601 case 1:
11602 retval = SYSCALL(num);
11603 break;
11604 case 2:
11605 retval = SYSCALL(num, arg[0]);
11606 break;
11607 case 3:
11608 retval = SYSCALL(num, arg[0],arg[1]);
11609 break;
11610 case 4:
11611 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11612 break;
11613 case 5:
11614 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11615 break;
11616 case 6:
11617 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11618 break;
11619 case 7:
11620 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11621 break;
11622 case 8:
11623 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11624 break;
11625 }
11626
11627 if (retval == -1)
11628 rb_sys_fail(0);
11629 return RETVAL2NUM(retval);
11630#undef SYSCALL
11631#undef NUM2SYSCALLID
11632#undef RETVAL2NUM
11633}
11634#else
11635#define rb_f_syscall rb_f_notimplement
11636#endif
11637
11638static VALUE
11639io_new_instance(VALUE args)
11640{
11641 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11642}
11643
11644static rb_encoding *
11645find_encoding(VALUE v)
11646{
11647 rb_encoding *enc = rb_find_encoding(v);
11648 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11649 return enc;
11650}
11651
11652static void
11653io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11654{
11655 rb_encoding *enc, *enc2;
11656 int ecflags = fptr->encs.ecflags;
11657 VALUE ecopts, tmp;
11658
11659 if (!NIL_P(v2)) {
11660 enc2 = find_encoding(v1);
11661 tmp = rb_check_string_type(v2);
11662 if (!NIL_P(tmp)) {
11663 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11664 /* Special case - "-" => no transcoding */
11665 enc = enc2;
11666 enc2 = NULL;
11667 }
11668 else
11669 enc = find_encoding(v2);
11670 if (enc == enc2) {
11671 /* Special case - "-" => no transcoding */
11672 enc2 = NULL;
11673 }
11674 }
11675 else {
11676 enc = find_encoding(v2);
11677 if (enc == enc2) {
11678 /* Special case - "-" => no transcoding */
11679 enc2 = NULL;
11680 }
11681 }
11682 if (enc2 == rb_ascii8bit_encoding()) {
11683 /* If external is ASCII-8BIT, no transcoding */
11684 enc = enc2;
11685 enc2 = NULL;
11686 }
11687 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11688 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11689 }
11690 else {
11691 if (NIL_P(v1)) {
11692 /* Set to default encodings */
11693 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11694 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11695 ecopts = Qnil;
11696 }
11697 else {
11698 tmp = rb_check_string_type(v1);
11699 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11700 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11701 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11702 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11703 }
11704 else {
11705 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11706 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11707 ecopts = Qnil;
11708 }
11709 }
11710 }
11711 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11712 fptr->encs.enc = enc;
11713 fptr->encs.enc2 = enc2;
11714 fptr->encs.ecflags = ecflags;
11715 fptr->encs.ecopts = ecopts;
11716 clear_codeconv(fptr);
11717
11718}
11719
11720 struct io_encoding_set_args {
11721 rb_io_t *fptr;
11722 VALUE v1;
11723 VALUE v2;
11724 VALUE opt;
11725};
11726
11727static VALUE
11728io_encoding_set_v(VALUE v)
11729{
11730 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11731 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11732 return Qnil;
11733}
11734
11735static VALUE
11736pipe_pair_close(VALUE rw)
11737{
11738 VALUE *rwp = (VALUE *)rw;
11739 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11740}
11741
11742/*
11743 * call-seq:
11744 * IO.pipe(**opts) -> [read_io, write_io]
11745 * IO.pipe(enc, **opts) -> [read_io, write_io]
11746 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11747 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11748 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11749 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11750 *
11751 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11752 * connected to each other.
11753 *
11754 * If argument +enc_string+ is given, it must be a string containing one of:
11755 *
11756 * - The name of the encoding to be used as the external encoding.
11757 * - The colon-separated names of two encodings to be used as the external
11758 * and internal encodings.
11759 *
11760 * If argument +int_enc+ is given, it must be an Encoding object
11761 * or encoding name string that specifies the internal encoding to be used;
11762 * if argument +ext_enc+ is also given, it must be an Encoding object
11763 * or encoding name string that specifies the external encoding to be used.
11764 *
11765 * The string read from +read_io+ is tagged with the external encoding;
11766 * if an internal encoding is also specified, the string is converted
11767 * to, and tagged with, that encoding.
11768 *
11769 * If any encoding is specified,
11770 * optional hash arguments specify the conversion option.
11771 *
11772 * Optional keyword arguments +opts+ specify:
11773 *
11774 * - {Open Options}[rdoc-ref:IO@Open+Options].
11775 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11776 *
11777 * With no block given, returns the two endpoints in an array:
11778 *
11779 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11780 *
11781 * With a block given, calls the block with the two endpoints;
11782 * closes both endpoints and returns the value of the block:
11783 *
11784 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11785 *
11786 * Output:
11787 *
11788 * #<IO:fd 6>
11789 * #<IO:fd 7>
11790 *
11791 * Not available on all platforms.
11792 *
11793 * In the example below, the two processes close the ends of the pipe
11794 * that they are not using. This is not just a cosmetic nicety. The
11795 * read end of a pipe will not generate an end of file condition if
11796 * there are any writers with the pipe still open. In the case of the
11797 * parent process, the <tt>rd.read</tt> will never return if it
11798 * does not first issue a <tt>wr.close</tt>:
11799 *
11800 * rd, wr = IO.pipe
11801 *
11802 * if fork
11803 * wr.close
11804 * puts "Parent got: <#{rd.read}>"
11805 * rd.close
11806 * Process.wait
11807 * else
11808 * rd.close
11809 * puts 'Sending message to parent'
11810 * wr.write "Hi Dad"
11811 * wr.close
11812 * end
11813 *
11814 * <em>produces:</em>
11815 *
11816 * Sending message to parent
11817 * Parent got: <Hi Dad>
11818 *
11819 */
11820
11821static VALUE
11822rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11823{
11824 int pipes[2], state;
11825 VALUE r, w, args[3], v1, v2;
11826 VALUE opt;
11827 rb_io_t *fptr, *fptr2;
11828 struct io_encoding_set_args ies_args;
11829 int fmode = 0;
11830 VALUE ret;
11831
11832 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11833 if (rb_pipe(pipes) < 0)
11834 rb_sys_fail(0);
11835
11836 args[0] = klass;
11837 args[1] = INT2NUM(pipes[0]);
11838 args[2] = INT2FIX(O_RDONLY);
11839 r = rb_protect(io_new_instance, (VALUE)args, &state);
11840 if (state) {
11841 close(pipes[0]);
11842 close(pipes[1]);
11843 rb_jump_tag(state);
11844 }
11845 GetOpenFile(r, fptr);
11846
11847 ies_args.fptr = fptr;
11848 ies_args.v1 = v1;
11849 ies_args.v2 = v2;
11850 ies_args.opt = opt;
11851 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11852 if (state) {
11853 close(pipes[1]);
11854 io_close(r);
11855 rb_jump_tag(state);
11856 }
11857
11858 args[1] = INT2NUM(pipes[1]);
11859 args[2] = INT2FIX(O_WRONLY);
11860 w = rb_protect(io_new_instance, (VALUE)args, &state);
11861 if (state) {
11862 close(pipes[1]);
11863 if (!NIL_P(r)) rb_io_close(r);
11864 rb_jump_tag(state);
11865 }
11866 GetOpenFile(w, fptr2);
11867 rb_io_synchronized(fptr2);
11868
11869 extract_binmode(opt, &fmode);
11870
11871 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11872 rb_io_ascii8bit_binmode(r);
11873 rb_io_ascii8bit_binmode(w);
11874 }
11875
11876#if DEFAULT_TEXTMODE
11877 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11878 fptr->mode &= ~FMODE_TEXTMODE;
11879 setmode(fptr->fd, O_BINARY);
11880 }
11881#if RUBY_CRLF_ENVIRONMENT
11882 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
11883 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
11884 }
11885#endif
11886#endif
11887 fptr->mode |= fmode;
11888#if DEFAULT_TEXTMODE
11889 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11890 fptr2->mode &= ~FMODE_TEXTMODE;
11891 setmode(fptr2->fd, O_BINARY);
11892 }
11893#endif
11894 fptr2->mode |= fmode;
11895
11896 ret = rb_assoc_new(r, w);
11897 if (rb_block_given_p()) {
11898 VALUE rw[2];
11899 rw[0] = r;
11900 rw[1] = w;
11901 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11902 }
11903 return ret;
11904}
11905
11906 struct foreach_arg {
11907 int argc;
11908 VALUE *argv;
11909 VALUE io;
11910};
11911
11912static void
11913open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11914{
11915 VALUE path, v;
11916 VALUE vmode = Qnil, vperm = Qnil;
11917
11918 path = *argv++;
11919 argc--;
11920 FilePathValue(path);
11921 arg->io = 0;
11922 arg->argc = argc;
11923 arg->argv = argv;
11924 if (NIL_P(opt)) {
11925 vmode = INT2NUM(O_RDONLY);
11926 vperm = INT2FIX(0666);
11927 }
11928 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11929 int n;
11930
11931 v = rb_to_array_type(v);
11932 n = RARRAY_LENINT(v);
11933 rb_check_arity(n, 0, 3); /* rb_io_open */
11934 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11935 }
11936 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11937}
11938
11939static VALUE
11940io_s_foreach(VALUE v)
11941{
11942 struct getline_arg *arg = (void *)v;
11943 VALUE str;
11944
11945 if (arg->limit == 0)
11946 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
11947 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11948 rb_lastline_set(str);
11949 rb_yield(str);
11950 }
11951 rb_lastline_set(Qnil);
11952 return Qnil;
11953}
11954
11955/*
11956 * call-seq:
11957 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
11958 * IO.foreach(path, limit, **opts) {|line| block } -> nil
11959 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
11960 * IO.foreach(...) -> an_enumerator
11961 *
11962 * Calls the block with each successive line read from the stream.
11963 *
11964 * When called from class \IO (but not subclasses of \IO),
11965 * this method has potential security vulnerabilities if called with untrusted input;
11966 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11967 *
11968 * The first argument must be a string that is the path to a file.
11969 *
11970 * With only argument +path+ given, parses lines from the file at the given +path+,
11971 * as determined by the default line separator,
11972 * and calls the block with each successive line:
11973 *
11974 * File.foreach('t.txt') {|line| p line }
11975 *
11976 * Output: the same as above.
11977 *
11978 * For both forms, command and path, the remaining arguments are the same.
11979 *
11980 * With argument +sep+ given, parses lines as determined by that line separator
11981 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
11982 *
11983 * File.foreach('t.txt', 'li') {|line| p line }
11984 *
11985 * Output:
11986 *
11987 * "First li"
11988 * "ne\nSecond li"
11989 * "ne\n\nThird li"
11990 * "ne\nFourth li"
11991 * "ne\n"
11992 *
11993 * Each paragraph:
11994 *
11995 * File.foreach('t.txt', '') {|paragraph| p paragraph }
11996 *
11997 * Output:
11998 *
11999 * "First line\nSecond line\n\n"
12000 * "Third line\nFourth line\n"
12001 *
12002 * With argument +limit+ given, parses lines as determined by the default
12003 * line separator and the given line-length limit
12004 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
12005 *
12006 * File.foreach('t.txt', 7) {|line| p line }
12007 *
12008 * Output:
12009 *
12010 * "First l"
12011 * "ine\n"
12012 * "Second "
12013 * "line\n"
12014 * "\n"
12015 * "Third l"
12016 * "ine\n"
12017 * "Fourth l"
12018 * "line\n"
12019 *
12020 * With arguments +sep+ and +limit+ given,
12021 * parses lines as determined by the given
12022 * line separator and the given line-length limit
12023 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
12024 *
12025 * Optional keyword arguments +opts+ specify:
12026 *
12027 * - {Open Options}[rdoc-ref:IO@Open+Options].
12028 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12029 * - {Line Options}[rdoc-ref:IO@Line+IO].
12030 *
12031 * Returns an Enumerator if no block is given.
12032 *
12033 */
12034
12035static VALUE
12036rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12037{
12038 VALUE opt;
12039 int orig_argc = argc;
12040 struct foreach_arg arg;
12041 struct getline_arg garg;
12042
12043 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12044 RETURN_ENUMERATOR(self, orig_argc, argv);
12045 extract_getline_args(argc-1, argv+1, &garg);
12046 open_key_args(self, argc, argv, opt, &arg);
12047 if (NIL_P(arg.io)) return Qnil;
12048 extract_getline_opts(opt, &garg);
12049 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12050 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12051}
12052
12053static VALUE
12054io_s_readlines(VALUE v)
12055{
12056 struct getline_arg *arg = (void *)v;
12057 return io_readlines(arg, arg->io);
12058}
12059
12060/*
12061 * call-seq:
12062 * IO.readlines(path, sep = $/, **opts) -> array
12063 * IO.readlines(path, limit, **opts) -> array
12064 * IO.readlines(path, sep, limit, **opts) -> array
12065 *
12066 * Returns an array of all lines read from the stream.
12067 *
12068 * When called from class \IO (but not subclasses of \IO),
12069 * this method has potential security vulnerabilities if called with untrusted input;
12070 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12071 *
12072 * The first argument must be a string that is the path to a file.
12073 *
12074 * With only argument +path+ given, parses lines from the file at the given +path+,
12075 * as determined by the default line separator,
12076 * and returns those lines in an array:
12077 *
12078 * IO.readlines('t.txt')
12079 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12080 *
12081 * With argument +sep+ given, parses lines as determined by that line separator
12082 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12083 *
12084 * # Ordinary separator.
12085 * IO.readlines('t.txt', 'li')
12086 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12087 * # Get-paragraphs separator.
12088 * IO.readlines('t.txt', '')
12089 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12090 * # Get-all separator.
12091 * IO.readlines('t.txt', nil)
12092 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12093 *
12094 * With argument +limit+ given, parses lines as determined by the default
12095 * line separator and the given line-length limit
12096 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
12097 *
12098 * IO.readlines('t.txt', 7)
12099 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12100 *
12101 * With arguments +sep+ and +limit+ given,
12102 * parses lines as determined by the given
12103 * line separator and the given line-length limit
12104 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
12105 *
12106 * Optional keyword arguments +opts+ specify:
12107 *
12108 * - {Open Options}[rdoc-ref:IO@Open+Options].
12109 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12110 * - {Line Options}[rdoc-ref:IO@Line+IO].
12111 *
12112 */
12113
12114static VALUE
12115rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12116{
12117 VALUE opt;
12118 struct foreach_arg arg;
12119 struct getline_arg garg;
12120
12121 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12122 extract_getline_args(argc-1, argv+1, &garg);
12123 open_key_args(io, argc, argv, opt, &arg);
12124 if (NIL_P(arg.io)) return Qnil;
12125 extract_getline_opts(opt, &garg);
12126 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12127 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12128}
12129
12130static VALUE
12131io_s_read(VALUE v)
12132{
12133 struct foreach_arg *arg = (void *)v;
12134 return io_read(arg->argc, arg->argv, arg->io);
12135}
12136
12137 struct seek_arg {
12138 VALUE io;
12139 VALUE offset;
12140 int mode;
12141};
12142
12143static VALUE
12144seek_before_access(VALUE argp)
12145{
12146 struct seek_arg *arg = (struct seek_arg *)argp;
12147 rb_io_binmode(arg->io);
12148 return rb_io_seek(arg->io, arg->offset, arg->mode);
12149}
12150
12151/*
12152 * call-seq:
12153 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12154 *
12155 * Opens the stream, reads and returns some or all of its content,
12156 * and closes the stream; returns +nil+ if no bytes were read.
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 * The first argument must be a string that is the path to a file.
12163 *
12164 * With only argument +path+ given, reads in text mode and returns the entire content
12165 * of the file at the given path:
12166 *
12167 * IO.read('t.txt')
12168 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12169 *
12170 * On Windows, text mode can terminate reading and leave bytes in the file
12171 * unread when encountering certain special bytes. Consider using
12172 * IO.binread if all bytes in the file should be read.
12173 *
12174 * With argument +length+, returns +length+ bytes if available:
12175 *
12176 * IO.read('t.txt', 7) # => "First l"
12177 * IO.read('t.txt', 700)
12178 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12179 *
12180 * With arguments +length+ and +offset+, returns +length+ bytes
12181 * if available, beginning at the given +offset+:
12182 *
12183 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12184 * IO.read('t.txt', 10, 200) # => nil
12185 *
12186 * Optional keyword arguments +opts+ specify:
12187 *
12188 * - {Open Options}[rdoc-ref:IO@Open+Options].
12189 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12190 *
12191 */
12192
12193static VALUE
12194rb_io_s_read(int argc, VALUE *argv, VALUE io)
12195{
12196 VALUE opt, offset;
12197 long off;
12198 struct foreach_arg arg;
12199
12200 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12201 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12202 rb_raise(rb_eArgError, "negative offset %ld given", off);
12203 }
12204 open_key_args(io, argc, argv, opt, &arg);
12205 if (NIL_P(arg.io)) return Qnil;
12206 if (!NIL_P(offset)) {
12207 struct seek_arg sarg;
12208 int state = 0;
12209 sarg.io = arg.io;
12210 sarg.offset = offset;
12211 sarg.mode = SEEK_SET;
12212 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12213 if (state) {
12214 rb_io_close(arg.io);
12215 rb_jump_tag(state);
12216 }
12217 if (arg.argc == 2) arg.argc = 1;
12218 }
12219 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12220}
12221
12222/*
12223 * call-seq:
12224 * IO.binread(path, length = nil, offset = 0) -> string or nil
12225 *
12226 * Behaves like IO.read, except that the stream is opened in binary mode
12227 * with ASCII-8BIT encoding.
12228 *
12229 * When called from class \IO (but not subclasses of \IO),
12230 * this method has potential security vulnerabilities if called with untrusted input;
12231 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12232 *
12233 */
12234
12235static VALUE
12236rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12237{
12238 VALUE offset;
12239 struct foreach_arg arg;
12240 enum {
12241 fmode = FMODE_READABLE|FMODE_BINMODE,
12242 oflags = O_RDONLY
12243#ifdef O_BINARY
12244 |O_BINARY
12245#endif
12246 };
12247 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12248
12249 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12250 FilePathValue(argv[0]);
12251 convconfig.enc = rb_ascii8bit_encoding();
12252 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12253 if (NIL_P(arg.io)) return Qnil;
12254 arg.argv = argv+1;
12255 arg.argc = (argc > 1) ? 1 : 0;
12256 if (!NIL_P(offset)) {
12257 struct seek_arg sarg;
12258 int state = 0;
12259 sarg.io = arg.io;
12260 sarg.offset = offset;
12261 sarg.mode = SEEK_SET;
12262 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12263 if (state) {
12264 rb_io_close(arg.io);
12265 rb_jump_tag(state);
12266 }
12267 }
12268 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12269}
12270
12271static VALUE
12272io_s_write0(VALUE v)
12273{
12274 struct write_arg *arg = (void *)v;
12275 return io_write(arg->io,arg->str,arg->nosync);
12276}
12277
12278static VALUE
12279io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12280{
12281 VALUE string, offset, opt;
12282 struct foreach_arg arg;
12283 struct write_arg warg;
12284
12285 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12286
12287 if (NIL_P(opt)) opt = rb_hash_new();
12288 else opt = rb_hash_dup(opt);
12289
12290
12291 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12292 int mode = O_WRONLY|O_CREAT;
12293#ifdef O_BINARY
12294 if (binary) mode |= O_BINARY;
12295#endif
12296 if (NIL_P(offset)) mode |= O_TRUNC;
12297 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12298 }
12299 open_key_args(klass, argc, argv, opt, &arg);
12300
12301#ifndef O_BINARY
12302 if (binary) rb_io_binmode_m(arg.io);
12303#endif
12304
12305 if (NIL_P(arg.io)) return Qnil;
12306 if (!NIL_P(offset)) {
12307 struct seek_arg sarg;
12308 int state = 0;
12309 sarg.io = arg.io;
12310 sarg.offset = offset;
12311 sarg.mode = SEEK_SET;
12312 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12313 if (state) {
12314 rb_io_close(arg.io);
12315 rb_jump_tag(state);
12316 }
12317 }
12318
12319 warg.io = arg.io;
12320 warg.str = string;
12321 warg.nosync = 0;
12322
12323 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12324}
12325
12326/*
12327 * call-seq:
12328 * IO.write(path, data, offset = 0, **opts) -> integer
12329 *
12330 * Opens the stream, writes the given +data+ to it,
12331 * and closes the stream; returns the number of bytes written.
12332 *
12333 * When called from class \IO (but not subclasses of \IO),
12334 * this method has potential security vulnerabilities if called with untrusted input;
12335 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12336 *
12337 * The first argument must be a string that is the path to a file.
12338 *
12339 * With only argument +path+ given, writes the given +data+ to the file at that path:
12340 *
12341 * IO.write('t.tmp', 'abc') # => 3
12342 * File.read('t.tmp') # => "abc"
12343 *
12344 * If +offset+ is zero (the default), the file is overwritten:
12345 *
12346 * IO.write('t.tmp', 'A') # => 1
12347 * File.read('t.tmp') # => "A"
12348 *
12349 * If +offset+ in within the file content, the file is partly overwritten:
12350 *
12351 * IO.write('t.tmp', 'abcdef') # => 3
12352 * File.read('t.tmp') # => "abcdef"
12353 * # Offset within content.
12354 * IO.write('t.tmp', '012', 2) # => 3
12355 * File.read('t.tmp') # => "ab012f"
12356 *
12357 * If +offset+ is outside the file content,
12358 * the file is padded with null characters <tt>"\u0000"</tt>:
12359 *
12360 * IO.write('t.tmp', 'xyz', 10) # => 3
12361 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12362 *
12363 * Optional keyword arguments +opts+ specify:
12364 *
12365 * - {Open Options}[rdoc-ref:IO@Open+Options].
12366 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12367 *
12368 */
12369
12370static VALUE
12371rb_io_s_write(int argc, VALUE *argv, VALUE io)
12372{
12373 return io_s_write(argc, argv, io, 0);
12374}
12375
12376/*
12377 * call-seq:
12378 * IO.binwrite(path, string, offset = 0) -> integer
12379 *
12380 * Behaves like IO.write, except that the stream is opened in binary mode
12381 * with ASCII-8BIT encoding.
12382 *
12383 * When called from class \IO (but not subclasses of \IO),
12384 * this method has potential security vulnerabilities if called with untrusted input;
12385 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12386 *
12387 */
12388
12389static VALUE
12390rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12391{
12392 return io_s_write(argc, argv, io, 1);
12393}
12394
12395 struct copy_stream_struct {
12396 VALUE src;
12397 VALUE dst;
12398 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12399 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12400
12401 rb_io_t *src_fptr;
12402 rb_io_t *dst_fptr;
12403 unsigned close_src : 1;
12404 unsigned close_dst : 1;
12405 int error_no;
12406 rb_off_t total;
12407 const char *syserr;
12408 const char *notimp;
12409 VALUE th;
12410 struct stat src_stat;
12411 struct stat dst_stat;
12412#ifdef HAVE_FCOPYFILE
12413 copyfile_state_t copyfile_state;
12414#endif
12415};
12416
12417static void *
12418exec_interrupts(void *arg)
12419{
12420 VALUE th = (VALUE)arg;
12421 rb_thread_execute_interrupts(th);
12422 return NULL;
12423}
12424
12425/*
12426 * returns TRUE if the preceding system call was interrupted
12427 * so we can continue. If the thread was interrupted, we
12428 * reacquire the GVL to execute interrupts before continuing.
12429 */
12430static int
12431maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12432{
12433 switch (errno) {
12434 case EINTR:
12435#if defined(ERESTART)
12436 case ERESTART:
12437#endif
12438 if (rb_thread_interrupted(stp->th)) {
12439 if (has_gvl)
12440 rb_thread_execute_interrupts(stp->th);
12441 else
12442 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12443 }
12444 return TRUE;
12445 }
12446 return FALSE;
12447}
12448
12449 struct fiber_scheduler_wait_for_arguments {
12450 VALUE scheduler;
12451
12452 rb_io_t *fptr;
12453 short events;
12454
12455 VALUE result;
12456};
12457
12458static void *
12459fiber_scheduler_wait_for(void * _arguments)
12460{
12461 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12462
12463 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12464
12465 return NULL;
12466}
12467
12468#if USE_POLL
12469# define IOWAIT_SYSCALL "poll"
12470STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12471STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12472static int
12473nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12474{
12475 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
12476 if (scheduler != Qnil) {
12477 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12478 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12479 return RTEST(args.result);
12480 }
12481
12482 int fd = fptr->fd;
12483 if (fd == -1) return 0;
12484
12485 struct pollfd fds;
12486
12487 fds.fd = fd;
12488 fds.events = events;
12489
12490 int timeout_milliseconds = -1;
12491
12492 if (timeout) {
12493 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12494 }
12495
12496 return poll(&fds, 1, timeout_milliseconds);
12497}
12498#else /* !USE_POLL */
12499# define IOWAIT_SYSCALL "select"
12500static int
12501nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12502{
12503 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
12504 if (scheduler != Qnil) {
12505 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12506 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12507 return RTEST(args.result);
12508 }
12509
12510 int fd = fptr->fd;
12511
12512 if (fd == -1) {
12513 errno = EBADF;
12514 return -1;
12515 }
12516
12517 rb_fdset_t fds;
12518 int ret;
12519
12520 rb_fd_init(&fds);
12521 rb_fd_set(fd, &fds);
12522
12523 switch (events) {
12524 case RB_WAITFD_IN:
12525 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12526 break;
12527 case RB_WAITFD_OUT:
12528 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12529 break;
12530 default:
12531 VM_UNREACHABLE(nogvl_wait_for);
12532 }
12533
12534 rb_fd_term(&fds);
12535
12536 // On timeout, this returns 0.
12537 return ret;
12538}
12539#endif /* !USE_POLL */
12540
12541static int
12542maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12543{
12544 int ret;
12545
12546 do {
12547 if (has_gvl) {
12548 ret = RB_NUM2INT(rb_io_wait(stp->src, RB_INT2NUM(RUBY_IO_READABLE), Qnil));
12549 }
12550 else {
12551 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12552 }
12553 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12554
12555 if (ret < 0) {
12556 stp->syserr = IOWAIT_SYSCALL;
12557 stp->error_no = errno;
12558 return ret;
12559 }
12560 return 0;
12561}
12562
12563static int
12564nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12565{
12566 int ret;
12567
12568 do {
12569 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12570 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12571
12572 if (ret < 0) {
12573 stp->syserr = IOWAIT_SYSCALL;
12574 stp->error_no = errno;
12575 return ret;
12576 }
12577 return 0;
12578}
12579
12580#ifdef USE_COPY_FILE_RANGE
12581
12582static ssize_t
12583simple_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)
12584{
12585#ifdef HAVE_COPY_FILE_RANGE
12586 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12587#else
12588 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12589#endif
12590}
12591
12592static int
12593nogvl_copy_file_range(struct copy_stream_struct *stp)
12594{
12595 ssize_t ss;
12596 rb_off_t src_size;
12597 rb_off_t copy_length, src_offset, *src_offset_ptr;
12598
12599 if (!S_ISREG(stp->src_stat.st_mode))
12600 return 0;
12601
12602 src_size = stp->src_stat.st_size;
12603 src_offset = stp->src_offset;
12604 if (src_offset >= (rb_off_t)0) {
12605 src_offset_ptr = &src_offset;
12606 }
12607 else {
12608 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12609 }
12610
12611 copy_length = stp->copy_length;
12612 if (copy_length < (rb_off_t)0) {
12613 if (src_offset < (rb_off_t)0) {
12614 rb_off_t current_offset;
12615 errno = 0;
12616 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12617 if (current_offset < (rb_off_t)0 && errno) {
12618 stp->syserr = "lseek";
12619 stp->error_no = errno;
12620 return (int)current_offset;
12621 }
12622 copy_length = src_size - current_offset;
12623 }
12624 else {
12625 copy_length = src_size - src_offset;
12626 }
12627 }
12628
12629 retry_copy_file_range:
12630# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12631 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12632 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12633# else
12634 ss = (ssize_t)copy_length;
12635# endif
12636 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12637 if (0 < ss) {
12638 stp->total += ss;
12639 copy_length -= ss;
12640 if (0 < copy_length) {
12641 goto retry_copy_file_range;
12642 }
12643 }
12644 if (ss < 0) {
12645 if (maygvl_copy_stream_continue_p(0, stp)) {
12646 goto retry_copy_file_range;
12647 }
12648 switch (errno) {
12649 case EINVAL:
12650 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12651 docker container) */
12652#ifdef ENOSYS
12653 case ENOSYS:
12654#endif
12655#ifdef EXDEV
12656 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12657#endif
12658 return 0;
12659 case EAGAIN:
12660#if EWOULDBLOCK != EAGAIN
12661 case EWOULDBLOCK:
12662#endif
12663 {
12664 int ret = nogvl_copy_stream_wait_write(stp);
12665 if (ret < 0) return ret;
12666 }
12667 goto retry_copy_file_range;
12668 case EBADF:
12669 {
12670 int e = errno;
12671 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12672
12673 if (flags != -1 && flags & O_APPEND) {
12674 return 0;
12675 }
12676 errno = e;
12677 }
12678 }
12679 stp->syserr = "copy_file_range";
12680 stp->error_no = errno;
12681 return (int)ss;
12682 }
12683 return 1;
12684}
12685#endif
12686
12687#ifdef HAVE_FCOPYFILE
12688static int
12689nogvl_fcopyfile(struct copy_stream_struct *stp)
12690{
12691 rb_off_t cur, ss = 0;
12692 const rb_off_t src_offset = stp->src_offset;
12693 int ret;
12694
12695 if (stp->copy_length >= (rb_off_t)0) {
12696 /* copy_length can't be specified in fcopyfile(3) */
12697 return 0;
12698 }
12699
12700 if (!S_ISREG(stp->src_stat.st_mode))
12701 return 0;
12702
12703 if (!S_ISREG(stp->dst_stat.st_mode))
12704 return 0;
12705 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12706 return 0;
12707 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12708 /* fcopyfile(3) appends src IO to dst IO and then truncates
12709 * dst IO to src IO's original size. */
12710 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12711 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12712 if (end > (rb_off_t)0) return 0;
12713 }
12714
12715 if (src_offset > (rb_off_t)0) {
12716 rb_off_t r;
12717
12718 /* get current offset */
12719 errno = 0;
12720 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12721 if (cur < (rb_off_t)0 && errno) {
12722 stp->error_no = errno;
12723 return 1;
12724 }
12725
12726 errno = 0;
12727 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12728 if (r < (rb_off_t)0 && errno) {
12729 stp->error_no = errno;
12730 return 1;
12731 }
12732 }
12733
12734 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12735 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12736 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12737
12738 if (ret == 0) { /* success */
12739 stp->total = ss;
12740 if (src_offset > (rb_off_t)0) {
12741 rb_off_t r;
12742 errno = 0;
12743 /* reset offset */
12744 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12745 if (r < (rb_off_t)0 && errno) {
12746 stp->error_no = errno;
12747 return 1;
12748 }
12749 }
12750 }
12751 else {
12752 switch (errno) {
12753 case ENOTSUP:
12754 case EPERM:
12755 case EINVAL:
12756 return 0;
12757 }
12758 stp->syserr = "fcopyfile";
12759 stp->error_no = errno;
12760 return (int)ret;
12761 }
12762 return 1;
12763}
12764#endif
12765
12766#ifdef HAVE_SENDFILE
12767
12768# ifdef __linux__
12769# define USE_SENDFILE
12770
12771# ifdef HAVE_SYS_SENDFILE_H
12772# include <sys/sendfile.h>
12773# endif
12774
12775static ssize_t
12776simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12777{
12778 return sendfile(out_fd, in_fd, offset, (size_t)count);
12779}
12780
12781# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12782/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12783 * without cpuset -l 0.
12784 */
12785# define USE_SENDFILE
12786
12787static ssize_t
12788simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12789{
12790 int r;
12791 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12792 rb_off_t sbytes;
12793# ifdef __APPLE__
12794 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12795 sbytes = count;
12796# else
12797 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12798# endif
12799 if (r != 0 && sbytes == 0) return r;
12800 if (offset) {
12801 *offset += sbytes;
12802 }
12803 else {
12804 lseek(in_fd, sbytes, SEEK_CUR);
12805 }
12806 return (ssize_t)sbytes;
12807}
12808
12809# endif
12810
12811#endif
12812
12813#ifdef USE_SENDFILE
12814static int
12815nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12816{
12817 ssize_t ss;
12818 rb_off_t src_size;
12819 rb_off_t copy_length;
12820 rb_off_t src_offset;
12821 int use_pread;
12822
12823 if (!S_ISREG(stp->src_stat.st_mode))
12824 return 0;
12825
12826 src_size = stp->src_stat.st_size;
12827#ifndef __linux__
12828 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12829 return 0;
12830#endif
12831
12832 src_offset = stp->src_offset;
12833 use_pread = src_offset >= (rb_off_t)0;
12834
12835 copy_length = stp->copy_length;
12836 if (copy_length < (rb_off_t)0) {
12837 if (use_pread)
12838 copy_length = src_size - src_offset;
12839 else {
12840 rb_off_t cur;
12841 errno = 0;
12842 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12843 if (cur < (rb_off_t)0 && errno) {
12844 stp->syserr = "lseek";
12845 stp->error_no = errno;
12846 return (int)cur;
12847 }
12848 copy_length = src_size - cur;
12849 }
12850 }
12851
12852 retry_sendfile:
12853# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12854 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12855 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12856# else
12857 ss = (ssize_t)copy_length;
12858# endif
12859 if (use_pread) {
12860 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12861 }
12862 else {
12863 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12864 }
12865 if (0 < ss) {
12866 stp->total += ss;
12867 copy_length -= ss;
12868 if (0 < copy_length) {
12869 goto retry_sendfile;
12870 }
12871 }
12872 if (ss < 0) {
12873 if (maygvl_copy_stream_continue_p(0, stp))
12874 goto retry_sendfile;
12875 switch (errno) {
12876 case EINVAL:
12877#ifdef ENOSYS
12878 case ENOSYS:
12879#endif
12880#ifdef EOPNOTSUP
12881 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12882 see also: [Feature #16965] */
12883 case EOPNOTSUP:
12884#endif
12885 return 0;
12886 case EAGAIN:
12887#if EWOULDBLOCK != EAGAIN
12888 case EWOULDBLOCK:
12889#endif
12890 {
12891 int ret;
12892#ifndef __linux__
12893 /*
12894 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12895 * select() reports regular files to always be "ready", so
12896 * there is no need to select() on it.
12897 * Other OSes may have the same limitation for sendfile() which
12898 * allow us to bypass maygvl_copy_stream_wait_read()...
12899 */
12900 ret = maygvl_copy_stream_wait_read(0, stp);
12901 if (ret < 0) return ret;
12902#endif
12903 ret = nogvl_copy_stream_wait_write(stp);
12904 if (ret < 0) return ret;
12905 }
12906 goto retry_sendfile;
12907 }
12908 stp->syserr = "sendfile";
12909 stp->error_no = errno;
12910 return (int)ss;
12911 }
12912 return 1;
12913}
12914#endif
12915
12916static ssize_t
12917maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12918{
12919 if (has_gvl)
12920 return rb_io_read_memory(fptr, buf, count);
12921 else
12922 return read(fptr->fd, buf, count);
12923}
12924
12925static ssize_t
12926maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12927{
12928 ssize_t ss;
12929 retry_read:
12930 if (offset < (rb_off_t)0) {
12931 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12932 }
12933 else {
12934 ss = pread(stp->src_fptr->fd, buf, len, offset);
12935 }
12936 if (ss == 0) {
12937 return 0;
12938 }
12939 if (ss < 0) {
12940 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12941 goto retry_read;
12942 switch (errno) {
12943 case EAGAIN:
12944#if EWOULDBLOCK != EAGAIN
12945 case EWOULDBLOCK:
12946#endif
12947 {
12948 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12949 if (ret < 0) return ret;
12950 }
12951 goto retry_read;
12952#ifdef ENOSYS
12953 case ENOSYS:
12954 stp->notimp = "pread";
12955 return ss;
12956#endif
12957 }
12958 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
12959 stp->error_no = errno;
12960 }
12961 return ss;
12962}
12963
12964static int
12965nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
12966{
12967 ssize_t ss;
12968 int off = 0;
12969 while (len) {
12970 ss = write(stp->dst_fptr->fd, buf+off, len);
12971 if (ss < 0) {
12972 if (maygvl_copy_stream_continue_p(0, stp))
12973 continue;
12974 if (io_again_p(errno)) {
12975 int ret = nogvl_copy_stream_wait_write(stp);
12976 if (ret < 0) return ret;
12977 continue;
12978 }
12979 stp->syserr = "write";
12980 stp->error_no = errno;
12981 return (int)ss;
12982 }
12983 off += (int)ss;
12984 len -= (int)ss;
12985 stp->total += ss;
12986 }
12987 return 0;
12988}
12989
12990static void
12991nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
12992{
12993 char buf[1024*16];
12994 size_t len;
12995 ssize_t ss;
12996 int ret;
12997 rb_off_t copy_length;
12998 rb_off_t src_offset;
12999 int use_eof;
13000 int use_pread;
13001
13002 copy_length = stp->copy_length;
13003 use_eof = copy_length < (rb_off_t)0;
13004 src_offset = stp->src_offset;
13005 use_pread = src_offset >= (rb_off_t)0;
13006
13007 if (use_pread && stp->close_src) {
13008 rb_off_t r;
13009 errno = 0;
13010 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13011 if (r < (rb_off_t)0 && errno) {
13012 stp->syserr = "lseek";
13013 stp->error_no = errno;
13014 return;
13015 }
13016 src_offset = (rb_off_t)-1;
13017 use_pread = 0;
13018 }
13019
13020 while (use_eof || 0 < copy_length) {
13021 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13022 len = (size_t)copy_length;
13023 }
13024 else {
13025 len = sizeof(buf);
13026 }
13027 if (use_pread) {
13028 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13029 if (0 < ss)
13030 src_offset += ss;
13031 }
13032 else {
13033 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13034 }
13035 if (ss <= 0) /* EOF or error */
13036 return;
13037
13038 ret = nogvl_copy_stream_write(stp, buf, ss);
13039 if (ret < 0)
13040 return;
13041
13042 if (!use_eof)
13043 copy_length -= ss;
13044 }
13045}
13046
13047static void *
13048nogvl_copy_stream_func(void *arg)
13049{
13050 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13051#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13052 int ret;
13053#endif
13054
13055#ifdef USE_COPY_FILE_RANGE
13056 ret = nogvl_copy_file_range(stp);
13057 if (ret != 0)
13058 goto finish; /* error or success */
13059#endif
13060
13061#ifdef HAVE_FCOPYFILE
13062 ret = nogvl_fcopyfile(stp);
13063 if (ret != 0)
13064 goto finish; /* error or success */
13065#endif
13066
13067#ifdef USE_SENDFILE
13068 ret = nogvl_copy_stream_sendfile(stp);
13069 if (ret != 0)
13070 goto finish; /* error or success */
13071#endif
13072
13073 nogvl_copy_stream_read_write(stp);
13074
13075#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13076 finish:
13077#endif
13078 return 0;
13079}
13080
13081static VALUE
13082copy_stream_fallback_body(VALUE arg)
13083{
13084 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13085 const int buflen = 16*1024;
13086 VALUE n;
13087 VALUE buf = rb_str_buf_new(buflen);
13088 rb_off_t rest = stp->copy_length;
13089 rb_off_t off = stp->src_offset;
13090 ID read_method = id_readpartial;
13091
13092 if (!stp->src_fptr) {
13093 if (!rb_respond_to(stp->src, read_method)) {
13094 read_method = id_read;
13095 }
13096 }
13097
13098 while (1) {
13099 long numwrote;
13100 long l;
13101 if (stp->copy_length < (rb_off_t)0) {
13102 l = buflen;
13103 }
13104 else {
13105 if (rest == 0) {
13106 rb_str_resize(buf, 0);
13107 break;
13108 }
13109 l = buflen < rest ? buflen : (long)rest;
13110 }
13111 if (!stp->src_fptr) {
13112 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13113
13114 if (read_method == id_read && NIL_P(rc))
13115 break;
13116 }
13117 else {
13118 ssize_t ss;
13119 rb_str_resize(buf, buflen);
13120 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13121 rb_str_resize(buf, ss > 0 ? ss : 0);
13122 if (ss < 0)
13123 return Qnil;
13124 if (ss == 0)
13125 rb_eof_error();
13126 if (off >= (rb_off_t)0)
13127 off += ss;
13128 }
13129 n = rb_io_write(stp->dst, buf);
13130 numwrote = NUM2LONG(n);
13131 stp->total += numwrote;
13132 rest -= numwrote;
13133 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13134 break;
13135 }
13136 }
13137
13138 return Qnil;
13139}
13140
13141static VALUE
13142copy_stream_fallback(struct copy_stream_struct *stp)
13143{
13144 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13145 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13146 }
13147 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13148 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13149 rb_eEOFError, (VALUE)0);
13150 return Qnil;
13151}
13152
13153static VALUE
13154copy_stream_body(VALUE arg)
13155{
13156 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13157 VALUE src_io = stp->src, dst_io = stp->dst;
13158 const int common_oflags = 0
13159#ifdef O_NOCTTY
13160 | O_NOCTTY
13161#endif
13162 ;
13163
13164 stp->th = rb_thread_current();
13165
13166 stp->total = 0;
13167
13168 if (src_io == argf ||
13169 !(RB_TYPE_P(src_io, T_FILE) ||
13170 RB_TYPE_P(src_io, T_STRING) ||
13171 rb_respond_to(src_io, rb_intern("to_path")))) {
13172 stp->src_fptr = NULL;
13173 }
13174 else {
13175 int stat_ret;
13176 VALUE tmp_io = rb_io_check_io(src_io);
13177 if (!NIL_P(tmp_io)) {
13178 src_io = tmp_io;
13179 }
13180 else if (!RB_TYPE_P(src_io, T_FILE)) {
13181 VALUE args[2];
13182 FilePathValue(src_io);
13183 args[0] = src_io;
13184 args[1] = INT2NUM(O_RDONLY|common_oflags);
13185 src_io = rb_class_new_instance(2, args, rb_cFile);
13186 stp->src = src_io;
13187 stp->close_src = 1;
13188 }
13189 RB_IO_POINTER(src_io, stp->src_fptr);
13190 rb_io_check_byte_readable(stp->src_fptr);
13191
13192 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13193 if (stat_ret < 0) {
13194 stp->syserr = "fstat";
13195 stp->error_no = errno;
13196 return Qnil;
13197 }
13198 }
13199
13200 if (dst_io == argf ||
13201 !(RB_TYPE_P(dst_io, T_FILE) ||
13202 RB_TYPE_P(dst_io, T_STRING) ||
13203 rb_respond_to(dst_io, rb_intern("to_path")))) {
13204 stp->dst_fptr = NULL;
13205 }
13206 else {
13207 int stat_ret;
13208 VALUE tmp_io = rb_io_check_io(dst_io);
13209 if (!NIL_P(tmp_io)) {
13210 dst_io = GetWriteIO(tmp_io);
13211 }
13212 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13213 VALUE args[3];
13214 FilePathValue(dst_io);
13215 args[0] = dst_io;
13216 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13217 args[2] = INT2FIX(0666);
13218 dst_io = rb_class_new_instance(3, args, rb_cFile);
13219 stp->dst = dst_io;
13220 stp->close_dst = 1;
13221 }
13222 else {
13223 dst_io = GetWriteIO(dst_io);
13224 stp->dst = dst_io;
13225 }
13226 RB_IO_POINTER(dst_io, stp->dst_fptr);
13227 rb_io_check_writable(stp->dst_fptr);
13228
13229 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13230 if (stat_ret < 0) {
13231 stp->syserr = "fstat";
13232 stp->error_no = errno;
13233 return Qnil;
13234 }
13235 }
13236
13237#ifdef O_BINARY
13238 if (stp->src_fptr)
13239 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13240#endif
13241 if (stp->dst_fptr)
13242 io_ascii8bit_binmode(stp->dst_fptr);
13243
13244 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13245 size_t len = stp->src_fptr->rbuf.len;
13246 VALUE str;
13247 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13248 len = (size_t)stp->copy_length;
13249 }
13250 str = rb_str_buf_new(len);
13251 rb_str_resize(str,len);
13252 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13253 if (stp->dst_fptr) { /* IO or filename */
13254 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13255 rb_sys_fail_on_write(stp->dst_fptr);
13256 }
13257 else /* others such as StringIO */
13258 rb_io_write(dst_io, str);
13259 rb_str_resize(str, 0);
13260 stp->total += len;
13261 if (stp->copy_length >= (rb_off_t)0)
13262 stp->copy_length -= len;
13263 }
13264
13265 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13266 rb_raise(rb_eIOError, "flush failed");
13267 }
13268
13269 if (stp->copy_length == 0)
13270 return Qnil;
13271
13272 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13273 return copy_stream_fallback(stp);
13274 }
13275
13276 rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
13277 return Qnil;
13278}
13279
13280static VALUE
13281copy_stream_finalize(VALUE arg)
13282{
13283 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13284
13285#ifdef HAVE_FCOPYFILE
13286 if (stp->copyfile_state) {
13287 copyfile_state_free(stp->copyfile_state);
13288 }
13289#endif
13290
13291 if (stp->close_src) {
13292 rb_io_close_m(stp->src);
13293 }
13294 if (stp->close_dst) {
13295 rb_io_close_m(stp->dst);
13296 }
13297 if (stp->syserr) {
13298 rb_syserr_fail(stp->error_no, stp->syserr);
13299 }
13300 if (stp->notimp) {
13301 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13302 }
13303 return Qnil;
13304}
13305
13306/*
13307 * call-seq:
13308 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13309 *
13310 * Copies from the given +src+ to the given +dst+,
13311 * returning the number of bytes copied.
13312 *
13313 * - The given +src+ must be one of the following:
13314 *
13315 * - The path to a readable file, from which source data is to be read.
13316 * - An \IO-like object, opened for reading and capable of responding
13317 * to method +:readpartial+ or method +:read+.
13318 *
13319 * - The given +dst+ must be one of the following:
13320 *
13321 * - The path to a writable file, to which data is to be written.
13322 * - An \IO-like object, opened for writing and capable of responding
13323 * to method +:write+.
13324 *
13325 * The examples here use file <tt>t.txt</tt> as source:
13326 *
13327 * File.read('t.txt')
13328 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13329 * File.read('t.txt').size # => 47
13330 *
13331 * If only arguments +src+ and +dst+ are given,
13332 * the entire source stream is copied:
13333 *
13334 * # Paths.
13335 * IO.copy_stream('t.txt', 't.tmp') # => 47
13336 *
13337 * # IOs (recall that a File is also an IO).
13338 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13339 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13340 * IO.copy_stream(src_io, dst_io) # => 47
13341 * src_io.close
13342 * dst_io.close
13343 *
13344 * With argument +src_length+ a non-negative integer,
13345 * no more than that many bytes are copied:
13346 *
13347 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13348 * File.read('t.tmp') # => "First line"
13349 *
13350 * With argument +src_offset+ also given,
13351 * the source stream is read beginning at that offset:
13352 *
13353 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13354 * IO.read('t.tmp') # => "Second line"
13355 *
13356 */
13357static VALUE
13358rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13359{
13360 VALUE src, dst, length, src_offset;
13361 struct copy_stream_struct st;
13362
13363 MEMZERO(&st, struct copy_stream_struct, 1);
13364
13365 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13366
13367 st.src = src;
13368 st.dst = dst;
13369
13370 st.src_fptr = NULL;
13371 st.dst_fptr = NULL;
13372
13373 if (NIL_P(length))
13374 st.copy_length = (rb_off_t)-1;
13375 else
13376 st.copy_length = NUM2OFFT(length);
13377
13378 if (NIL_P(src_offset))
13379 st.src_offset = (rb_off_t)-1;
13380 else
13381 st.src_offset = NUM2OFFT(src_offset);
13382
13383 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13384
13385 return OFFT2NUM(st.total);
13386}
13387
13388/*
13389 * call-seq:
13390 * external_encoding -> encoding or nil
13391 *
13392 * Returns the Encoding object that represents the encoding of the stream,
13393 * or +nil+ if the stream is in write mode and no encoding is specified.
13394 *
13395 * See {Encodings}[rdoc-ref:File@Encodings].
13396 *
13397 */
13398
13399static VALUE
13400rb_io_external_encoding(VALUE io)
13401{
13402 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13403
13404 if (fptr->encs.enc2) {
13405 return rb_enc_from_encoding(fptr->encs.enc2);
13406 }
13407 if (fptr->mode & FMODE_WRITABLE) {
13408 if (fptr->encs.enc)
13409 return rb_enc_from_encoding(fptr->encs.enc);
13410 return Qnil;
13411 }
13412 return rb_enc_from_encoding(io_read_encoding(fptr));
13413}
13414
13415/*
13416 * call-seq:
13417 * internal_encoding -> encoding or nil
13418 *
13419 * Returns the Encoding object that represents the encoding of the internal string,
13420 * if conversion is specified,
13421 * or +nil+ otherwise.
13422 *
13423 * See {Encodings}[rdoc-ref:File@Encodings].
13424 *
13425 */
13426
13427static VALUE
13428rb_io_internal_encoding(VALUE io)
13429{
13430 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13431
13432 if (!fptr->encs.enc2) return Qnil;
13433 return rb_enc_from_encoding(io_read_encoding(fptr));
13434}
13435
13436/*
13437 * call-seq:
13438 * set_encoding(ext_enc) -> self
13439 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13440 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13441 *
13442 * See {Encodings}[rdoc-ref:File@Encodings].
13443 *
13444 * Argument +ext_enc+, if given, must be an Encoding object
13445 * or a String with the encoding name;
13446 * it is assigned as the encoding for the stream.
13447 *
13448 * Argument +int_enc+, if given, must be an Encoding object
13449 * or a String with the encoding name;
13450 * it is assigned as the encoding for the internal string.
13451 *
13452 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13453 * containing two colon-separated encoding names;
13454 * corresponding Encoding objects are assigned as the external
13455 * and internal encodings for the stream.
13456 *
13457 * If the external encoding of a string is binary/ASCII-8BIT,
13458 * the internal encoding of the string is set to nil, since no
13459 * transcoding is needed.
13460 *
13461 * Optional keyword arguments +enc_opts+ specify
13462 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13463 *
13464 */
13465
13466static VALUE
13467rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13468{
13469 rb_io_t *fptr;
13470 VALUE v1, v2, opt;
13471
13472 if (!RB_TYPE_P(io, T_FILE)) {
13473 return forward(io, id_set_encoding, argc, argv);
13474 }
13475
13476 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13477 GetOpenFile(io, fptr);
13478 io_encoding_set(fptr, v1, v2, opt);
13479 return io;
13480}
13481
13482void
13483rb_stdio_set_default_encoding(void)
13484{
13485 VALUE val = Qnil;
13486
13487#ifdef _WIN32
13488 if (isatty(fileno(stdin))) {
13489 rb_encoding *external = rb_locale_encoding();
13490 rb_encoding *internal = rb_default_internal_encoding();
13491 if (!internal) internal = rb_default_external_encoding();
13492 io_encoding_set(RFILE(rb_stdin)->fptr,
13493 rb_enc_from_encoding(external),
13494 rb_enc_from_encoding(internal),
13495 Qnil);
13496 }
13497 else
13498#endif
13499 rb_io_set_encoding(1, &val, rb_stdin);
13500 rb_io_set_encoding(1, &val, rb_stdout);
13501 rb_io_set_encoding(1, &val, rb_stderr);
13502}
13503
13504static inline int
13505global_argf_p(VALUE arg)
13506{
13507 return arg == argf;
13508}
13509
13510typedef VALUE (*argf_encoding_func)(VALUE io);
13511
13512static VALUE
13513argf_encoding(VALUE argf, argf_encoding_func func)
13514{
13515 if (!RTEST(ARGF.current_file)) {
13516 return rb_enc_default_external();
13517 }
13518 return func(rb_io_check_io(ARGF.current_file));
13519}
13520
13521/*
13522 * call-seq:
13523 * ARGF.external_encoding -> encoding
13524 *
13525 * Returns the external encoding for files read from ARGF as an Encoding
13526 * object. The external encoding is the encoding of the text as stored in a
13527 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13528 * represent this text within Ruby.
13529 *
13530 * To set the external encoding use ARGF.set_encoding.
13531 *
13532 * For example:
13533 *
13534 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13535 *
13536 */
13537static VALUE
13538argf_external_encoding(VALUE argf)
13539{
13540 return argf_encoding(argf, rb_io_external_encoding);
13541}
13542
13543/*
13544 * call-seq:
13545 * ARGF.internal_encoding -> encoding
13546 *
13547 * Returns the internal encoding for strings read from ARGF as an
13548 * Encoding object.
13549 *
13550 * If ARGF.set_encoding has been called with two encoding names, the second
13551 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13552 * value is returned. Failing that, if a default external encoding was
13553 * specified on the command-line, that value is used. If the encoding is
13554 * unknown, +nil+ is returned.
13555 */
13556static VALUE
13557argf_internal_encoding(VALUE argf)
13558{
13559 return argf_encoding(argf, rb_io_internal_encoding);
13560}
13561
13562/*
13563 * call-seq:
13564 * ARGF.set_encoding(ext_enc) -> ARGF
13565 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13566 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13567 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13568 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13569 *
13570 * If single argument is specified, strings read from ARGF are tagged with
13571 * the encoding specified.
13572 *
13573 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13574 * the read string is converted from the first encoding (external encoding)
13575 * to the second encoding (internal encoding), then tagged with the second
13576 * encoding.
13577 *
13578 * If two arguments are specified, they must be encoding objects or encoding
13579 * names. Again, the first specifies the external encoding; the second
13580 * specifies the internal encoding.
13581 *
13582 * If the external encoding and the internal encoding are specified, the
13583 * optional Hash argument can be used to adjust the conversion process. The
13584 * structure of this hash is explained in the String#encode documentation.
13585 *
13586 * For example:
13587 *
13588 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13589 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13590 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13591 * # to UTF-8.
13592 */
13593static VALUE
13594argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13595{
13596 rb_io_t *fptr;
13597
13598 if (!next_argv()) {
13599 rb_raise(rb_eArgError, "no stream to set encoding");
13600 }
13601 rb_io_set_encoding(argc, argv, ARGF.current_file);
13602 GetOpenFile(ARGF.current_file, fptr);
13603 ARGF.encs = fptr->encs;
13604 return argf;
13605}
13606
13607/*
13608 * call-seq:
13609 * ARGF.tell -> Integer
13610 * ARGF.pos -> Integer
13611 *
13612 * Returns the current offset (in bytes) of the current file in ARGF.
13613 *
13614 * ARGF.pos #=> 0
13615 * ARGF.gets #=> "This is line one\n"
13616 * ARGF.pos #=> 17
13617 *
13618 */
13619static VALUE
13620argf_tell(VALUE argf)
13621{
13622 if (!next_argv()) {
13623 rb_raise(rb_eArgError, "no stream to tell");
13624 }
13625 ARGF_FORWARD(0, 0);
13626 return rb_io_tell(ARGF.current_file);
13627}
13628
13629/*
13630 * call-seq:
13631 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13632 *
13633 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13634 * the value of _whence_. See IO#seek for further details.
13635 */
13636static VALUE
13637argf_seek_m(int argc, VALUE *argv, VALUE argf)
13638{
13639 if (!next_argv()) {
13640 rb_raise(rb_eArgError, "no stream to seek");
13641 }
13642 ARGF_FORWARD(argc, argv);
13643 return rb_io_seek_m(argc, argv, ARGF.current_file);
13644}
13645
13646/*
13647 * call-seq:
13648 * ARGF.pos = position -> Integer
13649 *
13650 * Seeks to the position given by _position_ (in bytes) in ARGF.
13651 *
13652 * For example:
13653 *
13654 * ARGF.pos = 17
13655 * ARGF.gets #=> "This is line two\n"
13656 */
13657static VALUE
13658argf_set_pos(VALUE argf, VALUE offset)
13659{
13660 if (!next_argv()) {
13661 rb_raise(rb_eArgError, "no stream to set position");
13662 }
13663 ARGF_FORWARD(1, &offset);
13664 return rb_io_set_pos(ARGF.current_file, offset);
13665}
13666
13667/*
13668 * call-seq:
13669 * ARGF.rewind -> 0
13670 *
13671 * Positions the current file to the beginning of input, resetting
13672 * ARGF.lineno to zero.
13673 *
13674 * ARGF.readline #=> "This is line one\n"
13675 * ARGF.rewind #=> 0
13676 * ARGF.lineno #=> 0
13677 * ARGF.readline #=> "This is line one\n"
13678 */
13679static VALUE
13680argf_rewind(VALUE argf)
13681{
13682 VALUE ret;
13683 int old_lineno;
13684
13685 if (!next_argv()) {
13686 rb_raise(rb_eArgError, "no stream to rewind");
13687 }
13688 ARGF_FORWARD(0, 0);
13689 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13690 ret = rb_io_rewind(ARGF.current_file);
13691 if (!global_argf_p(argf)) {
13692 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13693 }
13694 return ret;
13695}
13696
13697/*
13698 * call-seq:
13699 * ARGF.fileno -> integer
13700 * ARGF.to_i -> integer
13701 *
13702 * Returns an integer representing the numeric file descriptor for
13703 * the current file. Raises an ArgumentError if there isn't a current file.
13704 *
13705 * ARGF.fileno #=> 3
13706 */
13707static VALUE
13708argf_fileno(VALUE argf)
13709{
13710 if (!next_argv()) {
13711 rb_raise(rb_eArgError, "no stream");
13712 }
13713 ARGF_FORWARD(0, 0);
13714 return rb_io_fileno(ARGF.current_file);
13715}
13716
13717/*
13718 * call-seq:
13719 * ARGF.to_io -> IO
13720 *
13721 * Returns an IO object representing the current file. This will be a
13722 * File object unless the current file is a stream such as STDIN.
13723 *
13724 * For example:
13725 *
13726 * ARGF.to_io #=> #<File:glark.txt>
13727 * ARGF.to_io #=> #<IO:<STDIN>>
13728 */
13729static VALUE
13730argf_to_io(VALUE argf)
13731{
13732 next_argv();
13733 ARGF_FORWARD(0, 0);
13734 return ARGF.current_file;
13735}
13736
13737/*
13738 * call-seq:
13739 * ARGF.eof? -> true or false
13740 * ARGF.eof -> true or false
13741 *
13742 * Returns true if the current file in ARGF is at end of file, i.e. it has
13743 * no data to read. The stream must be opened for reading or an IOError
13744 * will be raised.
13745 *
13746 * $ echo "eof" | ruby argf.rb
13747 *
13748 * ARGF.eof? #=> false
13749 * 3.times { ARGF.readchar }
13750 * ARGF.eof? #=> false
13751 * ARGF.readchar #=> "\n"
13752 * ARGF.eof? #=> true
13753 */
13754
13755static VALUE
13756argf_eof(VALUE argf)
13757{
13758 next_argv();
13759 if (RTEST(ARGF.current_file)) {
13760 if (ARGF.init_p == 0) return Qtrue;
13761 next_argv();
13762 ARGF_FORWARD(0, 0);
13763 if (rb_io_eof(ARGF.current_file)) {
13764 return Qtrue;
13765 }
13766 }
13767 return Qfalse;
13768}
13769
13770/*
13771 * call-seq:
13772 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13773 *
13774 * Reads _length_ bytes from ARGF. The files named on the command line
13775 * are concatenated and treated as a single file by this method, so when
13776 * called without arguments the contents of this pseudo file are returned in
13777 * their entirety.
13778 *
13779 * _length_ must be a non-negative integer or +nil+.
13780 *
13781 * If _length_ is a positive integer, +read+ tries to read
13782 * _length_ bytes without any conversion (binary mode).
13783 * It returns +nil+ if an EOF is encountered before anything can be read.
13784 * Fewer than _length_ bytes are returned if an EOF is encountered during
13785 * the read.
13786 * In the case of an integer _length_, the resulting string is always
13787 * in ASCII-8BIT encoding.
13788 *
13789 * If _length_ is omitted or is +nil+, it reads until EOF
13790 * and the encoding conversion is applied, if applicable.
13791 * A string is returned even if EOF is encountered before any data is read.
13792 *
13793 * If _length_ is zero, it returns an empty string (<code>""</code>).
13794 *
13795 * If the optional _outbuf_ argument is present,
13796 * it must reference a String, which will receive the data.
13797 * The _outbuf_ will contain only the received data after the method call
13798 * even if it is not empty at the beginning.
13799 *
13800 * For example:
13801 *
13802 * $ echo "small" > small.txt
13803 * $ echo "large" > large.txt
13804 * $ ./glark.rb small.txt large.txt
13805 *
13806 * ARGF.read #=> "small\nlarge"
13807 * ARGF.read(200) #=> "small\nlarge"
13808 * ARGF.read(2) #=> "sm"
13809 * ARGF.read(0) #=> ""
13810 *
13811 * Note that this method behaves like the fread() function in C.
13812 * This means it retries to invoke read(2) system calls to read data
13813 * with the specified length.
13814 * If you need the behavior like a single read(2) system call,
13815 * consider ARGF#readpartial or ARGF#read_nonblock.
13816 */
13817
13818static VALUE
13819argf_read(int argc, VALUE *argv, VALUE argf)
13820{
13821 VALUE tmp, str, length;
13822 long len = 0;
13823
13824 rb_scan_args(argc, argv, "02", &length, &str);
13825 if (!NIL_P(length)) {
13826 len = NUM2LONG(argv[0]);
13827 }
13828 if (!NIL_P(str)) {
13829 StringValue(str);
13830 rb_str_resize(str,0);
13831 argv[1] = Qnil;
13832 }
13833
13834 retry:
13835 if (!next_argv()) {
13836 return str;
13837 }
13838 if (ARGF_GENERIC_INPUT_P()) {
13839 tmp = argf_forward(argc, argv, argf);
13840 }
13841 else {
13842 tmp = io_read(argc, argv, ARGF.current_file);
13843 }
13844 if (NIL_P(str)) str = tmp;
13845 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13846 if (NIL_P(tmp) || NIL_P(length)) {
13847 if (ARGF.next_p != -1) {
13848 argf_close(argf);
13849 ARGF.next_p = 1;
13850 goto retry;
13851 }
13852 }
13853 else if (argc >= 1) {
13854 long slen = RSTRING_LEN(str);
13855 if (slen < len) {
13856 argv[0] = LONG2NUM(len - slen);
13857 goto retry;
13858 }
13859 }
13860 return str;
13861}
13862
13863 struct argf_call_arg {
13864 int argc;
13865 VALUE *argv;
13866 VALUE argf;
13867};
13868
13869static VALUE
13870argf_forward_call(VALUE arg)
13871{
13872 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13873 argf_forward(p->argc, p->argv, p->argf);
13874 return Qnil;
13875}
13876
13877static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13878 int nonblock);
13879
13880/*
13881 * call-seq:
13882 * ARGF.readpartial(maxlen) -> string
13883 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13884 *
13885 * Reads at most _maxlen_ bytes from the ARGF stream.
13886 *
13887 * If the optional _outbuf_ argument is present,
13888 * it must reference a String, which will receive the data.
13889 * The _outbuf_ will contain only the received data after the method call
13890 * even if it is not empty at the beginning.
13891 *
13892 * It raises EOFError on end of ARGF stream.
13893 * Since ARGF stream is a concatenation of multiple files,
13894 * internally EOF is occur for each file.
13895 * ARGF.readpartial returns empty strings for EOFs except the last one and
13896 * raises EOFError for the last one.
13897 *
13898 */
13899
13900static VALUE
13901argf_readpartial(int argc, VALUE *argv, VALUE argf)
13902{
13903 return argf_getpartial(argc, argv, argf, Qnil, 0);
13904}
13905
13906/*
13907 * call-seq:
13908 * ARGF.read_nonblock(maxlen[, options]) -> string
13909 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13910 *
13911 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13912 */
13913
13914static VALUE
13915argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13916{
13917 VALUE opts;
13918
13919 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13920
13921 if (!NIL_P(opts))
13922 argc--;
13923
13924 return argf_getpartial(argc, argv, argf, opts, 1);
13925}
13926
13927static VALUE
13928argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13929{
13930 VALUE tmp, str, length;
13931 int no_exception;
13932
13933 rb_scan_args(argc, argv, "11", &length, &str);
13934 if (!NIL_P(str)) {
13935 StringValue(str);
13936 argv[1] = str;
13937 }
13938 no_exception = no_exception_p(opts);
13939
13940 if (!next_argv()) {
13941 if (!NIL_P(str)) {
13942 rb_str_resize(str, 0);
13943 }
13944 rb_eof_error();
13945 }
13946 if (ARGF_GENERIC_INPUT_P()) {
13947 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13948 struct argf_call_arg arg;
13949 arg.argc = argc;
13950 arg.argv = argv;
13951 arg.argf = argf;
13952 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
13953 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
13954 }
13955 else {
13956 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13957 }
13958 if (NIL_P(tmp)) {
13959 if (ARGF.next_p == -1) {
13960 return io_nonblock_eof(no_exception);
13961 }
13962 argf_close(argf);
13963 ARGF.next_p = 1;
13964 if (RARRAY_LEN(ARGF.argv) == 0) {
13965 return io_nonblock_eof(no_exception);
13966 }
13967 if (NIL_P(str))
13968 str = rb_str_new(NULL, 0);
13969 return str;
13970 }
13971 return tmp;
13972}
13973
13974/*
13975 * call-seq:
13976 * ARGF.getc -> String or nil
13977 *
13978 * Reads the next character from ARGF and returns it as a String. Returns
13979 * +nil+ at the end of the stream.
13980 *
13981 * ARGF treats the files named on the command line as a single file created
13982 * by concatenating their contents. After returning the last character of the
13983 * first file, it returns the first character of the second file, and so on.
13984 *
13985 * For example:
13986 *
13987 * $ echo "foo" > file
13988 * $ ruby argf.rb file
13989 *
13990 * ARGF.getc #=> "f"
13991 * ARGF.getc #=> "o"
13992 * ARGF.getc #=> "o"
13993 * ARGF.getc #=> "\n"
13994 * ARGF.getc #=> nil
13995 * ARGF.getc #=> nil
13996 */
13997static VALUE
13998argf_getc(VALUE argf)
13999{
14000 VALUE ch;
14001
14002 retry:
14003 if (!next_argv()) return Qnil;
14004 if (ARGF_GENERIC_INPUT_P()) {
14005 ch = forward_current(rb_intern("getc"), 0, 0);
14006 }
14007 else {
14008 ch = rb_io_getc(ARGF.current_file);
14009 }
14010 if (NIL_P(ch) && ARGF.next_p != -1) {
14011 argf_close(argf);
14012 ARGF.next_p = 1;
14013 goto retry;
14014 }
14015
14016 return ch;
14017}
14018
14019/*
14020 * call-seq:
14021 * ARGF.getbyte -> Integer or nil
14022 *
14023 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14024 * the end of the stream.
14025 *
14026 * For example:
14027 *
14028 * $ echo "foo" > file
14029 * $ ruby argf.rb file
14030 *
14031 * ARGF.getbyte #=> 102
14032 * ARGF.getbyte #=> 111
14033 * ARGF.getbyte #=> 111
14034 * ARGF.getbyte #=> 10
14035 * ARGF.getbyte #=> nil
14036 */
14037static VALUE
14038argf_getbyte(VALUE argf)
14039{
14040 VALUE ch;
14041
14042 retry:
14043 if (!next_argv()) return Qnil;
14044 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14045 ch = forward_current(rb_intern("getbyte"), 0, 0);
14046 }
14047 else {
14048 ch = rb_io_getbyte(ARGF.current_file);
14049 }
14050 if (NIL_P(ch) && ARGF.next_p != -1) {
14051 argf_close(argf);
14052 ARGF.next_p = 1;
14053 goto retry;
14054 }
14055
14056 return ch;
14057}
14058
14059/*
14060 * call-seq:
14061 * ARGF.readchar -> String or nil
14062 *
14063 * Reads the next character from ARGF and returns it as a String. Raises
14064 * an EOFError after the last character of the last file has been read.
14065 *
14066 * For example:
14067 *
14068 * $ echo "foo" > file
14069 * $ ruby argf.rb file
14070 *
14071 * ARGF.readchar #=> "f"
14072 * ARGF.readchar #=> "o"
14073 * ARGF.readchar #=> "o"
14074 * ARGF.readchar #=> "\n"
14075 * ARGF.readchar #=> end of file reached (EOFError)
14076 */
14077static VALUE
14078argf_readchar(VALUE argf)
14079{
14080 VALUE ch;
14081
14082 retry:
14083 if (!next_argv()) rb_eof_error();
14084 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14085 ch = forward_current(rb_intern("getc"), 0, 0);
14086 }
14087 else {
14088 ch = rb_io_getc(ARGF.current_file);
14089 }
14090 if (NIL_P(ch) && ARGF.next_p != -1) {
14091 argf_close(argf);
14092 ARGF.next_p = 1;
14093 goto retry;
14094 }
14095
14096 return ch;
14097}
14098
14099/*
14100 * call-seq:
14101 * ARGF.readbyte -> Integer
14102 *
14103 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14104 * an EOFError after the last byte of the last file has been read.
14105 *
14106 * For example:
14107 *
14108 * $ echo "foo" > file
14109 * $ ruby argf.rb file
14110 *
14111 * ARGF.readbyte #=> 102
14112 * ARGF.readbyte #=> 111
14113 * ARGF.readbyte #=> 111
14114 * ARGF.readbyte #=> 10
14115 * ARGF.readbyte #=> end of file reached (EOFError)
14116 */
14117static VALUE
14118argf_readbyte(VALUE argf)
14119{
14120 VALUE c;
14121
14122 NEXT_ARGF_FORWARD(0, 0);
14123 c = argf_getbyte(argf);
14124 if (NIL_P(c)) {
14125 rb_eof_error();
14126 }
14127 return c;
14128}
14129
14130#define FOREACH_ARGF() while (next_argv())
14131
14132static VALUE
14133argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14134{
14135 const VALUE current = ARGF.current_file;
14136 rb_yield_values2(argc, argv);
14137 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14138 rb_iter_break_value(Qundef);
14139 }
14140 return Qnil;
14141}
14142
14143#define ARGF_block_call(mid, argc, argv, func, argf) \
14144 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14145 func, argf, rb_keyword_given_p())
14146
14147static void
14148argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14149{
14150 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14151 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14152}
14153
14154static VALUE
14155argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14156{
14157 if (!global_argf_p(argf)) {
14158 ARGF.last_lineno = ++ARGF.lineno;
14159 }
14160 return argf_block_call_i(i, argf, argc, argv, blockarg);
14161}
14162
14163static void
14164argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14165{
14166 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14167 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14168}
14169
14170/*
14171 * call-seq:
14172 * ARGF.each(sep=$/) {|line| block } -> ARGF
14173 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14174 * ARGF.each(...) -> an_enumerator
14175 *
14176 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14177 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14178 * ARGF.each_line(...) -> an_enumerator
14179 *
14180 * Returns an enumerator which iterates over each line (separated by _sep_,
14181 * which defaults to your platform's newline character) of each file in
14182 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14183 * block, otherwise an enumerator is returned.
14184 * The optional _limit_ argument is an Integer specifying the maximum
14185 * length of each line; longer lines will be split according to this limit.
14186 *
14187 * This method allows you to treat the files supplied on the command line as
14188 * a single file consisting of the concatenation of each named file. After
14189 * the last line of the first file has been returned, the first line of the
14190 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14191 * used to determine the filename of the current line and line number of the
14192 * whole input, respectively.
14193 *
14194 * For example, the following code prints out each line of each named file
14195 * prefixed with its line number, displaying the filename once per file:
14196 *
14197 * ARGF.each_line do |line|
14198 * puts ARGF.filename if ARGF.file.lineno == 1
14199 * puts "#{ARGF.file.lineno}: #{line}"
14200 * end
14201 *
14202 * While the following code prints only the first file's name at first, and
14203 * the contents with line number counted through all named files.
14204 *
14205 * ARGF.each_line do |line|
14206 * puts ARGF.filename if ARGF.lineno == 1
14207 * puts "#{ARGF.lineno}: #{line}"
14208 * end
14209 */
14210static VALUE
14211argf_each_line(int argc, VALUE *argv, VALUE argf)
14212{
14213 RETURN_ENUMERATOR(argf, argc, argv);
14214 FOREACH_ARGF() {
14215 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14216 }
14217 return argf;
14218}
14219
14220/*
14221 * call-seq:
14222 * ARGF.each_byte {|byte| block } -> ARGF
14223 * ARGF.each_byte -> an_enumerator
14224 *
14225 * Iterates over each byte of each file in +ARGV+.
14226 * A byte is returned as an Integer in the range 0..255.
14227 *
14228 * This method allows you to treat the files supplied on the command line as
14229 * a single file consisting of the concatenation of each named file. After
14230 * the last byte of the first file has been returned, the first byte of the
14231 * second file is returned. The ARGF.filename method can be used to
14232 * determine the filename of the current byte.
14233 *
14234 * If no block is given, an enumerator is returned instead.
14235 *
14236 * For example:
14237 *
14238 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14239 *
14240 */
14241static VALUE
14242argf_each_byte(VALUE argf)
14243{
14244 RETURN_ENUMERATOR(argf, 0, 0);
14245 FOREACH_ARGF() {
14246 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14247 }
14248 return argf;
14249}
14250
14251/*
14252 * call-seq:
14253 * ARGF.each_char {|char| block } -> ARGF
14254 * ARGF.each_char -> an_enumerator
14255 *
14256 * Iterates over each character of each file in ARGF.
14257 *
14258 * This method allows you to treat the files supplied on the command line as
14259 * a single file consisting of the concatenation of each named file. After
14260 * the last character of the first file has been returned, the first
14261 * character of the second file is returned. The ARGF.filename method can
14262 * be used to determine the name of the file in which the current character
14263 * appears.
14264 *
14265 * If no block is given, an enumerator is returned instead.
14266 */
14267static VALUE
14268argf_each_char(VALUE argf)
14269{
14270 RETURN_ENUMERATOR(argf, 0, 0);
14271 FOREACH_ARGF() {
14272 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14273 }
14274 return argf;
14275}
14276
14277/*
14278 * call-seq:
14279 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14280 * ARGF.each_codepoint -> an_enumerator
14281 *
14282 * Iterates over each codepoint of each file in ARGF.
14283 *
14284 * This method allows you to treat the files supplied on the command line as
14285 * a single file consisting of the concatenation of each named file. After
14286 * the last codepoint of the first file has been returned, the first
14287 * codepoint of the second file is returned. The ARGF.filename method can
14288 * be used to determine the name of the file in which the current codepoint
14289 * appears.
14290 *
14291 * If no block is given, an enumerator is returned instead.
14292 */
14293static VALUE
14294argf_each_codepoint(VALUE argf)
14295{
14296 RETURN_ENUMERATOR(argf, 0, 0);
14297 FOREACH_ARGF() {
14298 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14299 }
14300 return argf;
14301}
14302
14303/*
14304 * call-seq:
14305 * ARGF.filename -> String
14306 * ARGF.path -> String
14307 *
14308 * Returns the current filename. "-" is returned when the current file is
14309 * STDIN.
14310 *
14311 * For example:
14312 *
14313 * $ echo "foo" > foo
14314 * $ echo "bar" > bar
14315 * $ echo "glark" > glark
14316 *
14317 * $ ruby argf.rb foo bar glark
14318 *
14319 * ARGF.filename #=> "foo"
14320 * ARGF.read(5) #=> "foo\nb"
14321 * ARGF.filename #=> "bar"
14322 * ARGF.skip
14323 * ARGF.filename #=> "glark"
14324 */
14325static VALUE
14326argf_filename(VALUE argf)
14327{
14328 next_argv();
14329 return ARGF.filename;
14330}
14331
14332static VALUE
14333argf_filename_getter(ID id, VALUE *var)
14334{
14335 return argf_filename(*var);
14336}
14337
14338/*
14339 * call-seq:
14340 * ARGF.file -> IO or File object
14341 *
14342 * Returns the current file as an IO or File object.
14343 * <code>$stdin</code> is returned when the current file is STDIN.
14344 *
14345 * For example:
14346 *
14347 * $ echo "foo" > foo
14348 * $ echo "bar" > bar
14349 *
14350 * $ ruby argf.rb foo bar
14351 *
14352 * ARGF.file #=> #<File:foo>
14353 * ARGF.read(5) #=> "foo\nb"
14354 * ARGF.file #=> #<File:bar>
14355 */
14356static VALUE
14357argf_file(VALUE argf)
14358{
14359 next_argv();
14360 return ARGF.current_file;
14361}
14362
14363/*
14364 * call-seq:
14365 * ARGF.binmode -> ARGF
14366 *
14367 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14368 * be reset to non-binary mode. This option has the following effects:
14369 *
14370 * * Newline conversion is disabled.
14371 * * Encoding conversion is disabled.
14372 * * Content is treated as ASCII-8BIT.
14373 */
14374static VALUE
14375argf_binmode_m(VALUE argf)
14376{
14377 ARGF.binmode = 1;
14378 next_argv();
14379 ARGF_FORWARD(0, 0);
14380 rb_io_ascii8bit_binmode(ARGF.current_file);
14381 return argf;
14382}
14383
14384/*
14385 * call-seq:
14386 * ARGF.binmode? -> true or false
14387 *
14388 * Returns true if ARGF is being read in binary mode; false otherwise.
14389 * To enable binary mode use ARGF.binmode.
14390 *
14391 * For example:
14392 *
14393 * ARGF.binmode? #=> false
14394 * ARGF.binmode
14395 * ARGF.binmode? #=> true
14396 */
14397static VALUE
14398argf_binmode_p(VALUE argf)
14399{
14400 return RBOOL(ARGF.binmode);
14401}
14402
14403/*
14404 * call-seq:
14405 * ARGF.skip -> ARGF
14406 *
14407 * Sets the current file to the next file in ARGV. If there aren't any more
14408 * files it has no effect.
14409 *
14410 * For example:
14411 *
14412 * $ ruby argf.rb foo bar
14413 * ARGF.filename #=> "foo"
14414 * ARGF.skip
14415 * ARGF.filename #=> "bar"
14416 */
14417static VALUE
14418argf_skip(VALUE argf)
14419{
14420 if (ARGF.init_p && ARGF.next_p == 0) {
14421 argf_close(argf);
14422 ARGF.next_p = 1;
14423 }
14424 return argf;
14425}
14426
14427/*
14428 * call-seq:
14429 * ARGF.close -> ARGF
14430 *
14431 * Closes the current file and skips to the next file in ARGV. If there are
14432 * no more files to open, just closes the current file. STDIN will not be
14433 * closed.
14434 *
14435 * For example:
14436 *
14437 * $ ruby argf.rb foo bar
14438 *
14439 * ARGF.filename #=> "foo"
14440 * ARGF.close
14441 * ARGF.filename #=> "bar"
14442 * ARGF.close
14443 */
14444static VALUE
14445argf_close_m(VALUE argf)
14446{
14447 next_argv();
14448 argf_close(argf);
14449 if (ARGF.next_p != -1) {
14450 ARGF.next_p = 1;
14451 }
14452 ARGF.lineno = 0;
14453 return argf;
14454}
14455
14456/*
14457 * call-seq:
14458 * ARGF.closed? -> true or false
14459 *
14460 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14461 * ARGF.close to actually close the current file.
14462 */
14463static VALUE
14464argf_closed(VALUE argf)
14465{
14466 next_argv();
14467 ARGF_FORWARD(0, 0);
14468 return rb_io_closed_p(ARGF.current_file);
14469}
14470
14471/*
14472 * call-seq:
14473 * ARGF.to_s -> String
14474 *
14475 * Returns "ARGF".
14476 */
14477static VALUE
14478argf_to_s(VALUE argf)
14479{
14480 return rb_str_new2("ARGF");
14481}
14482
14483/*
14484 * call-seq:
14485 * ARGF.inplace_mode -> String
14486 *
14487 * Returns the file extension appended to the names of backup copies of
14488 * modified files under in-place edit mode. This value can be set using
14489 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14490 */
14491static VALUE
14492argf_inplace_mode_get(VALUE argf)
14493{
14494 if (!ARGF.inplace) return Qnil;
14495 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14496 return rb_str_dup(ARGF.inplace);
14497}
14498
14499static VALUE
14500opt_i_get(ID id, VALUE *var)
14501{
14502 return argf_inplace_mode_get(*var);
14503}
14504
14505/*
14506 * call-seq:
14507 * ARGF.inplace_mode = ext -> ARGF
14508 *
14509 * Sets the filename extension for in-place editing mode to the given String.
14510 * The backup copy of each file being edited has this value appended to its
14511 * filename.
14512 *
14513 * For example:
14514 *
14515 * $ ruby argf.rb file.txt
14516 *
14517 * ARGF.inplace_mode = '.bak'
14518 * ARGF.each_line do |line|
14519 * print line.sub("foo","bar")
14520 * end
14521 *
14522 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14523 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14524 * "bar".
14525 */
14526static VALUE
14527argf_inplace_mode_set(VALUE argf, VALUE val)
14528{
14529 if (!RTEST(val)) {
14530 ARGF.inplace = Qfalse;
14531 }
14532 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14533 ARGF.inplace = Qnil;
14534 }
14535 else {
14536 ARGF.inplace = rb_str_new_frozen(val);
14537 }
14538 return argf;
14539}
14540
14541static void
14542opt_i_set(VALUE val, ID id, VALUE *var)
14543{
14544 argf_inplace_mode_set(*var, val);
14545}
14546
14547void
14548ruby_set_inplace_mode(const char *suffix)
14549{
14550 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14551}
14552
14553/*
14554 * call-seq:
14555 * ARGF.argv -> ARGV
14556 *
14557 * Returns the +ARGV+ array, which contains the arguments passed to your
14558 * script, one per element.
14559 *
14560 * For example:
14561 *
14562 * $ ruby argf.rb -v glark.txt
14563 *
14564 * ARGF.argv #=> ["-v", "glark.txt"]
14565 *
14566 */
14567static VALUE
14568argf_argv(VALUE argf)
14569{
14570 return ARGF.argv;
14571}
14572
14573static VALUE
14574argf_argv_getter(ID id, VALUE *var)
14575{
14576 return argf_argv(*var);
14577}
14578
14579 VALUE
14580rb_get_argv(void)
14581{
14582 return ARGF.argv;
14583}
14584
14585/*
14586 * call-seq:
14587 * ARGF.to_write_io -> io
14588 *
14589 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14590 * enabled.
14591 */
14592static VALUE
14593argf_write_io(VALUE argf)
14594{
14595 if (!RTEST(ARGF.current_file)) {
14596 rb_raise(rb_eIOError, "not opened for writing");
14597 }
14598 return GetWriteIO(ARGF.current_file);
14599}
14600
14601/*
14602 * call-seq:
14603 * ARGF.write(string) -> integer
14604 *
14605 * Writes _string_ if inplace mode.
14606 */
14607static VALUE
14608argf_write(VALUE argf, VALUE str)
14609{
14610 return rb_io_write(argf_write_io(argf), str);
14611}
14612
14613void
14614rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14615{
14616 rb_readwrite_syserr_fail(waiting, errno, mesg);
14617}
14618
14619void
14620rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14621{
14622 VALUE arg, c = Qnil;
14623 arg = mesg ? rb_str_new2(mesg) : Qnil;
14624 switch (waiting) {
14625 case RB_IO_WAIT_WRITABLE:
14626 switch (n) {
14627 case EAGAIN:
14628 c = rb_eEAGAINWaitWritable;
14629 break;
14630#if EAGAIN != EWOULDBLOCK
14631 case EWOULDBLOCK:
14632 c = rb_eEWOULDBLOCKWaitWritable;
14633 break;
14634#endif
14635 case EINPROGRESS:
14636 c = rb_eEINPROGRESSWaitWritable;
14637 break;
14638 default:
14639 rb_mod_syserr_fail_str(rb_mWaitWritable, n, arg);
14640 }
14641 break;
14642 case RB_IO_WAIT_READABLE:
14643 switch (n) {
14644 case EAGAIN:
14645 c = rb_eEAGAINWaitReadable;
14646 break;
14647#if EAGAIN != EWOULDBLOCK
14648 case EWOULDBLOCK:
14649 c = rb_eEWOULDBLOCKWaitReadable;
14650 break;
14651#endif
14652 case EINPROGRESS:
14653 c = rb_eEINPROGRESSWaitReadable;
14654 break;
14655 default:
14656 rb_mod_syserr_fail_str(rb_mWaitReadable, n, arg);
14657 }
14658 break;
14659 default:
14660 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14661 }
14662 rb_exc_raise(rb_class_new_instance(1, &arg, c));
14663}
14664
14665static VALUE
14666get_LAST_READ_LINE(ID _x, VALUE *_y)
14667{
14668 return rb_lastline_get();
14669}
14670
14671static void
14672set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14673{
14674 rb_lastline_set(val);
14675}
14676
14677/*
14678 * Document-class: IOError
14679 *
14680 * Raised when an IO operation fails.
14681 *
14682 * File.open("/etc/hosts") {|f| f << "example"}
14683 * #=> IOError: not opened for writing
14684 *
14685 * File.open("/etc/hosts") {|f| f.close; f.read }
14686 * #=> IOError: closed stream
14687 *
14688 * Note that some IO failures raise <code>SystemCallError</code>s
14689 * and these are not subclasses of IOError:
14690 *
14691 * File.open("does/not/exist")
14692 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14693 */
14694
14695/*
14696 * Document-class: EOFError
14697 *
14698 * Raised by some IO operations when reaching the end of file. Many IO
14699 * methods exist in two forms,
14700 *
14701 * one that returns +nil+ when the end of file is reached, the other
14702 * raises EOFError.
14703 *
14704 * EOFError is a subclass of IOError.
14705 *
14706 * file = File.open("/etc/hosts")
14707 * file.read
14708 * file.gets #=> nil
14709 * file.readline #=> EOFError: end of file reached
14710 * file.close
14711 */
14712
14713/*
14714 * Document-class: ARGF
14715 *
14716 * ARGF is a stream designed for use in scripts that process files given as
14717 * command-line arguments or passed in via STDIN.
14718 *
14719 * The arguments passed to your script are stored in the +ARGV+ Array, one
14720 * argument per element. ARGF assumes that any arguments that aren't
14721 * filenames have been removed from +ARGV+. For example:
14722 *
14723 * $ ruby argf.rb --verbose file1 file2
14724 *
14725 * ARGV #=> ["--verbose", "file1", "file2"]
14726 * option = ARGV.shift #=> "--verbose"
14727 * ARGV #=> ["file1", "file2"]
14728 *
14729 * You can now use ARGF to work with a concatenation of each of these named
14730 * files. For instance, ARGF.read will return the contents of _file1_
14731 * followed by the contents of _file2_.
14732 *
14733 * After a file in +ARGV+ has been read ARGF removes it from the Array.
14734 * Thus, after all files have been read +ARGV+ will be empty.
14735 *
14736 * You can manipulate +ARGV+ yourself to control what ARGF operates on. If
14737 * you remove a file from +ARGV+, it is ignored by ARGF; if you add files to
14738 * +ARGV+, they are treated as if they were named on the command line. For
14739 * example:
14740 *
14741 * ARGV.replace ["file1"]
14742 * ARGF.readlines # Returns the contents of file1 as an Array
14743 * ARGV #=> []
14744 * ARGV.replace ["file2", "file3"]
14745 * ARGF.read # Returns the contents of file2 and file3
14746 *
14747 * If +ARGV+ is empty, ARGF acts as if it contained <tt>"-"</tt> that
14748 * makes ARGF read from STDIN, i.e. the data piped or typed to your
14749 * script. For example:
14750 *
14751 * $ echo "glark" | ruby -e 'p ARGF.read'
14752 * "glark\n"
14753 *
14754 * $ echo Glark > file1
14755 * $ echo "glark" | ruby -e 'p ARGF.read' -- - file1
14756 * "glark\nGlark\n"
14757 */
14758
14759/*
14760 * An instance of class \IO (commonly called a _stream_)
14761 * represents an input/output stream in the underlying operating system.
14762 * \Class \IO is the basis for input and output in Ruby.
14763 *
14764 * \Class File is the only class in the Ruby core that is a subclass of \IO.
14765 * Some classes in the Ruby standard library are also subclasses of \IO;
14766 * these include TCPSocket and UDPSocket.
14767 *
14768 * The global constant ARGF (also accessible as <tt>$<</tt>)
14769 * provides an IO-like stream that allows access to all file paths
14770 * found in ARGV (or found in STDIN if ARGV is empty).
14771 * ARGF is not itself a subclass of \IO.
14772 *
14773 * \Class StringIO provides an IO-like stream that handles a String.
14774 * StringIO is not itself a subclass of \IO.
14775 *
14776 * Important objects based on \IO include:
14777 *
14778 * - $stdin.
14779 * - $stdout.
14780 * - $stderr.
14781 * - Instances of class File.
14782 *
14783 * An instance of \IO may be created using:
14784 *
14785 * - IO.new: returns a new \IO object for the given integer file descriptor.
14786 * - IO.open: passes a new \IO object to the given block.
14787 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
14788 * of a newly-launched subprocess.
14789 * - Kernel#open: Returns a new \IO object connected to a given source:
14790 * stream, file, or subprocess.
14791 *
14792 * Like a File stream, an \IO stream has:
14793 *
14794 * - A read/write mode, which may be read-only, write-only, or read/write;
14795 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
14796 * - A data mode, which may be text-only or binary;
14797 * see {Data Mode}[rdoc-ref:File@Data+Mode].
14798 * - Internal and external encodings;
14799 * see {Encodings}[rdoc-ref:File@Encodings].
14800 *
14801 * And like other \IO streams, it has:
14802 *
14803 * - A position, which determines where in the stream the next
14804 * read or write is to occur;
14805 * see {Position}[rdoc-ref:IO@Position].
14806 * - A line number, which is a special, line-oriented, "position"
14807 * (different from the position mentioned above);
14808 * see {Line Number}[rdoc-ref:IO@Line+Number].
14809 *
14810 * == Extension <tt>io/console</tt>
14811 *
14812 * Extension <tt>io/console</tt> provides numerous methods
14813 * for interacting with the console;
14814 * requiring it adds numerous methods to class \IO.
14815 *
14816 * == Example Files
14817 *
14818 * Many examples here use these variables:
14819 *
14820 * :include: doc/examples/files.rdoc
14821 *
14822 * == Open Options
14823 *
14824 * A number of \IO methods accept optional keyword arguments
14825 * that determine how a new stream is to be opened:
14826 *
14827 * - +:mode+: Stream mode.
14828 * - +:flags+: Integer file open flags;
14829 * If +mode+ is also given, the two are bitwise-ORed.
14830 * - +:external_encoding+: External encoding for the stream.
14831 * - +:internal_encoding+: Internal encoding for the stream.
14832 * <tt>'-'</tt> is a synonym for the default internal encoding.
14833 * If the value is +nil+ no conversion occurs.
14834 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
14835 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
14836 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
14837 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
14838 * when the stream closes; otherwise it remains open.
14839 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
14840 * #path method.
14841 *
14842 * Also available are the options offered in String#encode,
14843 * which may control conversion between external and internal encoding.
14844 *
14845 * == Basic \IO
14846 *
14847 * You can perform basic stream \IO with these methods,
14848 * which typically operate on multi-byte strings:
14849 *
14850 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
14851 * - IO#write: Writes zero or more strings to the stream;
14852 * each given object that is not already a string is converted via +to_s+.
14853 *
14854 * === Position
14855 *
14856 * An \IO stream has a nonnegative integer _position_,
14857 * which is the byte offset at which the next read or write is to occur.
14858 * A new stream has position zero (and line number zero);
14859 * method +rewind+ resets the position (and line number) to zero.
14860 *
14861 * The relevant methods:
14862 *
14863 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
14864 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
14865 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
14866 * relative to a given position +whence+
14867 * (indicating the beginning, end, or current position).
14868 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
14869 *
14870 * === Open and Closed Streams
14871 *
14872 * A new \IO stream may be open for reading, open for writing, or both.
14873 *
14874 * A stream is automatically closed when claimed by the garbage collector.
14875 *
14876 * Attempted reading or writing on a closed stream raises an exception.
14877 *
14878 * The relevant methods:
14879 *
14880 * - IO#close: Closes the stream for both reading and writing.
14881 * - IO#close_read: Closes the stream for reading.
14882 * - IO#close_write: Closes the stream for writing.
14883 * - IO#closed?: Returns whether the stream is closed.
14884 *
14885 * === End-of-Stream
14886 *
14887 * You can query whether a stream is positioned at its end:
14888 *
14889 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
14890 *
14891 * You can reposition to end-of-stream by using method IO#seek:
14892 *
14893 * f = File.new('t.txt')
14894 * f.eof? # => false
14895 * f.seek(0, :END)
14896 * f.eof? # => true
14897 * f.close
14898 *
14899 * Or by reading all stream content (which is slower than using IO#seek):
14900 *
14901 * f.rewind
14902 * f.eof? # => false
14903 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14904 * f.eof? # => true
14905 *
14906 * == Line \IO
14907 *
14908 * You can read an \IO stream line-by-line using these methods:
14909 *
14910 * - IO#each_line: Reads each remaining line, passing it to the given block.
14911 * - IO#gets: Returns the next line.
14912 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
14913 * - IO#readlines: Returns all remaining lines in an array.
14914 *
14915 * Each of these reader methods accepts:
14916 *
14917 * - An optional line separator, +sep+;
14918 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
14919 * - An optional line-size limit, +limit+;
14920 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
14921 *
14922 * For each of these reader methods, reading may begin mid-line,
14923 * depending on the stream's position;
14924 * see {Position}[rdoc-ref:IO@Position]:
14925 *
14926 * f = File.new('t.txt')
14927 * f.pos = 27
14928 * f.each_line {|line| p line }
14929 * f.close
14930 *
14931 * Output:
14932 *
14933 * "rth line\n"
14934 * "Fifth line\n"
14935 *
14936 * You can write to an \IO stream line-by-line using this method:
14937 *
14938 * - IO#puts: Writes objects to the stream.
14939 *
14940 * === Line Separator
14941 *
14942 * Each of these methods uses a <i>line separator</i>,
14943 * which is the string that delimits lines:
14944 *
14945 * - IO.foreach.
14946 * - IO.readlines.
14947 * - IO#each_line.
14948 * - IO#gets.
14949 * - IO#readline.
14950 * - IO#readlines.
14951 *
14952 * The default line separator is the given by the global variable <tt>$/</tt>,
14953 * whose value is by default <tt>"\n"</tt>.
14954 * The line to be read next is all data from the current position
14955 * to the next line separator:
14956 *
14957 * f = File.new('t.txt')
14958 * f.gets # => "First line\n"
14959 * f.gets # => "Second line\n"
14960 * f.gets # => "\n"
14961 * f.gets # => "Fourth line\n"
14962 * f.gets # => "Fifth line\n"
14963 * f.close
14964 *
14965 * You can specify a different line separator:
14966 *
14967 * f = File.new('t.txt')
14968 * f.gets('l') # => "First l"
14969 * f.gets('li') # => "ine\nSecond li"
14970 * f.gets('lin') # => "ne\n\nFourth lin"
14971 * f.gets # => "e\n"
14972 * f.close
14973 *
14974 * There are two special line separators:
14975 *
14976 * - +nil+: The entire stream is read into a single string:
14977 *
14978 * f = File.new('t.txt')
14979 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14980 * f.close
14981 *
14982 * - <tt>''</tt> (the empty string): The next "paragraph" is read
14983 * (paragraphs being separated by two consecutive line separators):
14984 *
14985 * f = File.new('t.txt')
14986 * f.gets('') # => "First line\nSecond line\n\n"
14987 * f.gets('') # => "Fourth line\nFifth line\n"
14988 * f.close
14989 *
14990 * === Line Limit
14991 *
14992 * Each of these methods uses a <i>line limit</i>,
14993 * which specifies that the number of bytes returned may not be (much) longer
14994 * than the given +limit+;
14995 *
14996 * - IO.foreach.
14997 * - IO.readlines.
14998 * - IO#each_line.
14999 * - IO#gets.
15000 * - IO#readline.
15001 * - IO#readlines.
15002 *
15003 * A multi-byte character will not be split, and so a line may be slightly longer
15004 * than the given limit.
15005 *
15006 * If +limit+ is not given, the line is determined only by +sep+.
15007 *
15008 * # Text with 1-byte characters.
15009 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15010 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15011 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15012 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15013 * # No more than one line.
15014 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15015 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15016 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15017 *
15018 * # Text with 2-byte characters, which will not be split.
15019 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15020 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15021 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15022 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15023 *
15024 * === Line Separator and Line Limit
15025 *
15026 * With arguments +sep+ and +limit+ given,
15027 * combines the two behaviors:
15028 *
15029 * - Returns the next line as determined by line separator +sep+.
15030 * - But returns no more bytes than are allowed by the limit.
15031 *
15032 * Example:
15033 *
15034 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15035 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15036 *
15037 * === Line Number
15038 *
15039 * A readable \IO stream has a non-negative integer <i>line number</i>.
15040 *
15041 * The relevant methods:
15042 *
15043 * - IO#lineno: Returns the line number.
15044 * - IO#lineno=: Resets and returns the line number.
15045 *
15046 * Unless modified by a call to method IO#lineno=,
15047 * the line number is the number of lines read
15048 * by certain line-oriented methods,
15049 * according to the given line separator +sep+:
15050 *
15051 * - IO.foreach: Increments the line number on each call to the block.
15052 * - IO#each_line: Increments the line number on each call to the block.
15053 * - IO#gets: Increments the line number.
15054 * - IO#readline: Increments the line number.
15055 * - IO#readlines: Increments the line number for each line read.
15056 *
15057 * A new stream is initially has line number zero (and position zero);
15058 * method +rewind+ resets the line number (and position) to zero:
15059 *
15060 * f = File.new('t.txt')
15061 * f.lineno # => 0
15062 * f.gets # => "First line\n"
15063 * f.lineno # => 1
15064 * f.rewind
15065 * f.lineno # => 0
15066 * f.close
15067 *
15068 * Reading lines from a stream usually changes its line number:
15069 *
15070 * f = File.new('t.txt', 'r')
15071 * f.lineno # => 0
15072 * f.readline # => "This is line one.\n"
15073 * f.lineno # => 1
15074 * f.readline # => "This is the second line.\n"
15075 * f.lineno # => 2
15076 * f.readline # => "Here's the third line.\n"
15077 * f.lineno # => 3
15078 * f.eof? # => true
15079 * f.close
15080 *
15081 * Iterating over lines in a stream usually changes its line number:
15082 *
15083 * File.open('t.txt') do |f|
15084 * f.each_line do |line|
15085 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15086 * end
15087 * end
15088 *
15089 * Output:
15090 *
15091 * "position=11 eof?=false lineno=1"
15092 * "position=23 eof?=false lineno=2"
15093 * "position=24 eof?=false lineno=3"
15094 * "position=36 eof?=false lineno=4"
15095 * "position=47 eof?=true lineno=5"
15096 *
15097 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15098 * the line number does not affect where the next read or write will occur:
15099 *
15100 * f = File.new('t.txt')
15101 * f.lineno = 1000
15102 * f.lineno # => 1000
15103 * f.gets # => "First line\n"
15104 * f.lineno # => 1001
15105 * f.close
15106 *
15107 * Associated with the line number is the global variable <tt>$.</tt>:
15108 *
15109 * - When a stream is opened, <tt>$.</tt> is not set;
15110 * its value is left over from previous activity in the process:
15111 *
15112 * $. = 41
15113 * f = File.new('t.txt')
15114 * $. = 41
15115 * # => 41
15116 * f.close
15117 *
15118 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15119 *
15120 * f0 = File.new('t.txt')
15121 * f1 = File.new('t.dat')
15122 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15123 * $. # => 5
15124 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15125 * $. # => 1
15126 * f0.close
15127 * f1.close
15128 *
15129 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15130 *
15131 * f = File.new('t.txt')
15132 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15133 * $. # => 5
15134 * f.rewind
15135 * f.seek(0, :SET)
15136 * $. # => 5
15137 * f.close
15138 *
15139 * == Character \IO
15140 *
15141 * You can process an \IO stream character-by-character using these methods:
15142 *
15143 * - IO#getc: Reads and returns the next character from the stream.
15144 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15145 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15146 * - IO#putc: Writes a character to the stream.
15147 * - IO#each_char: Reads each remaining character in the stream,
15148 * passing the character to the given block.
15149 * == Byte \IO
15150 *
15151 * You can process an \IO stream byte-by-byte using these methods:
15152 *
15153 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15154 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15155 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15156 * - IO#each_byte: Reads each remaining byte in the stream,
15157 * passing the byte to the given block.
15158 *
15159 * == Codepoint \IO
15160 *
15161 * You can process an \IO stream codepoint-by-codepoint:
15162 *
15163 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15164 *
15165 * == What's Here
15166 *
15167 * First, what's elsewhere. \Class \IO:
15168 *
15169 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15170 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15171 * which provides dozens of additional methods.
15172 *
15173 * Here, class \IO provides methods that are useful for:
15174 *
15175 * - {Creating}[rdoc-ref:IO@Creating]
15176 * - {Reading}[rdoc-ref:IO@Reading]
15177 * - {Writing}[rdoc-ref:IO@Writing]
15178 * - {Positioning}[rdoc-ref:IO@Positioning]
15179 * - {Iterating}[rdoc-ref:IO@Iterating]
15180 * - {Settings}[rdoc-ref:IO@Settings]
15181 * - {Querying}[rdoc-ref:IO@Querying]
15182 * - {Buffering}[rdoc-ref:IO@Buffering]
15183 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15184 * - {Other}[rdoc-ref:IO@Other]
15185 *
15186 * === Creating
15187 *
15188 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15189 * integer file descriptor.
15190 * - ::open: Creates a new \IO object.
15191 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15192 * - ::popen: Creates an \IO object to interact with a subprocess.
15193 * - ::select: Selects which given \IO instances are ready for reading,
15194 * writing, or have pending exceptions.
15195 *
15196 * === Reading
15197 *
15198 * - ::binread: Returns a binary string with all or a subset of bytes
15199 * from the given file.
15200 * - ::read: Returns a string with all or a subset of bytes from the given file.
15201 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15202 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15203 * - #getc: Returns the next character read from +self+ as a string.
15204 * - #gets: Returns the line read from +self+.
15205 * - #pread: Returns all or the next _n_ bytes read from +self+,
15206 * not updating the receiver's offset.
15207 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15208 * for a given _n_.
15209 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15210 * in non-block mode.
15211 * - #readbyte: Returns the next byte read from +self+;
15212 * same as #getbyte, but raises an exception on end-of-stream.
15213 * - #readchar: Returns the next character read from +self+;
15214 * same as #getc, but raises an exception on end-of-stream.
15215 * - #readline: Returns the next line read from +self+;
15216 * same as #getline, but raises an exception of end-of-stream.
15217 * - #readlines: Returns an array of all lines read read from +self+.
15218 * - #readpartial: Returns up to the given number of bytes from +self+.
15219 *
15220 * === Writing
15221 *
15222 * - ::binwrite: Writes the given string to the file at the given filepath,
15223 * in binary mode.
15224 * - ::write: Writes the given string to +self+.
15225 * - #<<: Appends the given string to +self+.
15226 * - #print: Prints last read line or given objects to +self+.
15227 * - #printf: Writes to +self+ based on the given format string and objects.
15228 * - #putc: Writes a character to +self+.
15229 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15230 * - #pwrite: Writes the given string at the given offset,
15231 * not updating the receiver's offset.
15232 * - #write: Writes one or more given strings to +self+.
15233 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15234 *
15235 * === Positioning
15236 *
15237 * - #lineno: Returns the current line number in +self+.
15238 * - #lineno=: Sets the line number is +self+.
15239 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15240 * - #pos=: Sets the byte offset in +self+.
15241 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15242 * - #rewind: Positions +self+ to the beginning of input.
15243 * - #seek: Sets the offset for +self+ relative to given position.
15244 *
15245 * === Iterating
15246 *
15247 * - ::foreach: Yields each line of given file to the block.
15248 * - #each (aliased as #each_line): Calls the given block
15249 * with each successive line in +self+.
15250 * - #each_byte: Calls the given block with each successive byte in +self+
15251 * as an integer.
15252 * - #each_char: Calls the given block with each successive character in +self+
15253 * as a string.
15254 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15255 * as an integer.
15256 *
15257 * === Settings
15258 *
15259 * - #autoclose=: Sets whether +self+ auto-closes.
15260 * - #binmode: Sets +self+ to binary mode.
15261 * - #close: Closes +self+.
15262 * - #close_on_exec=: Sets the close-on-exec flag.
15263 * - #close_read: Closes +self+ for reading.
15264 * - #close_write: Closes +self+ for writing.
15265 * - #set_encoding: Sets the encoding for +self+.
15266 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15267 * Unicode byte-order-mark.
15268 * - #sync=: Sets the sync-mode to the given value.
15269 *
15270 * === Querying
15271 *
15272 * - #autoclose?: Returns whether +self+ auto-closes.
15273 * - #binmode?: Returns whether +self+ is in binary mode.
15274 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15275 * - #closed?: Returns whether +self+ is closed.
15276 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15277 * - #external_encoding: Returns the external encoding object for +self+.
15278 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15279 * - #internal_encoding: Returns the internal encoding object for +self+.
15280 * - #pid: Returns the process ID of a child process associated with +self+,
15281 * if +self+ was created by ::popen.
15282 * - #stat: Returns the File::Stat object containing status information for +self+.
15283 * - #sync: Returns whether +self+ is in sync-mode.
15284 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15285 *
15286 * === Buffering
15287 *
15288 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15289 * - #flush: Flushes any buffered data within +self+ to the underlying
15290 * operating system.
15291 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15292 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15293 * - #ungetc: Prepends buffer for +self+ with given string.
15294 *
15295 * === Low-Level Access
15296 *
15297 * - ::sysopen: Opens the file given by its path,
15298 * returning the integer file descriptor.
15299 * - #advise: Announces the intention to access data from +self+ in a specific way.
15300 * - #fcntl: Passes a low-level command to the file specified
15301 * by the given file descriptor.
15302 * - #ioctl: Passes a low-level command to the device specified
15303 * by the given file descriptor.
15304 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15305 * - #sysseek: Sets the offset for +self+.
15306 * - #syswrite: Writes the given string to +self+ using a low-level write.
15307 *
15308 * === Other
15309 *
15310 * - ::copy_stream: Copies data from a source to a destination,
15311 * each of which is a filepath or an \IO-like object.
15312 * - ::try_convert: Returns a new \IO object resulting from converting
15313 * the given object.
15314 * - #inspect: Returns the string representation of +self+.
15315 *
15316 */
15317
15318void
15319Init_IO(void)
15320{
15321 VALUE rb_cARGF;
15322#ifdef __CYGWIN__
15323#include <sys/cygwin.h>
15324 static struct __cygwin_perfile pf[] =
15325 {
15326 {"", O_RDONLY | O_BINARY},
15327 {"", O_WRONLY | O_BINARY},
15328 {"", O_RDWR | O_BINARY},
15329 {"", O_APPEND | O_BINARY},
15330 {NULL, 0}
15331 };
15332 cygwin_internal(CW_PERFILE, pf);
15333#endif
15334
15335 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15336 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15337
15338 id_write = rb_intern_const("write");
15339 id_read = rb_intern_const("read");
15340 id_getc = rb_intern_const("getc");
15341 id_flush = rb_intern_const("flush");
15342 id_readpartial = rb_intern_const("readpartial");
15343 id_set_encoding = rb_intern_const("set_encoding");
15344 id_fileno = rb_intern_const("fileno");
15345
15346 rb_define_global_function("syscall", rb_f_syscall, -1);
15347
15348 rb_define_global_function("open", rb_f_open, -1);
15349 rb_define_global_function("printf", rb_f_printf, -1);
15350 rb_define_global_function("print", rb_f_print, -1);
15351 rb_define_global_function("putc", rb_f_putc, 1);
15352 rb_define_global_function("puts", rb_f_puts, -1);
15353 rb_define_global_function("gets", rb_f_gets, -1);
15354 rb_define_global_function("readline", rb_f_readline, -1);
15355 rb_define_global_function("select", rb_f_select, -1);
15356
15357 rb_define_global_function("readlines", rb_f_readlines, -1);
15358
15359 rb_define_global_function("`", rb_f_backquote, 1);
15360
15361 rb_define_global_function("p", rb_f_p, -1);
15362 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15363
15364 rb_cIO = rb_define_class("IO", rb_cObject);
15365 rb_include_module(rb_cIO, rb_mEnumerable);
15366
15367 /* Can be raised by IO operations when IO#timeout= is set. */
15368 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15369
15370 /* Readable event mask for IO#wait. */
15371 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15372 /* Writable event mask for IO#wait. */
15373 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15374 /* Priority event mask for IO#wait. */
15375 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15376
15377 /* exception to wait for reading. see IO.select. */
15378 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15379 /* exception to wait for writing. see IO.select. */
15380 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15381 /* exception to wait for reading by EAGAIN. see IO.select. */
15382 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15383 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15384 /* exception to wait for writing by EAGAIN. see IO.select. */
15385 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15386 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15387#if EAGAIN == EWOULDBLOCK
15388 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15389 /* same as IO::EAGAINWaitReadable */
15390 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15391 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15392 /* same as IO::EAGAINWaitWritable */
15393 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15394#else
15395 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15396 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15397 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15398 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15399 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15400 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15401#endif
15402 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15403 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15404 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15405 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15406 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15407 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15408
15409#if 0
15410 /* This is necessary only for forcing rdoc handle File::open */
15411 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15412#endif
15413
15414 rb_define_alloc_func(rb_cIO, io_alloc);
15415 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15416 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15417 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15418 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15419 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15420 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15421 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15422 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15423 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15424 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15425 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15426 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15427 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15428 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15429 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15430
15431 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15432
15433 rb_output_fs = Qnil;
15434 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15435
15436 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15437 rb_gc_register_mark_object(rb_default_rs);
15438 rb_rs = rb_default_rs;
15439 rb_output_rs = Qnil;
15440 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15441 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15442 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15443
15444 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15445 rb_gvar_ractor_local("$_");
15446
15447 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15448 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15449
15450 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15451 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15452 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15453 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15454
15455 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15456 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15457 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15458 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15459 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15460
15461 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15462 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15463
15464 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15465 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15466
15467 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15468 rb_define_alias(rb_cIO, "to_i", "fileno");
15469 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15470
15471 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15472 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15473
15474 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15475 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15476 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15477 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15478
15479 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15480 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15481
15482 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15483
15484 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15485 rb_define_method(rb_cIO, "read", io_read, -1);
15486 rb_define_method(rb_cIO, "write", io_write_m, -1);
15487 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15488 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15489 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15490 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15491 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15492 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15493 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15494 rb_define_method(rb_cIO, "<<", rb_io_addstr, 1);
15495 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15496 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15497 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15498 /* Set I/O position from the beginning */
15499 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15500 /* Set I/O position from the current position */
15501 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15502 /* Set I/O position from the end */
15503 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15504#ifdef SEEK_DATA
15505 /* Set I/O position to the next location containing data */
15506 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15507#endif
15508#ifdef SEEK_HOLE
15509 /* Set I/O position to the next hole */
15510 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15511#endif
15512 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15513 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15514 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15515 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15516 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15517
15518 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15519 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15520
15521 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15522 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15523 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15524 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15525
15526 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15527 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15528 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15529 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15530 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15531 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15532
15533 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15534 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15535 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15536
15537 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15538 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15539
15540 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15541
15542 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15543 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15544 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15545 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15546
15547 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15548 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15549
15550 rb_define_method(rb_cIO, "wait", io_wait, -1);
15551
15552 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15553 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15554 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15555
15556 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15557 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15558 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15559 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15560
15561 rb_gvar_ractor_local("$stdin");
15562 rb_gvar_ractor_local("$stdout");
15563 rb_gvar_ractor_local("$>");
15564 rb_gvar_ractor_local("$stderr");
15565
15566 rb_global_variable(&rb_stdin);
15567 rb_stdin = rb_io_prep_stdin();
15568 rb_global_variable(&rb_stdout);
15569 rb_stdout = rb_io_prep_stdout();
15570 rb_global_variable(&rb_stderr);
15571 rb_stderr = rb_io_prep_stderr();
15572
15573 orig_stdout = rb_stdout;
15574 orig_stderr = rb_stderr;
15575
15576 /* Holds the original stdin */
15577 rb_define_global_const("STDIN", rb_stdin);
15578 /* Holds the original stdout */
15579 rb_define_global_const("STDOUT", rb_stdout);
15580 /* Holds the original stderr */
15581 rb_define_global_const("STDERR", rb_stderr);
15582
15583#if 0
15584 /* Hack to get rdoc to regard ARGF as a class: */
15585 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15586#endif
15587
15588 rb_cARGF = rb_class_new(rb_cObject);
15589 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15590 rb_define_alloc_func(rb_cARGF, argf_alloc);
15591
15592 rb_include_module(rb_cARGF, rb_mEnumerable);
15593
15594 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15595 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15596 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15597 rb_define_alias(rb_cARGF, "inspect", "to_s");
15598 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15599
15600 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15601 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15602 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15603 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15604 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15605 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15606 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15607 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15608 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15609
15610 rb_define_method(rb_cARGF, "read", argf_read, -1);
15611 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15612 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15613 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15614 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15615 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15616 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15617 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15618 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15619 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15620 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15621 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15622 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15623 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15624 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15625 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15626 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15627 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15628 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15629 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15630
15631 rb_define_method(rb_cARGF, "write", argf_write, 1);
15632 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15633 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15634 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15635 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15636
15637 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15638 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15639 rb_define_method(rb_cARGF, "file", argf_file, 0);
15640 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15641 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15642 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15643
15644 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15645 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15646
15647 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15648 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15649
15650 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15651 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15652 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15653
15654 argf = rb_class_new_instance(0, 0, rb_cARGF);
15655
15656 rb_define_readonly_variable("$<", &argf);
15657 /*
15658 * ARGF is a stream designed for use in scripts that process files given
15659 * as command-line arguments or passed in via STDIN.
15660 *
15661 * See ARGF (the class) for more details.
15662 */
15663 rb_define_global_const("ARGF", argf);
15664
15665 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15666 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15667 ARGF.filename = rb_str_new2("-");
15668
15669 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15670 rb_gvar_ractor_local("$-i");
15671
15672 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15673
15674#if defined (_WIN32) || defined(__CYGWIN__)
15675 atexit(pipe_atexit);
15676#endif
15677
15678 Init_File();
15679
15680 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15681
15682 sym_mode = ID2SYM(rb_intern_const("mode"));
15683 sym_perm = ID2SYM(rb_intern_const("perm"));
15684 sym_flags = ID2SYM(rb_intern_const("flags"));
15685 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15686 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15687 sym_encoding = ID2SYM(rb_id_encoding());
15688 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15689 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15690 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15691 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15692 sym_normal = ID2SYM(rb_intern_const("normal"));
15693 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15694 sym_random = ID2SYM(rb_intern_const("random"));
15695 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15696 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15697 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15698 sym_SET = ID2SYM(rb_intern_const("SET"));
15699 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15700 sym_END = ID2SYM(rb_intern_const("END"));
15701#ifdef SEEK_DATA
15702 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15703#endif
15704#ifdef SEEK_HOLE
15705 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15706#endif
15707 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15708 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15709}
15710
15711#include "io.rbinc"
rb_atomic_t
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
buffer.h
ruby_strtoul
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:137
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition cxxanyargs.hpp:670
rb_define_singleton_method
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition cxxanyargs.hpp:685
rb_define_global_function
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
Definition cxxanyargs.hpp:695
rb_include_module
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1177
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:970
rb_class_new
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:350
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1002
rb_define_module_under
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1109
rb_define_alias
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2332
rb_scan_args_kw
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
Definition class.c:2635
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:2622
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:866
rb_get_kwargs
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2411
ECONV_AFTER_OUTPUT
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
rb_str_new2
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
TYPE
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:107
NEWOBJ_OF
#define NEWOBJ_OF
Old name of RB_NEWOBJ_OF.
Definition newobj.h:61
FL_SINGLETON
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
Definition fl_type.h:58
RB_INTEGER_TYPE_P
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
ENC_CODERANGE_7BIT
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
T_FILE
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
ENC_CODERANGE_VALID
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
ECONV_UNIVERSAL_NEWLINE_DECORATOR
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
OBJ_INIT_COPY
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
ALLOC
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:394
T_STRING
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
Qundef
#define Qundef
Old name of RUBY_Qundef.
Definition special_consts.h:62
INT2FIX
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
rb_str_cat2
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
T_NIL
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
UNREACHABLE
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
ID2SYM
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
T_BIGNUM
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
OBJ_FREEZE
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:135
T_FIXNUM
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
FIX2UINT
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
SSIZET2NUM
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
ZALLOC
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:396
CLASS_OF
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
rb_ary_new4
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:653
ECONV_NEWLINE_DECORATOR_WRITE_MASK
#define ECONV_NEWLINE_DECORATOR_WRITE_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_WRITE_MASK.
Definition transcode.h:531
ENCODING_MAXNAMELEN
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:110
MBCLEN_NEEDMORE_LEN
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:519
ENCODING_GET
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:108
LONG2FIX
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
NUM2UINT
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
ALLOC_N
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:393
MBCLEN_CHARFOUND_LEN
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:516
LONG2NUM
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
rb_exc_new3
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
STRNCASECMP
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
MBCLEN_INVALID_P
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:517
ISASCII
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
ECONV_STATEFUL_DECORATOR_MASK
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
Qtrue
#define Qtrue
Old name of RUBY_Qtrue.
Definition special_consts.h:61
MBCLEN_NEEDMORE_P
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:518
ECONV_PARTIAL_INPUT
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
NUM2INT
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
ECONV_ERROR_HANDLER_MASK
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
INT2NUM
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
Qnil
#define Qnil
Old name of RUBY_Qnil.
Definition special_consts.h:60
Qfalse
#define Qfalse
Old name of RUBY_Qfalse.
Definition special_consts.h:59
FIX2LONG
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
ENC_CODERANGE_BROKEN
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
T_ARRAY
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
NIL_P
#define NIL_P
Old name of RB_NIL_P.
Definition special_consts.h:55
ALLOCV_N
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:399
MBCLEN_CHARFOUND_P
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:515
ECONV_NEWLINE_DECORATOR_READ_MASK
#define ECONV_NEWLINE_DECORATOR_READ_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_READ_MASK.
Definition transcode.h:530
NUM2CHR
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
FL_TEST
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:131
NUM2LONG
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
UINT2NUM
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
FIXNUM_P
#define FIXNUM_P
Old name of RB_FIXNUM_P.
Definition special_consts.h:53
ECONV_NEWLINE_DECORATOR_MASK
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
CONST_ID
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
rb_ary_new2
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:651
NUM2SIZET
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
ENC_CODERANGE_SET
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
rb_str_new4
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1677
ALLOCV_END
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:400
SYMBOL_P
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
ECONV_DEFAULT_NEWLINE_DECORATOR
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
rb_notimplement
void rb_notimplement(void)
Definition error.c:3498
rb_category_warn
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:433
rb_category_warning
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:465
rb_eNotImpError
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1354
rb_syserr_fail
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3567
rb_readwrite_syserr_fail
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
Definition io.c:14620
rb_eIOError
VALUE rb_eIOError
IOError exception.
Definition io.c:178
rb_eStandardError
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1341
rb_mod_syserr_fail_str
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3657
rb_syserr_fail_str
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3573
ruby_verbose
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:471
rb_eTypeError
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1344
rb_eEOFError
VALUE rb_eEOFError
EOFError exception.
Definition io.c:177
rb_readwrite_sys_fail
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14614
rb_iter_break_value
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2058
rb_io_wait_readwrite
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:69
rb_eRuntimeError
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1342
rb_warn
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:423
rb_eSystemCallError
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1364
RB_WARN_CATEGORY_DEPRECATED
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
rb_mKernel
VALUE rb_mKernel
Kernel module.
Definition object.c:63
rb_check_to_int
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3151
rb_any_to_s
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:634
rb_obj_alloc
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2058
rb_class_new_instance
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2099
rb_cIO
VALUE rb_cIO
IO class.
Definition io.c:176
rb_class_new_instance_kw
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
Definition object.c:2087
rb_mEnumerable
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
rb_stdin
VALUE rb_stdin
STDIN constant.
Definition io.c:190
rb_stderr
VALUE rb_stderr
STDERR constant.
Definition io.c:190
rb_obj_class
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:215
rb_obj_dup
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:541
rb_inspect
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:645
rb_mWaitReadable
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:180
rb_mWaitWritable
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:181
rb_check_to_integer
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
Definition object.c:3132
rb_cFile
VALUE rb_cFile
File class.
Definition file.c:175
rb_stdout
VALUE rb_stdout
STDOUT constant.
Definition io.c:190
rb_to_int
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3145
rb_enc_codepoint
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition encoding.h:570
rb_enc_mbc_to_codepoint
static OnigCodePoint rb_enc_mbc_to_codepoint(const char *p, const char *e, rb_encoding *enc)
Identical to rb_enc_codepoint(), except it assumes the passed character is not broken.
Definition encoding.h:590
rb_enc_mbminlen
static int rb_enc_mbminlen(rb_encoding *enc)
Queries the minimum number of bytes that the passed encoding needs to represent a character.
Definition encoding.h:431
rb_enc_uint_chr
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3739
rb_str_coderange_scan_restartable
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:653
rb_econv_prepare_options
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2600
rb_econv_open_exc
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2097
rb_econv_convert
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1475
rb_econv_result_t
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
econv_incomplete_input
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
econv_finished
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
econv_undefined_conversion
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
econv_source_buffer_empty
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
econv_destination_buffer_full
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
econv_invalid_byte_sequence
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
rb_econv_putbackable
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1770
rb_econv_asciicompat_encoding
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1814
rb_econv_str_convert
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1931
rb_econv_open_opts
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2651
rb_econv_binmode
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:1996
rb_str_encode
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2914
rb_econv_make_exception
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4272
rb_econv_check_error
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4278
rb_econv_close
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1731
rb_econv_putback
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1781
rb_funcall
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1121
rb_funcallv_kw
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1088
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:239
rb_check_frozen
#define rb_check_frozen
Just another name of rb_check_frozen.
Definition error.h:264
rb_check_arity
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:280
rb_io_printf
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8583
rb_io_gets
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4268
rb_cloexec_pipe
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:405
rb_io_print
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8709
rb_io_addstr
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2317
rb_write_error
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9138
rb_io_ungetbyte
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
Definition io.c:5144
rb_io_getbyte
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5050
rb_cloexec_dup2
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:352
rb_io_fdopen
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
Definition io.c:9298
rb_update_max_fd
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:226
rb_cloexec_open
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:306
rb_output_rs
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:195
rb_io_eof
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2662
rb_write_error2
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9118
rb_close_before_exec
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
rb_reserved_fd_p
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
rb_fd_fix_cloexec
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
Definition io.c:276
rb_io_ascii8bit_binmode
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6351
rb_io_binmode
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6305
rb_io_ungetc
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5208
rb_pipe
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7343
rb_gets
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10360
rb_cloexec_fcntl_dupfd
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:439
rb_file_open_str
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
Definition io.c:7226
rb_cloexec_dup
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:345
rb_file_open
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7233
rb_io_close
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5731
rb_lastline_set
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:1820
rb_lastline_get
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1814
rb_obj_method_arity
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
Definition proc.c:2906
rb_waitpid
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1269
rb_last_status_set
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:682
rb_str_append
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3411
rb_str_new
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
rb_str_buf_cat
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
rb_usascii_str_new
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1532
rb_str_capacity
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:815
rb_str_locktmp
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_str_setter
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
rb_str_buf_cat_ascii
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
Definition string.c:3353
rb_check_string_type
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2681
rb_str_substr
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:2979
rb_str_unlocktmp
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3072
rb_str_modify_expand
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2486
rb_str_new_cstr
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
rb_thread_interrupted
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1435
rb_mutex_new
VALUE rb_mutex_new(void)
Creates a mutex.
Definition thread_sync.c:191
rb_thread_fd_writable
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
Definition io.c:1572
RUBY_UBF_IO
#define RUBY_UBF_IO
A special UBF for blocking IO operations.
Definition thread.h:382
rb_exec_recursive
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
Definition thread.c:5266
rb_thread_fd_close
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
Definition thread.c:2650
rb_mutex_synchronize
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
Definition thread_sync.c:640
rb_thread_check_ints
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1418
rb_thread_current
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:2927
rb_thread_wait_fd
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1566
rb_thread_sleep
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1441
rb_time_interval
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2875
rb_set_class_path
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:343
rb_ivar_set
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1854
rb_class_name
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:402
rb_respond_to
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:2937
rb_check_funcall
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:687
rb_define_alloc_func
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
rb_intern_const
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:276
RB_ID2SYM
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
rb_define_global_const
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:3702
rb_define_readonly_variable
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:722
rb_gvar_readonly_setter
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
rb_define_const
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition variable.c:3690
io.h
FMODE_READABLE
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:270
rb_io_modestr_fmode
int rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6437
rb_io_get_io
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:792
rb_io_timeout
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:838
rb_io_taint_check
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:762
rb_io_read_check
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1049
rb_io_modestr_oflags
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
Definition io.c:6570
FMODE_SETENC_BY_BOM
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
Definition io.h:368
rb_io_mode
int rb_io_mode(VALUE io)
Get the mode of the IO.
Definition io.c:2883
rb_io_event
rb_io_event
Type of events that an IO can wait.
Definition io.h:81
RUBY_IO_READABLE
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:82
RUBY_IO_PRIORITY
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:84
RUBY_IO_WRITABLE
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:83
FMODE_READWRITE
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:276
FMODE_EXTERNAL
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:360
GetOpenFile
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:402
rb_io_check_byte_readable
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:995
FMODE_TTY
#define FMODE_TTY
The IO is a TTY.
Definition io.h:300
FMODE_CREATE
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:323
rb_io_check_readable
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1004
rb_io_extract_encoding_option
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:6719
rb_io_oflags_fmode
int rb_io_oflags_fmode(int oflags)
Converts an oflags (that rb_io_modestr_oflags() returns) to a fmode (that rb_io_mode_flags() returns)...
Definition io.c:6494
rb_wait_for_single_fd
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition io.c:1560
rb_fdopen
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
Definition io.c:7050
rb_io_descriptor
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2863
FMODE_WRITABLE
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:273
rb_io_stdio_file
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
Definition io.c:9344
FMODE_APPEND
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:315
MakeOpenFile
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:425
FMODE_DUPLEX
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:308
FMODE_BINMODE
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:287
rb_io_maybe_wait_readable
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1619
capa
int capa
Designed capacity of the buffer.
Definition io.h:11
RB_IO_POINTER
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:396
rb_io_maybe_wait
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1578
rb_eIOTimeoutError
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:179
FMODE_SYNC
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:294
off
int off
Offset inside of ptr.
Definition io.h:5
rb_io_path
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:2937
rb_io_check_initialized
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:769
FMODE_EXCL
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
Definition io.h:331
FMODE_TEXTMODE
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:351
rb_io_check_io
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
Definition io.c:798
rb_io_closed_p
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5836
rb_io_buffer_t
struct rb_io_internal_buffer rb_io_buffer_t
Just another name of rb_io_buffer_t.
Definition io.h:110
rb_io_set_timeout
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:867
rb_io_bufwrite
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:1982
rb_io_check_char_readable
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:976
FMODE_TRUNC
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:337
rb_io_read_pending
int rb_io_read_pending(rb_io_t *fptr)
Queries if the passed IO has any pending reads.
Definition io.c:1040
rb_io_get_write_io
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:804
rb_io_set_nonblock
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3389
rb_io_extract_modeenc
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:6844
rb_io_wait_writable
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1517
rb_io_open_descriptor
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
Definition io.c:9231
rb_io_set_write_io
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:815
rb_io_check_writable
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1028
rb_io_maybe_wait_writable
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
Definition io.c:1632
rb_io_check_closed
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:777
rb_eof_error
void rb_eof_error(void)
Utility function to raise rb_eEOFError.
Definition io.c:756
rb_io_wait_readable
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1483
rb_io_synchronized
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7330
rb_io_wait
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1422
len
int len
Length of the buffer.
Definition io.h:8
ractor.h
rb_ractor_stdin
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:2671
rb_ractor_stderr_set
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
Definition ractor.c:2731
rb_ractor_stdout_set
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
Definition ractor.c:2719
rb_ractor_stdin_set
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
Definition ractor.c:2707
thread.h
rb_thread_call_with_gvl
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:1837
rb_thread_call_without_gvl
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
Definition thread.c:1658
util.h
RB_NUM2INT
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
RB_INT2NUM
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
rb_f_sprintf
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:208
RB_BLOCK_CALL_FUNC_ARGLIST
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
rb_yield_values2
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1410
rb_yield
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1376
rb_fd_term
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
MEMZERO
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:354
RB_GC_GUARD
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
MEMMOVE
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:378
NUM2MODET
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
ruby::backward::cxxanyargs::rb_define_hooked_variable
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
Definition cxxanyargs.hpp:136
ruby::backward::cxxanyargs::rb_define_virtual_variable
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
Definition cxxanyargs.hpp:73
ruby::backward::cxxanyargs::rb_rescue2
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
Definition cxxanyargs.hpp:284
ruby::backward::cxxanyargs::rb_ensure
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
Definition cxxanyargs.hpp:310
PRI_OFFT_PREFIX
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
OFFT2NUM
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
NUM2OFFT
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
PIDT2NUM
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
rb_fd_isset
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
rb_fd_select
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
rb_fd_init
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
rb_fd_set
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
RARRAY_LEN
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
RARRAY_LENINT
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition rarray.h:403
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
RFILE
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
SafeStringValue
#define SafeStringValue(v)
Definition rstring.h:98
StringValue
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
RSTRING_GETMEM
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:488
StringValueCStr
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
RUBY_TYPED_DEFAULT_FREE
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:79
rb_data_type_t
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:197
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:497
rb_get_argv
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14580
rb_p
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9017
FilePathValue
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
errno
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
RB_SCAN_ARGS_LAST_HASH_KEYWORDS
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
RB_PASS_CALLED_KEYWORDS
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
scheduler.h
Scheduler APIs.
rb_fiber_scheduler_current
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:219
rb_fiber_scheduler_io_pread_memory
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:631
rb_fiber_scheduler_make_timeout
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:262
rb_fiber_scheduler_io_wait_readable
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:443
rb_fiber_scheduler_io_read_memory
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:607
rb_fiber_scheduler_io_wait
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:437
rb_fiber_scheduler_io_result_apply
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:70
rb_fiber_scheduler_io_selectv
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:473
rb_fiber_scheduler_io_pwrite_memory
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:643
rb_fiber_scheduler_current_for_thread
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:224
rb_fiber_scheduler_io_write_memory
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:619
rb_fiber_scheduler_io_wait_writable
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:449
rb_thread_fd_select
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
Definition thread.c:4275
RB_TEST
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
Definition special_consts.h:138
RTEST
#define RTEST
This is an old name of RB_TEST.
Definition special_consts.h:51
_
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
stdbool.h
C99 shim for <stdbool.h>
RFile
Ruby's File and IO.
Definition rfile.h:35
argf_call_arg
Definition io.c:13863
argf
Definition io.c:214
binwrite_arg
Definition io.c:1700
bufread_arg
Definition io.c:3057
copy_stream_struct
Definition io.c:12395
fiber_scheduler_wait_for_arguments
Definition io.c:12449
finish_writeconv_arg
Definition io.c:5438
foreach_arg
Definition io.c:11906
getline_arg
Definition io.c:4035
io_encoding_set_args
Definition io.c:11720
io_internal_read_struct
Definition io.c:1104
io_internal_write_struct
Definition io.c:1115
iovec
Definition win32.h:218
pipe_list
Definition io.c:7239
prdwr_internal_arg
Definition io.c:6134
rb_execarg
Definition process.h:30
rb_fdset_t
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
rb_global_variable
Definition variable.c:429
rb_io_close_wait_list
Definition thread.h:57
rb_io_encoding
Decomposed encoding flags (e.g.
Definition io.h:119
rb_io_encoding::ecflags
int ecflags
Flags.
Definition io.h:129
rb_io_encoding::ecopts
VALUE ecopts
Flags as Ruby hash.
Definition io.h:137
rb_io_encoding::enc2
rb_encoding * enc2
External encoding.
Definition io.h:123
rb_io_encoding::enc
rb_encoding * enc
Internal encoding.
Definition io.h:121
rb_io_internal_buffer
IO buffers.
Definition io.h:94
rb_io_internal_buffer::ptr
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:97
rb_io_internal_buffer::off
int off
Offset inside of ptr.
Definition io.h:100
rb_io_internal_buffer::len
int len
Length of the buffer.
Definition io.h:103
rb_io_internal_buffer::capa
int capa
Designed capacity of the buffer.
Definition io.h:106
rb_io
Ruby's IO, metadata and buffers.
Definition io.h:143
rb_io::mode
int mode
mode flags: FMODE_XXXs
Definition io.h:158
rb_io::wbuf
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:178
rb_io::finalize
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:174
rb_io::readconv
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:200
rb_io::writeconv
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:211
rb_io::encs
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:196
rb_io::self
VALUE self
The IO's Ruby level counterpart.
Definition io.h:146
rb_io::write_lock
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:248
rb_io::timeout
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:254
rb_io::stdio_file
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:150
rb_io::writeconv_pre_ecopts
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:238
rb_io::tied_io_for_writing
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:193
rb_io::writeconv_initialized
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:224
rb_io::fd
int fd
file descriptor.
Definition io.h:154
rb_io::rbuf
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:185
rb_io::lineno
int lineno
number of lines read
Definition io.h:166
rb_io::writeconv_asciicompat
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:220
rb_io::cbuf
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:207
rb_io::pid
rb_pid_t pid
child's pid (for pipes)
Definition io.h:162
rb_io::writeconv_pre_ecflags
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:231
rb_io::pathv
VALUE pathv
pathname for file
Definition io.h:170
seek_arg
Definition io.c:12137
select_args
Definition io.c:10728
sysopen_struct
Definition io.c:6989
timeval
Definition missing.h:63
write_arg
Definition io.c:1707
SIGNED_VALUE
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
ID
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
RB_SYMBOL_P
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:306
Check_Type
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:432