Ruby 3.2.4p170 (2024-04-23 revision af471c0e0127eea0cafa6f308c0425bbfab0acf5)
io.c
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#ifdef _WIN32
20# include "ruby/ruby.h"
21# include "ruby/io.h"
22#endif
23
24#include <ctype.h>
25#include <errno.h>
26#include <stddef.h>
27
28/* non-Linux poll may not work on all FDs */
29#if defined(HAVE_POLL)
30# if defined(__linux__)
31# define USE_POLL 1
32# endif
33# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
34# define USE_POLL 1
35# endif
36#endif
37
38#ifndef USE_POLL
39# define USE_POLL 0
40#endif
41
42#undef free
43#define free(x) xfree(x)
44
45#if defined(DOSISH) || defined(__CYGWIN__)
46#include <io.h>
47#endif
48
49#include <sys/types.h>
50#if defined HAVE_NET_SOCKET_H
51# include <net/socket.h>
52#elif defined HAVE_SYS_SOCKET_H
53# include <sys/socket.h>
54#endif
55
56#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
57# define NO_SAFE_RENAME
58#endif
59
60#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
61# define USE_SETVBUF
62#endif
63
64#ifdef __QNXNTO__
65#include <unix.h>
66#endif
67
68#include <sys/types.h>
69#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
70#include <sys/ioctl.h>
71#endif
72#if defined(HAVE_FCNTL_H) || defined(_WIN32)
73#include <fcntl.h>
74#elif defined(HAVE_SYS_FCNTL_H)
75#include <sys/fcntl.h>
76#endif
77
78#ifdef HAVE_SYS_TIME_H
79# include <sys/time.h>
80#endif
81
82#include <sys/stat.h>
83
84#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
85# include <sys/param.h>
86#endif
87
88#if !defined NOFILE
89# define NOFILE 64
90#endif
91
92#ifdef HAVE_UNISTD_H
93#include <unistd.h>
94#endif
95
96#ifdef HAVE_SYSCALL_H
97#include <syscall.h>
98#elif defined HAVE_SYS_SYSCALL_H
99#include <sys/syscall.h>
100#endif
101
102#ifdef HAVE_SYS_UIO_H
103#include <sys/uio.h>
104#endif
105
106#ifdef HAVE_SYS_WAIT_H
107# include <sys/wait.h> /* for WNOHANG on BSD */
108#endif
109
110#ifdef HAVE_COPYFILE_H
111# include <copyfile.h>
112#endif
113
115#include "ccan/list/list.h"
116#include "dln.h"
117#include "encindex.h"
118#include "id.h"
119#include "internal.h"
120#include "internal/encoding.h"
121#include "internal/error.h"
122#include "internal/inits.h"
123#include "internal/io.h"
124#include "internal/numeric.h"
125#include "internal/object.h"
126#include "internal/process.h"
127#include "internal/thread.h"
128#include "internal/transcode.h"
129#include "internal/variable.h"
130#include "ruby/io.h"
131#include "ruby/io/buffer.h"
132#include "ruby/missing.h"
133#include "ruby/thread.h"
134#include "ruby/util.h"
135#include "ruby_atomic.h"
136#include "ruby/ractor.h"
137
138#if !USE_POLL
139# include "vm_core.h"
140#endif
141
142#include "builtin.h"
143
144#ifndef O_ACCMODE
145#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
146#endif
147
148#ifndef PIPE_BUF
149# ifdef _POSIX_PIPE_BUF
150# define PIPE_BUF _POSIX_PIPE_BUF
151# else
152# define PIPE_BUF 512 /* is this ok? */
153# endif
154#endif
155
156#ifndef EWOULDBLOCK
157# define EWOULDBLOCK EAGAIN
158#endif
159
160#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
161/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
162off_t __syscall(quad_t number, ...);
163#endif
164
165#define IO_RBUF_CAPA_MIN 8192
166#define IO_CBUF_CAPA_MIN (128*1024)
167#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
168#define IO_WBUF_CAPA_MIN 8192
169
170#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
171
172/* define system APIs */
173#ifdef _WIN32
174#undef open
175#define open rb_w32_uopen
176#undef rename
177#define rename(f, t) rb_w32_urename((f), (t))
178#endif
179
186
187static VALUE rb_eEAGAINWaitReadable;
188static VALUE rb_eEAGAINWaitWritable;
189static VALUE rb_eEWOULDBLOCKWaitReadable;
190static VALUE rb_eEWOULDBLOCKWaitWritable;
191static VALUE rb_eEINPROGRESSWaitWritable;
192static VALUE rb_eEINPROGRESSWaitReadable;
193
195static VALUE orig_stdout, orig_stderr;
196
197VALUE rb_output_fs;
198VALUE rb_rs;
201
202static VALUE argf;
203
204static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
205static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
206static VALUE sym_textmode, sym_binmode, sym_autoclose;
207static VALUE sym_SET, sym_CUR, sym_END;
208static VALUE sym_wait_readable, sym_wait_writable;
209#ifdef SEEK_DATA
210static VALUE sym_DATA;
211#endif
212#ifdef SEEK_HOLE
213static VALUE sym_HOLE;
214#endif
215
216static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
217
218struct argf {
219 VALUE filename, current_file;
220 long last_lineno; /* $. */
221 long lineno;
222 VALUE argv;
223 VALUE inplace;
224 struct rb_io_enc_t encs;
225 int8_t init_p, next_p, binmode;
226};
227
228static rb_atomic_t max_file_descriptor = NOFILE;
229void
231{
232 rb_atomic_t afd = (rb_atomic_t)fd;
233 rb_atomic_t max_fd = max_file_descriptor;
234 int err;
235
236 if (fd < 0 || afd <= max_fd)
237 return;
238
239#if defined(HAVE_FCNTL) && defined(F_GETFL)
240 err = fcntl(fd, F_GETFL) == -1;
241#else
242 {
243 struct stat buf;
244 err = fstat(fd, &buf) != 0;
245 }
246#endif
247 if (err && errno == EBADF) {
248 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
249 }
250
251 while (max_fd < afd) {
252 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
253 }
254}
255
256void
257rb_maygvl_fd_fix_cloexec(int fd)
258{
259 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
260#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
261 int flags, flags2, ret;
262 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
263 if (flags == -1) {
264 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
265 }
266 if (fd <= 2)
267 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
268 else
269 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
270 if (flags != flags2) {
271 ret = fcntl(fd, F_SETFD, flags2);
272 if (ret != 0) {
273 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
274 }
275 }
276#endif
277}
278
279void
281{
282 rb_maygvl_fd_fix_cloexec(fd);
284}
285
286/* this is only called once */
287static int
288rb_fix_detect_o_cloexec(int fd)
289{
290#if defined(O_CLOEXEC) && defined(F_GETFD)
291 int flags = fcntl(fd, F_GETFD);
292
293 if (flags == -1)
294 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
295
296 if (flags & FD_CLOEXEC)
297 return 1;
298#endif /* fall through if O_CLOEXEC does not work: */
299 rb_maygvl_fd_fix_cloexec(fd);
300 return 0;
301}
302
303static inline bool
304io_again_p(int e)
305{
306 return (e == EWOULDBLOCK) || (e == EAGAIN);
307}
308
309int
310rb_cloexec_open(const char *pathname, int flags, mode_t mode)
311{
312 int ret;
313 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
314
315 static const int retry_interval = 0;
316 static const int retry_max_count = 10000;
317
318 int retry_count = 0;
319
320#ifdef O_CLOEXEC
321 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
322 flags |= O_CLOEXEC;
323#elif defined O_NOINHERIT
324 flags |= O_NOINHERIT;
325#endif
326
327 while ((ret = open(pathname, flags, mode)) == -1) {
328 int e = errno;
329 if (!io_again_p(e)) break;
330 if (retry_count++ >= retry_max_count) break;
331
332 sleep(retry_interval);
333 }
334
335 if (ret < 0) return ret;
336 if (ret <= 2 || o_cloexec_state == 0) {
337 rb_maygvl_fd_fix_cloexec(ret);
338 }
339 else if (o_cloexec_state > 0) {
340 return ret;
341 }
342 else {
343 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
344 }
345 return ret;
346}
347
348int
350{
351 /* Don't allocate standard file descriptors: 0, 1, 2 */
352 return rb_cloexec_fcntl_dupfd(oldfd, 3);
353}
354
355int
356rb_cloexec_dup2(int oldfd, int newfd)
357{
358 int ret;
359
360 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
361 * rb_cloexec_dup2 succeeds as dup2. */
362 if (oldfd == newfd) {
363 ret = newfd;
364 }
365 else {
366#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
367 static int try_dup3 = 1;
368 if (2 < newfd && try_dup3) {
369 ret = dup3(oldfd, newfd, O_CLOEXEC);
370 if (ret != -1)
371 return ret;
372 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
373 if (errno == ENOSYS) {
374 try_dup3 = 0;
375 ret = dup2(oldfd, newfd);
376 }
377 }
378 else {
379 ret = dup2(oldfd, newfd);
380 }
381#else
382 ret = dup2(oldfd, newfd);
383#endif
384 if (ret < 0) return ret;
385 }
386 rb_maygvl_fd_fix_cloexec(ret);
387 return ret;
388}
389
390static int
391rb_fd_set_nonblock(int fd)
392{
393#ifdef _WIN32
394 return rb_w32_set_nonblock(fd);
395#elif defined(F_GETFL)
396 int oflags = fcntl(fd, F_GETFL);
397
398 if (oflags == -1)
399 return -1;
400 if (oflags & O_NONBLOCK)
401 return 0;
402 oflags |= O_NONBLOCK;
403 return fcntl(fd, F_SETFL, oflags);
404#endif
405 return 0;
406}
407
408int
409rb_cloexec_pipe(int descriptors[2])
410{
411#ifdef HAVE_PIPE2
412 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
413#else
414 int result = pipe(descriptors);
415#endif
416
417 if (result < 0)
418 return result;
419
420#ifdef __CYGWIN__
421 if (result == 0 && descriptors[1] == -1) {
422 close(descriptors[0]);
423 descriptors[0] = -1;
424 errno = ENFILE;
425 return -1;
426 }
427#endif
428
429#ifndef HAVE_PIPE2
430 rb_maygvl_fd_fix_cloexec(descriptors[0]);
431 rb_maygvl_fd_fix_cloexec(descriptors[1]);
432
433#ifndef _WIN32
434 rb_fd_set_nonblock(descriptors[0]);
435 rb_fd_set_nonblock(descriptors[1]);
436#endif
437#endif
438
439 return result;
440}
441
442int
443rb_cloexec_fcntl_dupfd(int fd, int minfd)
444{
445 int ret;
446
447#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
448 static int try_dupfd_cloexec = 1;
449 if (try_dupfd_cloexec) {
450 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
451 if (ret != -1) {
452 if (ret <= 2)
453 rb_maygvl_fd_fix_cloexec(ret);
454 return ret;
455 }
456 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
457 if (errno == EINVAL) {
458 ret = fcntl(fd, F_DUPFD, minfd);
459 if (ret != -1) {
460 try_dupfd_cloexec = 0;
461 }
462 }
463 }
464 else {
465 ret = fcntl(fd, F_DUPFD, minfd);
466 }
467#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
468 ret = fcntl(fd, F_DUPFD, minfd);
469#else
470 ret = dup(fd);
471 if (ret >= 0 && ret < minfd) {
472 const int prev_fd = ret;
473 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
474 close(prev_fd);
475 }
476 return ret;
477#endif
478 if (ret < 0) return ret;
479 rb_maygvl_fd_fix_cloexec(ret);
480 return ret;
481}
482
483#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
484#define ARGF argf_of(argf)
485
486#define GetWriteIO(io) rb_io_get_write_io(io)
487
488#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
489#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
490#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
491#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
492
493#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
494#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
495#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
496
497#if defined(_WIN32)
498#define WAIT_FD_IN_WIN32(fptr) \
499 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
500#else
501#define WAIT_FD_IN_WIN32(fptr)
502#endif
503
504#define READ_CHECK(fptr) do {\
505 if (!READ_DATA_PENDING(fptr)) {\
506 WAIT_FD_IN_WIN32(fptr);\
507 rb_io_check_closed(fptr);\
508 }\
509} while(0)
510
511#ifndef S_ISSOCK
512# ifdef _S_ISSOCK
513# define S_ISSOCK(m) _S_ISSOCK(m)
514# else
515# ifdef _S_IFSOCK
516# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
517# else
518# ifdef S_IFSOCK
519# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
520# endif
521# endif
522# endif
523#endif
524
525static int io_fflush(rb_io_t *);
526static rb_io_t *flush_before_seek(rb_io_t *fptr);
527
528#define FMODE_PREP (1<<16)
529#define FMODE_SIGNAL_ON_EPIPE (1<<17)
530
531#define fptr_signal_on_epipe(fptr) \
532 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
533
534#define fptr_set_signal_on_epipe(fptr, flag) \
535 ((flag) ? \
536 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
537 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
538
539extern ID ruby_static_id_signo;
540
541NORETURN(static void raise_on_write(rb_io_t *fptr, int e, VALUE errinfo));
542static void
543raise_on_write(rb_io_t *fptr, int e, VALUE errinfo)
544{
545#if defined EPIPE
546 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
547 const VALUE sig =
548# if defined SIGPIPE
549 INT2FIX(SIGPIPE) - INT2FIX(0) +
550# endif
551 INT2FIX(0);
552 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
553 }
554#endif
555 rb_exc_raise(errinfo);
556}
557
558#define rb_sys_fail_on_write(fptr) \
559 do { \
560 int e = errno; \
561 raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
562 } while (0)
563
564#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
565#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
566#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
567# define RUBY_CRLF_ENVIRONMENT 1
568#else
569# define RUBY_CRLF_ENVIRONMENT 0
570#endif
571
572#if RUBY_CRLF_ENVIRONMENT
573/* Windows */
574# define DEFAULT_TEXTMODE FMODE_TEXTMODE
575# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
576/*
577 * CRLF newline is set as default newline decorator.
578 * If only CRLF newline conversion is needed, we use binary IO process
579 * with OS's text mode for IO performance improvement.
580 * If encoding conversion is needed or a user sets text mode, we use encoding
581 * conversion IO process and universal newline decorator by default.
582 */
583#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
584#define WRITECONV_MASK ( \
585 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
586 ECONV_STATEFUL_DECORATOR_MASK|\
587 0)
588#define NEED_WRITECONV(fptr) ( \
589 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
590 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
591 0)
592#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
593
594#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
595 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
596 if (((fptr)->mode & FMODE_READABLE) &&\
597 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
598 setmode((fptr)->fd, O_BINARY);\
599 }\
600 else {\
601 setmode((fptr)->fd, O_TEXT);\
602 }\
603 }\
604} while(0)
605
606#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
607 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
608 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
609 }\
610} while(0)
611
612/*
613 * IO unread with taking care of removed '\r' in text mode.
614 */
615static void
616io_unread(rb_io_t *fptr)
617{
618 rb_off_t r, pos;
619 ssize_t read_size;
620 long i;
621 long newlines = 0;
622 long extra_max;
623 char *p;
624 char *buf;
625
626 rb_io_check_closed(fptr);
627 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
628 return;
629 }
630
631 errno = 0;
632 if (!rb_w32_fd_is_text(fptr->fd)) {
633 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
634 if (r < 0 && errno) {
635 if (errno == ESPIPE)
636 fptr->mode |= FMODE_DUPLEX;
637 return;
638 }
639
640 fptr->rbuf.off = 0;
641 fptr->rbuf.len = 0;
642 return;
643 }
644
645 pos = lseek(fptr->fd, 0, SEEK_CUR);
646 if (pos < 0 && errno) {
647 if (errno == ESPIPE)
648 fptr->mode |= FMODE_DUPLEX;
649 return;
650 }
651
652 /* add extra offset for removed '\r' in rbuf */
653 extra_max = (long)(pos - fptr->rbuf.len);
654 p = fptr->rbuf.ptr + fptr->rbuf.off;
655
656 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
657 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
658 newlines++;
659 }
660
661 for (i = 0; i < fptr->rbuf.len; i++) {
662 if (*p == '\n') newlines++;
663 if (extra_max == newlines) break;
664 p++;
665 }
666
667 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
668 while (newlines >= 0) {
669 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
670 if (newlines == 0) break;
671 if (r < 0) {
672 newlines--;
673 continue;
674 }
675 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
676 if (read_size < 0) {
677 int e = errno;
678 free(buf);
679 rb_syserr_fail_path(e, fptr->pathv);
680 }
681 if (read_size == fptr->rbuf.len) {
682 lseek(fptr->fd, r, SEEK_SET);
683 break;
684 }
685 else {
686 newlines--;
687 }
688 }
689 free(buf);
690 fptr->rbuf.off = 0;
691 fptr->rbuf.len = 0;
692 return;
693}
694
695/*
696 * We use io_seek to back cursor position when changing mode from text to binary,
697 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
698 * conversion for working properly with mode change.
699 *
700 * Return previous translation mode.
701 */
702static inline int
703set_binary_mode_with_seek_cur(rb_io_t *fptr)
704{
705 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
706
707 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
708 return setmode(fptr->fd, O_BINARY);
709 }
710 flush_before_seek(fptr);
711 return setmode(fptr->fd, O_BINARY);
712}
713#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
714
715#else
716/* Unix */
717# define DEFAULT_TEXTMODE 0
718#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
719#define NEED_WRITECONV(fptr) ( \
720 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
721 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
722 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
723 0)
724#define SET_BINARY_MODE(fptr) (void)(fptr)
725#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
726#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
728#endif
729
730#if !defined HAVE_SHUTDOWN && !defined shutdown
731#define shutdown(a,b) 0
732#endif
733
734#if defined(_WIN32)
735#define is_socket(fd, path) rb_w32_is_socket(fd)
736#elif !defined(S_ISSOCK)
737#define is_socket(fd, path) 0
738#else
739static int
740is_socket(int fd, VALUE path)
741{
742 struct stat sbuf;
743 if (fstat(fd, &sbuf) < 0)
744 rb_sys_fail_path(path);
745 return S_ISSOCK(sbuf.st_mode);
746}
747#endif
748
749static const char closed_stream[] = "closed stream";
750
751static void
752io_fd_check_closed(int fd)
753{
754 if (fd < 0) {
755 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
756 rb_raise(rb_eIOError, closed_stream);
757 }
758}
759
760void
761rb_eof_error(void)
762{
763 rb_raise(rb_eEOFError, "end of file reached");
764}
765
766VALUE
768{
769 rb_check_frozen(io);
770 return io;
771}
772
773void
775{
776 if (!fptr) {
777 rb_raise(rb_eIOError, "uninitialized stream");
778 }
779}
780
781void
783{
785 io_fd_check_closed(fptr->fd);
786}
787
788static rb_io_t *
789rb_io_get_fptr(VALUE io)
790{
791 rb_io_t *fptr = RFILE(io)->fptr;
793 return fptr;
794}
795
796VALUE
798{
799 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
800}
801
802VALUE
804{
805 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
806}
807
808VALUE
810{
811 VALUE write_io;
812 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
813 if (write_io) {
814 return write_io;
815 }
816 return io;
817}
818
819VALUE
821{
822 VALUE write_io;
823 rb_io_t *fptr = rb_io_get_fptr(io);
824 if (!RTEST(w)) {
825 w = 0;
826 }
827 else {
828 GetWriteIO(w);
829 }
830 write_io = fptr->tied_io_for_writing;
831 fptr->tied_io_for_writing = w;
832 return write_io ? write_io : Qnil;
833}
834
835/*
836 * call-seq:
837 * timeout -> duration or nil
838 *
839 * Get the internal timeout duration or nil if it was not set.
840 *
841 */
842VALUE
844{
845 rb_io_t *fptr = rb_io_get_fptr(self);
846
847 return fptr->timeout;
848}
849
850/*
851 * call-seq:
852 * timeout = duration -> duration
853 * timeout = nil -> nil
854 *
855 * Set the internal timeout to the specified duration or nil. The timeout
856 * applies to all blocking operations where possible.
857 *
858 * This affects the following methods (but is not limited to): #gets, #puts,
859 * #read, #write, #wait_readable and #wait_writable. This also affects
860 * blocking socket operations like Socket#accept and Socket#connect.
861 *
862 * Some operations like File#open and IO#close are not affected by the
863 * timeout. A timeout during a write operation may leave the IO in an
864 * inconsistent state, e.g. data was partially written. Generally speaking, a
865 * timeout is a last ditch effort to prevent an application from hanging on
866 * slow I/O operations, such as those that occur during a slowloris attack.
867 */
868VALUE
870{
871 // Validate it:
872 if (RTEST(timeout)) {
873 rb_time_interval(timeout);
874 }
875
876 rb_io_t *fptr = rb_io_get_fptr(self);
877
878 fptr->timeout = timeout;
879
880 return self;
881}
882
883/*
884 * call-seq:
885 * IO.try_convert(object) -> new_io or nil
886 *
887 * Attempts to convert +object+ into an \IO object via method +to_io+;
888 * returns the new \IO object if successful, or +nil+ otherwise:
889 *
890 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
891 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
892 * IO.try_convert('STDOUT') # => nil
893 *
894 */
895static VALUE
896rb_io_s_try_convert(VALUE dummy, VALUE io)
897{
898 return rb_io_check_io(io);
899}
900
901#if !RUBY_CRLF_ENVIRONMENT
902static void
903io_unread(rb_io_t *fptr)
904{
905 rb_off_t r;
906 rb_io_check_closed(fptr);
907 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
908 return;
909 /* xxx: target position may be negative if buffer is filled by ungetc */
910 errno = 0;
911 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
912 if (r < 0 && errno) {
913 if (errno == ESPIPE)
914 fptr->mode |= FMODE_DUPLEX;
915 return;
916 }
917 fptr->rbuf.off = 0;
918 fptr->rbuf.len = 0;
919 return;
920}
921#endif
922
923static rb_encoding *io_input_encoding(rb_io_t *fptr);
924
925static void
926io_ungetbyte(VALUE str, rb_io_t *fptr)
927{
928 long len = RSTRING_LEN(str);
929
930 if (fptr->rbuf.ptr == NULL) {
931 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
932 fptr->rbuf.off = 0;
933 fptr->rbuf.len = 0;
934#if SIZEOF_LONG > SIZEOF_INT
935 if (len > INT_MAX)
936 rb_raise(rb_eIOError, "ungetbyte failed");
937#endif
938 if (len > min_capa)
939 fptr->rbuf.capa = (int)len;
940 else
941 fptr->rbuf.capa = min_capa;
942 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
943 }
944 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
945 rb_raise(rb_eIOError, "ungetbyte failed");
946 }
947 if (fptr->rbuf.off < len) {
948 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
949 fptr->rbuf.ptr+fptr->rbuf.off,
950 char, fptr->rbuf.len);
951 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
952 }
953 fptr->rbuf.off-=(int)len;
954 fptr->rbuf.len+=(int)len;
955 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
956}
957
958static rb_io_t *
959flush_before_seek(rb_io_t *fptr)
960{
961 if (io_fflush(fptr) < 0)
962 rb_sys_fail_on_write(fptr);
963 io_unread(fptr);
964 errno = 0;
965 return fptr;
966}
967
968#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
969#define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
970
971#ifndef SEEK_CUR
972# define SEEK_SET 0
973# define SEEK_CUR 1
974# define SEEK_END 2
975#endif
976
977void
979{
980 rb_io_check_closed(fptr);
981 if (!(fptr->mode & FMODE_READABLE)) {
982 rb_raise(rb_eIOError, "not opened for reading");
983 }
984 if (fptr->wbuf.len) {
985 if (io_fflush(fptr) < 0)
986 rb_sys_fail_on_write(fptr);
987 }
988 if (fptr->tied_io_for_writing) {
989 rb_io_t *wfptr;
990 GetOpenFile(fptr->tied_io_for_writing, wfptr);
991 if (io_fflush(wfptr) < 0)
992 rb_sys_fail_on_write(wfptr);
993 }
994}
995
996void
998{
1000 if (READ_CHAR_PENDING(fptr)) {
1001 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1002 }
1003}
1004
1005void
1010
1011static rb_encoding*
1012io_read_encoding(rb_io_t *fptr)
1013{
1014 if (fptr->encs.enc) {
1015 return fptr->encs.enc;
1016 }
1017 return rb_default_external_encoding();
1018}
1019
1020static rb_encoding*
1021io_input_encoding(rb_io_t *fptr)
1022{
1023 if (fptr->encs.enc2) {
1024 return fptr->encs.enc2;
1025 }
1026 return io_read_encoding(fptr);
1027}
1028
1029void
1031{
1032 rb_io_check_closed(fptr);
1033 if (!(fptr->mode & FMODE_WRITABLE)) {
1034 rb_raise(rb_eIOError, "not opened for writing");
1035 }
1036 if (fptr->rbuf.len) {
1037 io_unread(fptr);
1038 }
1039}
1040
1041int
1042rb_io_read_pending(rb_io_t *fptr)
1043{
1044 /* This function is used for bytes and chars. Confusing. */
1045 if (READ_CHAR_PENDING(fptr))
1046 return 1; /* should raise? */
1047 return READ_DATA_PENDING(fptr);
1048}
1049
1050void
1052{
1053 if (!READ_DATA_PENDING(fptr)) {
1054 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1055 }
1056 return;
1057}
1058
1059int
1060rb_gc_for_fd(int err)
1061{
1062 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1063 rb_gc();
1064 return 1;
1065 }
1066 return 0;
1067}
1068
1069static int
1070ruby_dup(int orig)
1071{
1072 int fd;
1073
1074 fd = rb_cloexec_dup(orig);
1075 if (fd < 0) {
1076 int e = errno;
1077 if (rb_gc_for_fd(e)) {
1078 fd = rb_cloexec_dup(orig);
1079 }
1080 if (fd < 0) {
1081 rb_syserr_fail(e, 0);
1082 }
1083 }
1084 rb_update_max_fd(fd);
1085 return fd;
1086}
1087
1088static VALUE
1089io_alloc(VALUE klass)
1090{
1091 NEWOBJ_OF(io, struct RFile, klass, T_FILE);
1092
1093 io->fptr = 0;
1094
1095 return (VALUE)io;
1096}
1097
1098#ifndef S_ISREG
1099# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1100#endif
1101
1103 VALUE th;
1104 rb_io_t *fptr;
1105 int nonblock;
1106 int fd;
1107
1108 void *buf;
1109 size_t capa;
1110 struct timeval *timeout;
1111};
1112
1114 VALUE th;
1115 rb_io_t *fptr;
1116 int nonblock;
1117 int fd;
1118
1119 const void *buf;
1120 size_t capa;
1121 struct timeval *timeout;
1122};
1123
1124#ifdef HAVE_WRITEV
1125struct io_internal_writev_struct {
1126 VALUE th;
1127 rb_io_t *fptr;
1128 int nonblock;
1129 int fd;
1130
1131 int iovcnt;
1132 const struct iovec *iov;
1133 struct timeval *timeout;
1134};
1135#endif
1136
1137static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1138
1144static inline int
1145io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1146{
1147 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1148
1149 if (ready > 0) {
1150 return ready;
1151 } else if (ready == 0) {
1152 errno = ETIMEDOUT;
1153 return -1;
1154 }
1155
1156 errno = error;
1157 return -1;
1158}
1159
1160static VALUE
1161internal_read_func(void *ptr)
1162{
1163 struct io_internal_read_struct *iis = ptr;
1164 ssize_t result;
1165
1166 if (iis->timeout && !iis->nonblock) {
1167 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1168 return -1;
1169 }
1170 }
1171
1172 retry:
1173 result = read(iis->fd, iis->buf, iis->capa);
1174
1175 if (result < 0 && !iis->nonblock) {
1176 if (io_again_p(errno)) {
1177 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1178 return -1;
1179 } else {
1180 goto retry;
1181 }
1182 }
1183 }
1184
1185 return result;
1186}
1187
1188#if defined __APPLE__
1189# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1190#else
1191# define do_write_retry(code) result = code
1192#endif
1193
1194static VALUE
1195internal_write_func(void *ptr)
1196{
1197 struct io_internal_write_struct *iis = ptr;
1198 ssize_t result;
1199
1200 if (iis->timeout && !iis->nonblock) {
1201 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1202 return -1;
1203 }
1204 }
1205
1206 retry:
1207 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1208
1209 if (result < 0 && !iis->nonblock) {
1210 int e = errno;
1211 if (io_again_p(e)) {
1212 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1213 return -1;
1214 } else {
1215 goto retry;
1216 }
1217 }
1218 }
1219
1220 return result;
1221}
1222
1223#ifdef HAVE_WRITEV
1224static VALUE
1225internal_writev_func(void *ptr)
1226{
1227 struct io_internal_writev_struct *iis = ptr;
1228 ssize_t result;
1229
1230 if (iis->timeout && !iis->nonblock) {
1231 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1232 return -1;
1233 }
1234 }
1235
1236 retry:
1237 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1238
1239 if (result < 0 && !iis->nonblock) {
1240 if (io_again_p(errno)) {
1241 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1242 return -1;
1243 } else {
1244 goto retry;
1245 }
1246 }
1247 }
1248
1249 return result;
1250}
1251#endif
1252
1253static ssize_t
1254rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1255{
1256 VALUE scheduler = rb_fiber_scheduler_current();
1257 if (scheduler != Qnil) {
1258 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1259
1260 if (!UNDEF_P(result)) {
1262 }
1263 }
1264
1265 struct io_internal_read_struct iis = {
1266 .th = rb_thread_current(),
1267 .fptr = fptr,
1268 .nonblock = 0,
1269 .fd = fptr->fd,
1270
1271 .buf = buf,
1272 .capa = count,
1273 .timeout = NULL,
1274 };
1275
1276 struct timeval timeout_storage;
1277
1278 if (fptr->timeout != Qnil) {
1279 timeout_storage = rb_time_interval(fptr->timeout);
1280 iis.timeout = &timeout_storage;
1281 }
1282
1283 return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fptr->fd);
1284}
1285
1286static ssize_t
1287rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1288{
1289 VALUE scheduler = rb_fiber_scheduler_current();
1290 if (scheduler != Qnil) {
1291 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1292
1293 if (!UNDEF_P(result)) {
1295 }
1296 }
1297
1298 struct io_internal_write_struct iis = {
1299 .th = rb_thread_current(),
1300 .fptr = fptr,
1301 .nonblock = 0,
1302 .fd = fptr->fd,
1303
1304 .buf = buf,
1305 .capa = count,
1306 .timeout = NULL
1307 };
1308
1309 struct timeval timeout_storage;
1310
1311 if (fptr->timeout != Qnil) {
1312 timeout_storage = rb_time_interval(fptr->timeout);
1313 iis.timeout = &timeout_storage;
1314 }
1315
1316 return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fptr->fd);
1317}
1318
1319#ifdef HAVE_WRITEV
1320static ssize_t
1321rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1322{
1323 if (!iovcnt) return 0;
1324
1325 VALUE scheduler = rb_fiber_scheduler_current();
1326 if (scheduler != Qnil) {
1327 // This path assumes at least one `iov`:
1328 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1329
1330 if (!UNDEF_P(result)) {
1332 }
1333 }
1334
1335 struct io_internal_writev_struct iis = {
1336 .th = rb_thread_current(),
1337 .fptr = fptr,
1338 .nonblock = 0,
1339 .fd = fptr->fd,
1340
1341 .iov = iov,
1342 .iovcnt = iovcnt,
1343 .timeout = NULL
1344 };
1345
1346 struct timeval timeout_storage;
1347
1348 if (fptr->timeout != Qnil) {
1349 timeout_storage = rb_time_interval(fptr->timeout);
1350 iis.timeout = &timeout_storage;
1351 }
1352
1353 return (ssize_t)rb_thread_io_blocking_region(internal_writev_func, &iis, fptr->fd);
1354}
1355#endif
1356
1357static VALUE
1358io_flush_buffer_sync(void *arg)
1359{
1360 rb_io_t *fptr = arg;
1361 long l = fptr->wbuf.len;
1362 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1363
1364 if (fptr->wbuf.len <= r) {
1365 fptr->wbuf.off = 0;
1366 fptr->wbuf.len = 0;
1367 return 0;
1368 }
1369
1370 if (0 <= r) {
1371 fptr->wbuf.off += (int)r;
1372 fptr->wbuf.len -= (int)r;
1373 errno = EAGAIN;
1374 }
1375
1376 return (VALUE)-1;
1377}
1378
1379static VALUE
1380io_flush_buffer_async(VALUE arg)
1381{
1382 rb_io_t *fptr = (rb_io_t *)arg;
1383 return rb_thread_io_blocking_region(io_flush_buffer_sync, fptr, fptr->fd);
1384}
1385
1386static inline int
1387io_flush_buffer(rb_io_t *fptr)
1388{
1389 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1390 return (int)io_flush_buffer_async((VALUE)fptr);
1391 }
1392 else {
1393 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1394 }
1395}
1396
1397static int
1398io_fflush(rb_io_t *fptr)
1399{
1400 rb_io_check_closed(fptr);
1401
1402 if (fptr->wbuf.len == 0)
1403 return 0;
1404
1405 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1406 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1407 return -1;
1408
1409 rb_io_check_closed(fptr);
1410 }
1411
1412 return 0;
1413}
1414
1415VALUE
1416rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1417{
1418 VALUE scheduler = rb_fiber_scheduler_current();
1419
1420 if (scheduler != Qnil) {
1421 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1422 }
1423
1424 rb_io_t * fptr = NULL;
1425 RB_IO_POINTER(io, fptr);
1426
1427 struct timeval tv_storage;
1428 struct timeval *tv = NULL;
1429
1430 if (NIL_OR_UNDEF_P(timeout)) {
1431 timeout = fptr->timeout;
1432 }
1433
1434 if (timeout != Qnil) {
1435 tv_storage = rb_time_interval(timeout);
1436 tv = &tv_storage;
1437 }
1438
1439 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1440
1441 if (ready < 0) {
1442 rb_sys_fail(0);
1443 }
1444
1445 // Not sure if this is necessary:
1446 rb_io_check_closed(fptr);
1447
1448 if (ready) {
1449 return RB_INT2NUM(ready);
1450 }
1451 else {
1452 return Qfalse;
1453 }
1454}
1455
1456static VALUE
1457io_from_fd(int fd)
1458{
1459 return prep_io(fd, FMODE_PREP, rb_cIO, NULL);
1460}
1461
1462static int
1463io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1464{
1465 VALUE scheduler = rb_fiber_scheduler_current();
1466
1467 if (scheduler != Qnil) {
1468 return RTEST(
1469 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1470 );
1471 }
1472
1473 return rb_thread_wait_for_single_fd(fd, events, timeout);
1474}
1475
1476int
1478{
1479 io_fd_check_closed(f);
1480
1481 VALUE scheduler = rb_fiber_scheduler_current();
1482
1483 switch (errno) {
1484 case EINTR:
1485#if defined(ERESTART)
1486 case ERESTART:
1487#endif
1489 return TRUE;
1490
1491 case EAGAIN:
1492#if EWOULDBLOCK != EAGAIN
1493 case EWOULDBLOCK:
1494#endif
1495 if (scheduler != Qnil) {
1496 return RTEST(
1497 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1498 );
1499 }
1500 else {
1501 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1502 }
1503 return TRUE;
1504
1505 default:
1506 return FALSE;
1507 }
1508}
1509
1510int
1512{
1513 io_fd_check_closed(f);
1514
1515 VALUE scheduler = rb_fiber_scheduler_current();
1516
1517 switch (errno) {
1518 case EINTR:
1519#if defined(ERESTART)
1520 case ERESTART:
1521#endif
1522 /*
1523 * In old Linux, several special files under /proc and /sys don't handle
1524 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1525 * Otherwise, we face nasty hang up. Sigh.
1526 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1527 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1528 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1529 * Then rb_thread_check_ints() is enough.
1530 */
1532 return TRUE;
1533
1534 case EAGAIN:
1535#if EWOULDBLOCK != EAGAIN
1536 case EWOULDBLOCK:
1537#endif
1538 if (scheduler != Qnil) {
1539 return RTEST(
1540 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1541 );
1542 }
1543 else {
1544 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1545 }
1546 return TRUE;
1547
1548 default:
1549 return FALSE;
1550 }
1551}
1552
1553int
1554rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1555{
1556 return io_wait_for_single_fd(fd, events, timeout);
1557}
1558
1559int
1561{
1562 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1563}
1564
1565int
1567{
1568 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1569}
1570
1571VALUE
1572rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1573{
1574 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1575 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1576 // instead relies on `read(-1) -> -1` which causes this code path. We then
1577 // check here whether the IO was in fact closed. Probably it's better to
1578 // check that `fptr->fd != -1` before using it in syscall.
1579 rb_io_check_closed(RFILE(io)->fptr);
1580
1581 switch (error) {
1582 // In old Linux, several special files under /proc and /sys don't handle
1583 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1584 // Otherwise, we face nasty hang up. Sigh.
1585 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1586 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1587 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1588 // Then rb_thread_check_ints() is enough.
1589 case EINTR:
1590#if defined(ERESTART)
1591 case ERESTART:
1592#endif
1593 // We might have pending interrupts since the previous syscall was interrupted:
1595
1596 // The operation was interrupted, so retry it immediately:
1597 return events;
1598
1599 case EAGAIN:
1600#if EWOULDBLOCK != EAGAIN
1601 case EWOULDBLOCK:
1602#endif
1603 // The operation would block, so wait for the specified events:
1604 return rb_io_wait(io, events, timeout);
1605
1606 default:
1607 // Non-specific error, no event is ready:
1608 return Qfalse;
1609 }
1610}
1611
1612int
1614{
1615 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1616
1617 if (RTEST(result)) {
1618 return RB_NUM2INT(result);
1619 }
1620 else {
1621 return 0;
1622 }
1623}
1624
1625int
1627{
1628 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1629
1630 if (RTEST(result)) {
1631 return RB_NUM2INT(result);
1632 }
1633 else {
1634 return 0;
1635 }
1636}
1637
1638static void
1639make_writeconv(rb_io_t *fptr)
1640{
1641 if (!fptr->writeconv_initialized) {
1642 const char *senc, *denc;
1643 rb_encoding *enc;
1644 int ecflags;
1645 VALUE ecopts;
1646
1647 fptr->writeconv_initialized = 1;
1648
1649 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1650 ecopts = fptr->encs.ecopts;
1651
1652 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1653 /* no encoding conversion */
1654 fptr->writeconv_pre_ecflags = 0;
1655 fptr->writeconv_pre_ecopts = Qnil;
1656 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1657 if (!fptr->writeconv)
1658 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1660 }
1661 else {
1662 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1664 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1665 /* single conversion */
1666 fptr->writeconv_pre_ecflags = ecflags;
1667 fptr->writeconv_pre_ecopts = ecopts;
1668 fptr->writeconv = NULL;
1670 }
1671 else {
1672 /* double conversion */
1673 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1674 fptr->writeconv_pre_ecopts = ecopts;
1675 if (senc) {
1676 denc = rb_enc_name(enc);
1677 fptr->writeconv_asciicompat = rb_str_new2(senc);
1678 }
1679 else {
1680 senc = denc = "";
1682 }
1684 ecopts = fptr->encs.ecopts;
1685 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1686 if (!fptr->writeconv)
1687 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1688 }
1689 }
1690 }
1691}
1692
1693/* writing functions */
1695 rb_io_t *fptr;
1696 VALUE str;
1697 const char *ptr;
1698 long length;
1699};
1700
1702 VALUE io;
1703 VALUE str;
1704 int nosync;
1705};
1706
1707#ifdef HAVE_WRITEV
1708static ssize_t
1709io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1710{
1711 if (fptr->wbuf.len) {
1712 struct iovec iov[2];
1713
1714 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1715 iov[0].iov_len = fptr->wbuf.len;
1716 iov[1].iov_base = (void*)ptr;
1717 iov[1].iov_len = length;
1718
1719 ssize_t result = rb_writev_internal(fptr, iov, 2);
1720
1721 if (result < 0)
1722 return result;
1723
1724 if (result >= fptr->wbuf.len) {
1725 // We wrote more than the internal buffer:
1726 result -= fptr->wbuf.len;
1727 fptr->wbuf.off = 0;
1728 fptr->wbuf.len = 0;
1729 }
1730 else {
1731 // We only wrote less data than the internal buffer:
1732 fptr->wbuf.off += (int)result;
1733 fptr->wbuf.len -= (int)result;
1734
1735 result = 0;
1736 }
1737
1738 return result;
1739 }
1740 else {
1741 return rb_io_write_memory(fptr, ptr, length);
1742 }
1743}
1744#else
1745static ssize_t
1746io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1747{
1748 long remaining = length;
1749
1750 if (fptr->wbuf.len) {
1751 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1752 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1753 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1754 fptr->wbuf.off = 0;
1755 }
1756
1757 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1758 fptr->wbuf.len += (int)length;
1759
1760 // We copied the entire incoming data to the internal buffer:
1761 remaining = 0;
1762 }
1763
1764 // Flush the internal buffer:
1765 if (io_fflush(fptr) < 0) {
1766 return -1;
1767 }
1768
1769 // If all the data was buffered, we are done:
1770 if (remaining == 0) {
1771 return length;
1772 }
1773 }
1774
1775 // Otherwise, we should write the data directly:
1776 return rb_io_write_memory(fptr, ptr, length);
1777}
1778#endif
1779
1780static VALUE
1781io_binwrite_string(VALUE arg)
1782{
1783 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1784
1785 const char *ptr = p->ptr;
1786 size_t remaining = p->length;
1787
1788 while (remaining) {
1789 // Write as much as possible:
1790 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1791
1792 if (result == 0) {
1793 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1794 // should try again immediately.
1795 }
1796 else if (result > 0) {
1797 if ((size_t)result == remaining) break;
1798 ptr += result;
1799 remaining -= result;
1800 }
1801 // Wait for it to become writable:
1802 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1803 rb_io_check_closed(p->fptr);
1804 }
1805 else {
1806 // The error was unrelated to waiting for it to become writable, so we fail:
1807 return -1;
1808 }
1809 }
1810
1811 return p->length;
1812}
1813
1814inline static void
1815io_allocate_write_buffer(rb_io_t *fptr, int sync)
1816{
1817 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1818 fptr->wbuf.off = 0;
1819 fptr->wbuf.len = 0;
1820 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1821 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1822 }
1823
1824 if (NIL_P(fptr->write_lock)) {
1825 fptr->write_lock = rb_mutex_new();
1826 rb_mutex_allow_trap(fptr->write_lock, 1);
1827 }
1828}
1829
1830static inline int
1831io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1832{
1833 // If the requested operation was synchronous and the output mode is synchronus or a TTY:
1834 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1835 return 1;
1836
1837 // If the amount of data we want to write exceeds the internal buffer:
1838 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1839 return 1;
1840
1841 // Otherwise, we can append to the internal buffer:
1842 return 0;
1843}
1844
1845static long
1846io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
1847{
1848 if (len <= 0) return len;
1849
1850 // Don't write anything if current thread has a pending interrupt:
1852
1853 io_allocate_write_buffer(fptr, !nosync);
1854
1855 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1856 struct binwrite_arg arg;
1857
1858 arg.fptr = fptr;
1859 arg.str = str;
1860 arg.ptr = ptr;
1861 arg.length = len;
1862
1863 if (!NIL_P(fptr->write_lock)) {
1864 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1865 }
1866 else {
1867 return io_binwrite_string((VALUE)&arg);
1868 }
1869 }
1870 else {
1871 if (fptr->wbuf.off) {
1872 if (fptr->wbuf.len)
1873 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1874 fptr->wbuf.off = 0;
1875 }
1876
1877 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1878 fptr->wbuf.len += (int)len;
1879
1880 return len;
1881 }
1882}
1883
1884# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1885 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1886
1887#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1888 MODE_BTMODE(d, e, f) : \
1889 MODE_BTMODE(a, b, c))
1890
1891static VALUE
1892do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1893{
1894 if (NEED_WRITECONV(fptr)) {
1895 VALUE common_encoding = Qnil;
1896 SET_BINARY_MODE(fptr);
1897
1898 make_writeconv(fptr);
1899
1900 if (fptr->writeconv) {
1901#define fmode (fptr->mode)
1902 if (!NIL_P(fptr->writeconv_asciicompat))
1903 common_encoding = fptr->writeconv_asciicompat;
1904 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1905 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1906 rb_enc_name(rb_enc_get(str)));
1907 }
1908#undef fmode
1909 }
1910 else {
1911 if (fptr->encs.enc2)
1912 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1913 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1914 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1915 }
1916
1917 if (!NIL_P(common_encoding)) {
1918 str = rb_str_encode(str, common_encoding,
1920 *converted = 1;
1921 }
1922
1923 if (fptr->writeconv) {
1925 *converted = 1;
1926 }
1927 }
1928#if RUBY_CRLF_ENVIRONMENT
1929#define fmode (fptr->mode)
1930 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1931 if ((fptr->mode & FMODE_READABLE) &&
1933 setmode(fptr->fd, O_BINARY);
1934 }
1935 else {
1936 setmode(fptr->fd, O_TEXT);
1937 }
1938 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1939 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1940 rb_enc_name(rb_enc_get(str)));
1941 }
1942 }
1943#undef fmode
1944#endif
1945 return str;
1946}
1947
1948static long
1949io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1950{
1951 int converted = 0;
1952 VALUE tmp;
1953 long n, len;
1954 const char *ptr;
1955
1956#ifdef _WIN32
1957 if (fptr->mode & FMODE_TTY) {
1958 long len = rb_w32_write_console(str, fptr->fd);
1959 if (len > 0) return len;
1960 }
1961#endif
1962
1963 str = do_writeconv(str, fptr, &converted);
1964 if (converted)
1965 OBJ_FREEZE(str);
1966
1967 tmp = rb_str_tmp_frozen_acquire(str);
1968 RSTRING_GETMEM(tmp, ptr, len);
1969 n = io_binwrite(tmp, ptr, len, fptr, nosync);
1970 rb_str_tmp_frozen_release(str, tmp);
1971
1972 return n;
1973}
1974
1975ssize_t
1976rb_io_bufwrite(VALUE io, const void *buf, size_t size)
1977{
1978 rb_io_t *fptr;
1979
1980 GetOpenFile(io, fptr);
1982 return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
1983}
1984
1985static VALUE
1986io_write(VALUE io, VALUE str, int nosync)
1987{
1988 rb_io_t *fptr;
1989 long n;
1990 VALUE tmp;
1991
1992 io = GetWriteIO(io);
1993 str = rb_obj_as_string(str);
1994 tmp = rb_io_check_io(io);
1995
1996 if (NIL_P(tmp)) {
1997 /* port is not IO, call write method for it. */
1998 return rb_funcall(io, id_write, 1, str);
1999 }
2000
2001 io = tmp;
2002 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2003
2004 GetOpenFile(io, fptr);
2006
2007 n = io_fwrite(str, fptr, nosync);
2008 if (n < 0L) rb_sys_fail_on_write(fptr);
2009
2010 return LONG2FIX(n);
2011}
2012
2013#ifdef HAVE_WRITEV
2014struct binwritev_arg {
2015 rb_io_t *fptr;
2016 struct iovec *iov;
2017 int iovcnt;
2018 size_t total;
2019};
2020
2021static VALUE
2022io_binwritev_internal(VALUE arg)
2023{
2024 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2025
2026 size_t remaining = p->total;
2027 size_t offset = 0;
2028
2029 rb_io_t *fptr = p->fptr;
2030 struct iovec *iov = p->iov;
2031 int iovcnt = p->iovcnt;
2032
2033 while (remaining) {
2034 long result = rb_writev_internal(fptr, iov, iovcnt);
2035
2036 if (result >= 0) {
2037 offset += result;
2038 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2039 if (offset < (size_t)fptr->wbuf.len) {
2040 fptr->wbuf.off += result;
2041 fptr->wbuf.len -= result;
2042 }
2043 else {
2044 offset -= (size_t)fptr->wbuf.len;
2045 fptr->wbuf.off = 0;
2046 fptr->wbuf.len = 0;
2047 }
2048 }
2049
2050 if (offset == p->total) {
2051 return p->total;
2052 }
2053
2054 while (result >= (ssize_t)iov->iov_len) {
2055 /* iovcnt > 0 */
2056 result -= iov->iov_len;
2057 iov->iov_len = 0;
2058 iov++;
2059
2060 if (!--iovcnt) {
2061 // I don't believe this code path can ever occur.
2062 return offset;
2063 }
2064 }
2065
2066 iov->iov_base = (char *)iov->iov_base + result;
2067 iov->iov_len -= result;
2068 }
2069 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2070 rb_io_check_closed(fptr);
2071 }
2072 else {
2073 return -1;
2074 }
2075 }
2076
2077 return offset;
2078}
2079
2080static long
2081io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2082{
2083 // Don't write anything if current thread has a pending interrupt:
2085
2086 if (iovcnt == 0) return 0;
2087
2088 size_t total = 0;
2089 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2090
2091 io_allocate_write_buffer(fptr, 1);
2092
2093 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2094 // The end of the buffered data:
2095 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2096
2097 if (offset + total <= (size_t)fptr->wbuf.capa) {
2098 for (int i = 1; i < iovcnt; i++) {
2099 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2100 offset += iov[i].iov_len;
2101 }
2102
2103 fptr->wbuf.len += total;
2104
2105 return total;
2106 }
2107 else {
2108 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2109 iov[0].iov_len = fptr->wbuf.len;
2110 }
2111 }
2112 else {
2113 // The first iov is reserved for the internal buffer, and it's empty.
2114 iov++;
2115
2116 if (!--iovcnt) {
2117 // If there are no other io vectors we are done.
2118 return 0;
2119 }
2120 }
2121
2122 struct binwritev_arg arg;
2123 arg.fptr = fptr;
2124 arg.iov = iov;
2125 arg.iovcnt = iovcnt;
2126 arg.total = total;
2127
2128 if (!NIL_P(fptr->write_lock)) {
2129 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2130 }
2131 else {
2132 return io_binwritev_internal((VALUE)&arg);
2133 }
2134}
2135
2136static long
2137io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2138{
2139 int i, converted, iovcnt = argc + 1;
2140 long n;
2141 VALUE v1, v2, str, tmp, *tmp_array;
2142 struct iovec *iov;
2143
2144 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2145 tmp_array = ALLOCV_N(VALUE, v2, argc);
2146
2147 for (i = 0; i < argc; i++) {
2148 str = rb_obj_as_string(argv[i]);
2149 converted = 0;
2150 str = do_writeconv(str, fptr, &converted);
2151
2152 if (converted)
2153 OBJ_FREEZE(str);
2154
2155 tmp = rb_str_tmp_frozen_acquire(str);
2156 tmp_array[i] = tmp;
2157
2158 /* iov[0] is reserved for buffer of fptr */
2159 iov[i+1].iov_base = RSTRING_PTR(tmp);
2160 iov[i+1].iov_len = RSTRING_LEN(tmp);
2161 }
2162
2163 n = io_binwritev(iov, iovcnt, fptr);
2164 if (v1) ALLOCV_END(v1);
2165
2166 for (i = 0; i < argc; i++) {
2167 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2168 }
2169
2170 if (v2) ALLOCV_END(v2);
2171
2172 return n;
2173}
2174
2175static int
2176iovcnt_ok(int iovcnt)
2177{
2178#ifdef IOV_MAX
2179 return iovcnt < IOV_MAX;
2180#else /* GNU/Hurd has writev, but no IOV_MAX */
2181 return 1;
2182#endif
2183}
2184#endif /* HAVE_WRITEV */
2185
2186static VALUE
2187io_writev(int argc, const VALUE *argv, VALUE io)
2188{
2189 rb_io_t *fptr;
2190 long n;
2191 VALUE tmp, total = INT2FIX(0);
2192 int i, cnt = 1;
2193
2194 io = GetWriteIO(io);
2195 tmp = rb_io_check_io(io);
2196
2197 if (NIL_P(tmp)) {
2198 /* port is not IO, call write method for it. */
2199 return rb_funcallv(io, id_write, argc, argv);
2200 }
2201
2202 io = tmp;
2203
2204 GetOpenFile(io, fptr);
2206
2207 for (i = 0; i < argc; i += cnt) {
2208#ifdef HAVE_WRITEV
2209 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2210 n = io_fwritev(cnt, &argv[i], fptr);
2211 }
2212 else
2213#endif
2214 {
2215 cnt = 1;
2216 /* sync at last item */
2217 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2218 }
2219
2220 if (n < 0L)
2221 rb_sys_fail_on_write(fptr);
2222
2223 total = rb_fix_plus(LONG2FIX(n), total);
2224 }
2225
2226 return total;
2227}
2228
2229/*
2230 * call-seq:
2231 * write(*objects) -> integer
2232 *
2233 * Writes each of the given +objects+ to +self+,
2234 * which must be opened for writing
2235 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2236 * returns the total number bytes written;
2237 * each of +objects+ that is not a string is converted via method +to_s+:
2238 *
2239 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2240 * $stdout.write('foo', :bar, 2, "\n") # => 8
2241 *
2242 * Output:
2243 *
2244 * Hello, World!
2245 * foobar2
2246 *
2247 * Related: IO#read.
2248 */
2249
2250static VALUE
2251io_write_m(int argc, VALUE *argv, VALUE io)
2252{
2253 if (argc != 1) {
2254 return io_writev(argc, argv, io);
2255 }
2256 else {
2257 VALUE str = argv[0];
2258 return io_write(io, str, 0);
2259 }
2260}
2261
2262VALUE
2264{
2265 return rb_funcallv(io, id_write, 1, &str);
2266}
2267
2268static VALUE
2269rb_io_writev(VALUE io, int argc, const VALUE *argv)
2270{
2271 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2272 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2273 VALUE klass = CLASS_OF(io);
2274 char sep = FL_TEST(klass, FL_SINGLETON) ? (klass = io, '.') : '#';
2276 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2277 " which accepts just one argument",
2278 klass, sep
2279 );
2280 }
2281
2282 do rb_io_write(io, *argv++); while (--argc);
2283
2284 return Qnil;
2285 }
2286
2287 return rb_funcallv(io, id_write, argc, argv);
2288}
2289
2290/*
2291 * call-seq:
2292 * self << object -> self
2293 *
2294 * Writes the given +object+ to +self+,
2295 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2296 * returns +self+;
2297 * if +object+ is not a string, it is converted via method +to_s+:
2298 *
2299 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2300 * $stdout << 'foo' << :bar << 2 << "\n"
2301 *
2302 * Output:
2303 *
2304 * Hello, World!
2305 * foobar2
2306 *
2307 */
2308
2309
2310VALUE
2312{
2313 rb_io_write(io, str);
2314 return io;
2315}
2316
2317#ifdef HAVE_FSYNC
2318static VALUE
2319nogvl_fsync(void *ptr)
2320{
2321 rb_io_t *fptr = ptr;
2322
2323#ifdef _WIN32
2324 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2325 return 0;
2326#endif
2327 return (VALUE)fsync(fptr->fd);
2328}
2329#endif
2330
2331VALUE
2332rb_io_flush_raw(VALUE io, int sync)
2333{
2334 rb_io_t *fptr;
2335
2336 if (!RB_TYPE_P(io, T_FILE)) {
2337 return rb_funcall(io, id_flush, 0);
2338 }
2339
2340 io = GetWriteIO(io);
2341 GetOpenFile(io, fptr);
2342
2343 if (fptr->mode & FMODE_WRITABLE) {
2344 if (io_fflush(fptr) < 0)
2345 rb_sys_fail_on_write(fptr);
2346 }
2347 if (fptr->mode & FMODE_READABLE) {
2348 io_unread(fptr);
2349 }
2350
2351 return io;
2352}
2353
2354/*
2355 * call-seq:
2356 * flush -> self
2357 *
2358 * Flushes data buffered in +self+ to the operating system
2359 * (but does not necessarily flush data buffered in the operating system):
2360 *
2361 * $stdout.print 'no newline' # Not necessarily flushed.
2362 * $stdout.flush # Flushed.
2363 *
2364 */
2365
2366VALUE
2368{
2369 return rb_io_flush_raw(io, 1);
2370}
2371
2372/*
2373 * call-seq:
2374 * tell -> integer
2375 *
2376 * Returns the current position (in bytes) in +self+
2377 * (see {Position}[rdoc-ref:IO@Position]):
2378 *
2379 * f = File.open('t.txt')
2380 * f.tell # => 0
2381 * f.gets # => "First line\n"
2382 * f.tell # => 12
2383 * f.close
2384 *
2385 * Related: IO#pos=, IO#seek.
2386 *
2387 * IO#pos is an alias for IO#tell.
2388 *
2389 */
2390
2391static VALUE
2392rb_io_tell(VALUE io)
2393{
2394 rb_io_t *fptr;
2395 rb_off_t pos;
2396
2397 GetOpenFile(io, fptr);
2398 pos = io_tell(fptr);
2399 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2400 pos -= fptr->rbuf.len;
2401 return OFFT2NUM(pos);
2402}
2403
2404static VALUE
2405rb_io_seek(VALUE io, VALUE offset, int whence)
2406{
2407 rb_io_t *fptr;
2408 rb_off_t pos;
2409
2410 pos = NUM2OFFT(offset);
2411 GetOpenFile(io, fptr);
2412 pos = io_seek(fptr, pos, whence);
2413 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2414
2415 return INT2FIX(0);
2416}
2417
2418static int
2419interpret_seek_whence(VALUE vwhence)
2420{
2421 if (vwhence == sym_SET)
2422 return SEEK_SET;
2423 if (vwhence == sym_CUR)
2424 return SEEK_CUR;
2425 if (vwhence == sym_END)
2426 return SEEK_END;
2427#ifdef SEEK_DATA
2428 if (vwhence == sym_DATA)
2429 return SEEK_DATA;
2430#endif
2431#ifdef SEEK_HOLE
2432 if (vwhence == sym_HOLE)
2433 return SEEK_HOLE;
2434#endif
2435 return NUM2INT(vwhence);
2436}
2437
2438/*
2439 * call-seq:
2440 * seek(offset, whence = IO::SEEK_SET) -> 0
2441 *
2442 * Seeks to the position given by integer +offset+
2443 * (see {Position}[rdoc-ref:IO@Position])
2444 * and constant +whence+, which is one of:
2445 *
2446 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2447 * Repositions the stream to its current position plus the given +offset+:
2448 *
2449 * f = File.open('t.txt')
2450 * f.tell # => 0
2451 * f.seek(20, :CUR) # => 0
2452 * f.tell # => 20
2453 * f.seek(-10, :CUR) # => 0
2454 * f.tell # => 10
2455 * f.close
2456 *
2457 * - +:END+ or <tt>IO::SEEK_END</tt>:
2458 * Repositions the stream to its end plus the given +offset+:
2459 *
2460 * f = File.open('t.txt')
2461 * f.tell # => 0
2462 * f.seek(0, :END) # => 0 # Repositions to stream end.
2463 * f.tell # => 52
2464 * f.seek(-20, :END) # => 0
2465 * f.tell # => 32
2466 * f.seek(-40, :END) # => 0
2467 * f.tell # => 12
2468 * f.close
2469 *
2470 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2471 * Repositions the stream to the given +offset+:
2472 *
2473 * f = File.open('t.txt')
2474 * f.tell # => 0
2475 * f.seek(20, :SET) # => 0
2476 * f.tell # => 20
2477 * f.seek(40, :SET) # => 0
2478 * f.tell # => 40
2479 * f.close
2480 *
2481 * Related: IO#pos=, IO#tell.
2482 *
2483 */
2484
2485static VALUE
2486rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2487{
2488 VALUE offset, ptrname;
2489 int whence = SEEK_SET;
2490
2491 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2492 whence = interpret_seek_whence(ptrname);
2493 }
2494
2495 return rb_io_seek(io, offset, whence);
2496}
2497
2498/*
2499 * call-seq:
2500 * pos = new_position -> new_position
2501 *
2502 * Seeks to the given +new_position+ (in bytes);
2503 * see {Position}[rdoc-ref:IO@Position]:
2504 *
2505 * f = File.open('t.txt')
2506 * f.tell # => 0
2507 * f.pos = 20 # => 20
2508 * f.tell # => 20
2509 * f.close
2510 *
2511 * Related: IO#seek, IO#tell.
2512 *
2513 */
2514
2515static VALUE
2516rb_io_set_pos(VALUE io, VALUE offset)
2517{
2518 rb_io_t *fptr;
2519 rb_off_t pos;
2520
2521 pos = NUM2OFFT(offset);
2522 GetOpenFile(io, fptr);
2523 pos = io_seek(fptr, pos, SEEK_SET);
2524 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2525
2526 return OFFT2NUM(pos);
2527}
2528
2529static void clear_readconv(rb_io_t *fptr);
2530
2531/*
2532 * call-seq:
2533 * rewind -> 0
2534 *
2535 * Repositions the stream to its beginning,
2536 * setting both the position and the line number to zero;
2537 * see {Position}[rdoc-ref:IO@Position]
2538 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2539 *
2540 * f = File.open('t.txt')
2541 * f.tell # => 0
2542 * f.lineno # => 0
2543 * f.gets # => "First line\n"
2544 * f.tell # => 12
2545 * f.lineno # => 1
2546 * f.rewind # => 0
2547 * f.tell # => 0
2548 * f.lineno # => 0
2549 * f.close
2550 *
2551 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2552 *
2553 */
2554
2555static VALUE
2556rb_io_rewind(VALUE io)
2557{
2558 rb_io_t *fptr;
2559
2560 GetOpenFile(io, fptr);
2561 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2562 if (io == ARGF.current_file) {
2563 ARGF.lineno -= fptr->lineno;
2564 }
2565 fptr->lineno = 0;
2566 if (fptr->readconv) {
2567 clear_readconv(fptr);
2568 }
2569
2570 return INT2FIX(0);
2571}
2572
2573static int
2574fptr_wait_readable(rb_io_t *fptr)
2575{
2576 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2577
2578 if (result)
2579 rb_io_check_closed(fptr);
2580
2581 return result;
2582}
2583
2584static int
2585io_fillbuf(rb_io_t *fptr)
2586{
2587 ssize_t r;
2588
2589 if (fptr->rbuf.ptr == NULL) {
2590 fptr->rbuf.off = 0;
2591 fptr->rbuf.len = 0;
2592 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2593 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2594#ifdef _WIN32
2595 fptr->rbuf.capa--;
2596#endif
2597 }
2598 if (fptr->rbuf.len == 0) {
2599 retry:
2600 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2601
2602 if (r < 0) {
2603 if (fptr_wait_readable(fptr))
2604 goto retry;
2605
2606 int e = errno;
2607 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2608 if (!NIL_P(fptr->pathv)) {
2609 rb_str_append(path, fptr->pathv);
2610 }
2611
2612 rb_syserr_fail_path(e, path);
2613 }
2614 if (r > 0) rb_io_check_closed(fptr);
2615 fptr->rbuf.off = 0;
2616 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2617 if (r == 0)
2618 return -1; /* EOF */
2619 }
2620 return 0;
2621}
2622
2623/*
2624 * call-seq:
2625 * eof -> true or false
2626 *
2627 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2628 * see {Position}[rdoc-ref:IO@Position]:
2629 *
2630 * f = File.open('t.txt')
2631 * f.eof # => false
2632 * f.seek(0, :END) # => 0
2633 * f.eof # => true
2634 * f.close
2635 *
2636 * Raises an exception unless the stream is opened for reading;
2637 * see {Mode}[rdoc-ref:File@Access+Modes].
2638 *
2639 * If +self+ is a stream such as pipe or socket, this method
2640 * blocks until the other end sends some data or closes it:
2641 *
2642 * r, w = IO.pipe
2643 * Thread.new { sleep 1; w.close }
2644 * r.eof? # => true # After 1-second wait.
2645 *
2646 * r, w = IO.pipe
2647 * Thread.new { sleep 1; w.puts "a" }
2648 * r.eof? # => false # After 1-second wait.
2649 *
2650 * r, w = IO.pipe
2651 * r.eof? # blocks forever
2652 *
2653 * Note that this method reads data to the input byte buffer. So
2654 * IO#sysread may not behave as you intend with IO#eof?, unless you
2655 * call IO#rewind first (which is not available for some streams).
2656 *
2657 * IO#eof? is an alias for IO#eof.
2658 *
2659 */
2660
2661VALUE
2663{
2664 rb_io_t *fptr;
2665
2666 GetOpenFile(io, 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{
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 * IO#to_i is an alias for IO#fileno.
2850 *
2851 */
2852
2853static VALUE
2854rb_io_fileno(VALUE io)
2855{
2856 rb_io_t *fptr = RFILE(io)->fptr;
2857 int fd;
2858
2859 rb_io_check_closed(fptr);
2860 fd = fptr->fd;
2861 return INT2FIX(fd);
2862}
2863
2864int
2866{
2867 if (RB_TYPE_P(io, T_FILE)) {
2868 rb_io_t *fptr = RFILE(io)->fptr;
2869 rb_io_check_closed(fptr);
2870 return fptr->fd;
2871 }
2872 else {
2873 return RB_NUM2INT(rb_funcall(io, id_fileno, 0));
2874 }
2875}
2876
2877/*
2878 * call-seq:
2879 * pid -> integer or nil
2880 *
2881 * Returns the process ID of a child process associated with the stream,
2882 * which will have been set by IO#popen, or +nil+ if the stream was not
2883 * created by IO#popen:
2884 *
2885 * pipe = IO.popen("-")
2886 * if pipe
2887 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2888 * else
2889 * $stderr.puts "In child, pid is #{$$}"
2890 * end
2891 *
2892 * Output:
2893 *
2894 * In child, pid is 26209
2895 * In parent, child pid is 26209
2896 *
2897 */
2898
2899static VALUE
2900rb_io_pid(VALUE io)
2901{
2902 rb_io_t *fptr;
2903
2904 GetOpenFile(io, fptr);
2905 if (!fptr->pid)
2906 return Qnil;
2907 return PIDT2NUM(fptr->pid);
2908}
2909
2910/*
2911 * call-seq:
2912 * path -> string or nil
2913 *
2914 * Returns the path associated with the IO, or +nil+ if there is no path
2915 * associated with the IO. It is not guaranteed that the path exists on
2916 * the filesystem.
2917 *
2918 * $stdin.path # => "<STDIN>"
2919 *
2920 * File.open("testfile") {|f| f.path} # => "testfile"
2921 */
2922
2923static VALUE
2924rb_io_path(VALUE io)
2925{
2926 rb_io_t *fptr = RFILE(io)->fptr;
2927
2928 if (!fptr)
2929 return Qnil;
2930
2931 return rb_obj_dup(fptr->pathv);
2932}
2933
2934/*
2935 * call-seq:
2936 * inspect -> string
2937 *
2938 * Returns a string representation of +self+:
2939 *
2940 * f = File.open('t.txt')
2941 * f.inspect # => "#<File:t.txt>"
2942 * f.close
2943 *
2944 */
2945
2946static VALUE
2947rb_io_inspect(VALUE obj)
2948{
2949 rb_io_t *fptr;
2950 VALUE result;
2951 static const char closed[] = " (closed)";
2952
2953 fptr = RFILE(obj)->fptr;
2954 if (!fptr) return rb_any_to_s(obj);
2955 result = rb_str_new_cstr("#<");
2956 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2957 rb_str_cat2(result, ":");
2958 if (NIL_P(fptr->pathv)) {
2959 if (fptr->fd < 0) {
2960 rb_str_cat(result, closed+1, strlen(closed)-1);
2961 }
2962 else {
2963 rb_str_catf(result, "fd %d", fptr->fd);
2964 }
2965 }
2966 else {
2967 rb_str_append(result, fptr->pathv);
2968 if (fptr->fd < 0) {
2969 rb_str_cat(result, closed, strlen(closed));
2970 }
2971 }
2972 return rb_str_cat2(result, ">");
2973}
2974
2975/*
2976 * call-seq:
2977 * to_io -> self
2978 *
2979 * Returns +self+.
2980 *
2981 */
2982
2983static VALUE
2984rb_io_to_io(VALUE io)
2985{
2986 return io;
2987}
2988
2989/* reading functions */
2990static long
2991read_buffered_data(char *ptr, long len, rb_io_t *fptr)
2992{
2993 int n;
2994
2995 n = READ_DATA_PENDING_COUNT(fptr);
2996 if (n <= 0) return 0;
2997 if (n > len) n = (int)len;
2998 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
2999 fptr->rbuf.off += n;
3000 fptr->rbuf.len -= n;
3001 return n;
3002}
3003
3004static long
3005io_bufread(char *ptr, long len, rb_io_t *fptr)
3006{
3007 long offset = 0;
3008 long n = len;
3009 long c;
3010
3011 if (READ_DATA_PENDING(fptr) == 0) {
3012 while (n > 0) {
3013 again:
3014 rb_io_check_closed(fptr);
3015 c = rb_io_read_memory(fptr, ptr+offset, n);
3016 if (c == 0) break;
3017 if (c < 0) {
3018 if (fptr_wait_readable(fptr))
3019 goto again;
3020 return -1;
3021 }
3022 offset += c;
3023 if ((n -= c) <= 0) break;
3024 }
3025 return len - n;
3026 }
3027
3028 while (n > 0) {
3029 c = read_buffered_data(ptr+offset, n, fptr);
3030 if (c > 0) {
3031 offset += c;
3032 if ((n -= c) <= 0) break;
3033 }
3034 rb_io_check_closed(fptr);
3035 if (io_fillbuf(fptr) < 0) {
3036 break;
3037 }
3038 }
3039 return len - n;
3040}
3041
3042static int io_setstrbuf(VALUE *str, long len);
3043
3045 char *str_ptr;
3046 long len;
3047 rb_io_t *fptr;
3048};
3049
3050static VALUE
3051bufread_call(VALUE arg)
3052{
3053 struct bufread_arg *p = (struct bufread_arg *)arg;
3054 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3055 return Qundef;
3056}
3057
3058static long
3059io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3060{
3061 long len;
3062 struct bufread_arg arg;
3063
3064 io_setstrbuf(&str, offset + size);
3065 arg.str_ptr = RSTRING_PTR(str) + offset;
3066 arg.len = size;
3067 arg.fptr = fptr;
3068 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3069 len = arg.len;
3070 if (len < 0) rb_sys_fail_path(fptr->pathv);
3071 return len;
3072}
3073
3074static long
3075remain_size(rb_io_t *fptr)
3076{
3077 struct stat st;
3078 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3079 rb_off_t pos;
3080
3081 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3082#if defined(__HAIKU__)
3083 && (st.st_dev > 3)
3084#endif
3085 )
3086 {
3087 if (io_fflush(fptr) < 0)
3088 rb_sys_fail_on_write(fptr);
3089 pos = lseek(fptr->fd, 0, SEEK_CUR);
3090 if (st.st_size >= pos && pos >= 0) {
3091 siz += st.st_size - pos;
3092 if (siz > LONG_MAX) {
3093 rb_raise(rb_eIOError, "file too big for single read");
3094 }
3095 }
3096 }
3097 else {
3098 siz += BUFSIZ;
3099 }
3100 return (long)siz;
3101}
3102
3103static VALUE
3104io_enc_str(VALUE str, rb_io_t *fptr)
3105{
3106 rb_enc_associate(str, io_read_encoding(fptr));
3107 return str;
3108}
3109
3110static rb_encoding *io_read_encoding(rb_io_t *fptr);
3111
3112static void
3113make_readconv(rb_io_t *fptr, int size)
3114{
3115 if (!fptr->readconv) {
3116 int ecflags;
3117 VALUE ecopts;
3118 const char *sname, *dname;
3119 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3120 ecopts = fptr->encs.ecopts;
3121 if (fptr->encs.enc2) {
3122 sname = rb_enc_name(fptr->encs.enc2);
3123 dname = rb_enc_name(io_read_encoding(fptr));
3124 }
3125 else {
3126 sname = dname = "";
3127 }
3128 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3129 if (!fptr->readconv)
3130 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3131 fptr->cbuf.off = 0;
3132 fptr->cbuf.len = 0;
3133 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3134 fptr->cbuf.capa = size;
3135 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3136 }
3137}
3138
3139#define MORE_CHAR_SUSPENDED Qtrue
3140#define MORE_CHAR_FINISHED Qnil
3141static VALUE
3142fill_cbuf(rb_io_t *fptr, int ec_flags)
3143{
3144 const unsigned char *ss, *sp, *se;
3145 unsigned char *ds, *dp, *de;
3147 int putbackable;
3148 int cbuf_len0;
3149 VALUE exc;
3150
3151 ec_flags |= ECONV_PARTIAL_INPUT;
3152
3153 if (fptr->cbuf.len == fptr->cbuf.capa)
3154 return MORE_CHAR_SUSPENDED; /* cbuf full */
3155 if (fptr->cbuf.len == 0)
3156 fptr->cbuf.off = 0;
3157 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3158 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3159 fptr->cbuf.off = 0;
3160 }
3161
3162 cbuf_len0 = fptr->cbuf.len;
3163
3164 while (1) {
3165 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3166 se = sp + fptr->rbuf.len;
3167 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3168 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3169 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3170 fptr->rbuf.off += (int)(sp - ss);
3171 fptr->rbuf.len -= (int)(sp - ss);
3172 fptr->cbuf.len += (int)(dp - ds);
3173
3174 putbackable = rb_econv_putbackable(fptr->readconv);
3175 if (putbackable) {
3176 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3177 fptr->rbuf.off -= putbackable;
3178 fptr->rbuf.len += putbackable;
3179 }
3180
3181 exc = rb_econv_make_exception(fptr->readconv);
3182 if (!NIL_P(exc))
3183 return exc;
3184
3185 if (cbuf_len0 != fptr->cbuf.len)
3186 return MORE_CHAR_SUSPENDED;
3187
3188 if (res == econv_finished) {
3189 return MORE_CHAR_FINISHED;
3190 }
3191
3192 if (res == econv_source_buffer_empty) {
3193 if (fptr->rbuf.len == 0) {
3194 READ_CHECK(fptr);
3195 if (io_fillbuf(fptr) < 0) {
3196 if (!fptr->readconv) {
3197 return MORE_CHAR_FINISHED;
3198 }
3199 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3200 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3201 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3202 fptr->cbuf.len += (int)(dp - ds);
3204 break;
3205 }
3206 }
3207 }
3208 }
3209 if (cbuf_len0 != fptr->cbuf.len)
3210 return MORE_CHAR_SUSPENDED;
3211
3212 return MORE_CHAR_FINISHED;
3213}
3214
3215static VALUE
3216more_char(rb_io_t *fptr)
3217{
3218 VALUE v;
3219 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3220 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3221 rb_exc_raise(v);
3222 return v;
3223}
3224
3225static VALUE
3226io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3227{
3228 VALUE str = Qnil;
3229 if (strp) {
3230 str = *strp;
3231 if (NIL_P(str)) {
3232 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3233 }
3234 else {
3235 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3236 }
3237 rb_enc_associate(str, fptr->encs.enc);
3238 }
3239 fptr->cbuf.off += len;
3240 fptr->cbuf.len -= len;
3241 /* xxx: set coderange */
3242 if (fptr->cbuf.len == 0)
3243 fptr->cbuf.off = 0;
3244 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3245 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3246 fptr->cbuf.off = 0;
3247 }
3248 return str;
3249}
3250
3251static int
3252io_setstrbuf(VALUE *str, long len)
3253{
3254#ifdef _WIN32
3255 if (len > 0)
3256 len = (len + 1) & ~1L; /* round up for wide char */
3257#endif
3258 if (NIL_P(*str)) {
3259 *str = rb_str_new(0, len);
3260 return TRUE;
3261 }
3262 else {
3263 VALUE s = StringValue(*str);
3264 long clen = RSTRING_LEN(s);
3265 if (clen >= len) {
3266 rb_str_modify(s);
3267 return FALSE;
3268 }
3269 len -= clen;
3270 }
3271 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3272 rb_str_modify_expand(*str, len);
3273 }
3274 return FALSE;
3275}
3276
3277#define MAX_REALLOC_GAP 4096
3278static void
3279io_shrink_read_string(VALUE str, long n)
3280{
3281 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3282 rb_str_resize(str, n);
3283 }
3284}
3285
3286static void
3287io_set_read_length(VALUE str, long n, int shrinkable)
3288{
3289 if (RSTRING_LEN(str) != n) {
3290 rb_str_modify(str);
3291 rb_str_set_len(str, n);
3292 if (shrinkable) io_shrink_read_string(str, n);
3293 }
3294}
3295
3296static VALUE
3297read_all(rb_io_t *fptr, long siz, VALUE str)
3298{
3299 long bytes;
3300 long n;
3301 long pos;
3302 rb_encoding *enc;
3303 int cr;
3304 int shrinkable;
3305
3306 if (NEED_READCONV(fptr)) {
3307 int first = !NIL_P(str);
3308 SET_BINARY_MODE(fptr);
3309 shrinkable = io_setstrbuf(&str,0);
3310 make_readconv(fptr, 0);
3311 while (1) {
3312 VALUE v;
3313 if (fptr->cbuf.len) {
3314 if (first) rb_str_set_len(str, first = 0);
3315 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3316 }
3317 v = fill_cbuf(fptr, 0);
3318 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3319 if (fptr->cbuf.len) {
3320 if (first) rb_str_set_len(str, first = 0);
3321 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3322 }
3323 rb_exc_raise(v);
3324 }
3325 if (v == MORE_CHAR_FINISHED) {
3326 clear_readconv(fptr);
3327 if (first) rb_str_set_len(str, first = 0);
3328 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3329 return io_enc_str(str, fptr);
3330 }
3331 }
3332 }
3333
3334 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3335 bytes = 0;
3336 pos = 0;
3337
3338 enc = io_read_encoding(fptr);
3339 cr = 0;
3340
3341 if (siz == 0) siz = BUFSIZ;
3342 shrinkable = io_setstrbuf(&str, siz);
3343 for (;;) {
3344 READ_CHECK(fptr);
3345 n = io_fread(str, bytes, siz - bytes, fptr);
3346 if (n == 0 && bytes == 0) {
3347 rb_str_set_len(str, 0);
3348 break;
3349 }
3350 bytes += n;
3351 rb_str_set_len(str, bytes);
3352 if (cr != ENC_CODERANGE_BROKEN)
3353 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3354 if (bytes < siz) break;
3355 siz += BUFSIZ;
3356
3357 size_t capa = rb_str_capacity(str);
3358 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3359 if (capa < BUFSIZ) {
3360 capa = BUFSIZ;
3361 }
3362 else if (capa > IO_MAX_BUFFER_GROWTH) {
3363 capa = IO_MAX_BUFFER_GROWTH;
3364 }
3365 rb_str_modify_expand(str, capa);
3366 }
3367 }
3368 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3369 str = io_enc_str(str, fptr);
3370 ENC_CODERANGE_SET(str, cr);
3371 return str;
3372}
3373
3374void
3376{
3377 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3378 rb_sys_fail_path(fptr->pathv);
3379 }
3380}
3381
3382static VALUE
3383io_read_memory_call(VALUE arg)
3384{
3385 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3386
3387 VALUE scheduler = rb_fiber_scheduler_current();
3388 if (scheduler != Qnil) {
3389 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3390
3391 if (!UNDEF_P(result)) {
3392 // This is actually returned as a pseudo-VALUE and later cast to a long:
3394 }
3395 }
3396
3397 return rb_thread_io_blocking_region(internal_read_func, iis, iis->fptr->fd);
3398}
3399
3400static long
3401io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3402{
3403 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3404}
3405
3406#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3407
3408static VALUE
3409io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3410{
3411 rb_io_t *fptr;
3412 VALUE length, str;
3413 long n, len;
3414 struct io_internal_read_struct iis;
3415 int shrinkable;
3416
3417 rb_scan_args(argc, argv, "11", &length, &str);
3418
3419 if ((len = NUM2LONG(length)) < 0) {
3420 rb_raise(rb_eArgError, "negative length %ld given", len);
3421 }
3422
3423 shrinkable = io_setstrbuf(&str, len);
3424
3425 GetOpenFile(io, fptr);
3427
3428 if (len == 0) {
3429 io_set_read_length(str, 0, shrinkable);
3430 return str;
3431 }
3432
3433 if (!nonblock)
3434 READ_CHECK(fptr);
3435 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3436 if (n <= 0) {
3437 again:
3438 if (nonblock) {
3439 rb_io_set_nonblock(fptr);
3440 }
3441 io_setstrbuf(&str, len);
3442 iis.th = rb_thread_current();
3443 iis.fptr = fptr;
3444 iis.nonblock = nonblock;
3445 iis.fd = fptr->fd;
3446 iis.buf = RSTRING_PTR(str);
3447 iis.capa = len;
3448 iis.timeout = NULL;
3449 n = io_read_memory_locktmp(str, &iis);
3450 if (n < 0) {
3451 int e = errno;
3452 if (!nonblock && fptr_wait_readable(fptr))
3453 goto again;
3454 if (nonblock && (io_again_p(e))) {
3455 if (no_exception)
3456 return sym_wait_readable;
3457 else
3458 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3459 e, "read would block");
3460 }
3461 rb_syserr_fail_path(e, fptr->pathv);
3462 }
3463 }
3464 io_set_read_length(str, n, shrinkable);
3465
3466 if (n == 0)
3467 return Qnil;
3468 else
3469 return str;
3470}
3471
3472/*
3473 * call-seq:
3474 * readpartial(maxlen) -> string
3475 * readpartial(maxlen, out_string) -> out_string
3476 *
3477 * Reads up to +maxlen+ bytes from the stream;
3478 * returns a string (either a new string or the given +out_string+).
3479 * Its encoding is:
3480 *
3481 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3482 * - ASCII-8BIT, otherwise.
3483 *
3484 * - Contains +maxlen+ bytes from the stream, if available.
3485 * - Otherwise contains all available bytes, if any available.
3486 * - Otherwise is an empty string.
3487 *
3488 * With the single non-negative integer argument +maxlen+ given,
3489 * returns a new string:
3490 *
3491 * f = File.new('t.txt')
3492 * f.readpartial(20) # => "First line\nSecond l"
3493 * f.readpartial(20) # => "ine\n\nFourth line\n"
3494 * f.readpartial(20) # => "Fifth line\n"
3495 * f.readpartial(20) # Raises EOFError.
3496 * f.close
3497 *
3498 * With both argument +maxlen+ and string argument +out_string+ given,
3499 * returns modified +out_string+:
3500 *
3501 * f = File.new('t.txt')
3502 * s = 'foo'
3503 * f.readpartial(20, s) # => "First line\nSecond l"
3504 * s = 'bar'
3505 * f.readpartial(0, s) # => ""
3506 * f.close
3507 *
3508 * This method is useful for a stream such as a pipe, a socket, or a tty.
3509 * It blocks only when no data is immediately available.
3510 * This means that it blocks only when _all_ of the following are true:
3511 *
3512 * - The byte buffer in the stream is empty.
3513 * - The content of the stream is empty.
3514 * - The stream is not at EOF.
3515 *
3516 * When blocked, the method waits for either more data or EOF on the stream:
3517 *
3518 * - If more data is read, the method returns the data.
3519 * - If EOF is reached, the method raises EOFError.
3520 *
3521 * When not blocked, the method responds immediately:
3522 *
3523 * - Returns data from the buffer if there is any.
3524 * - Otherwise returns data from the stream if there is any.
3525 * - Otherwise raises EOFError if the stream has reached EOF.
3526 *
3527 * Note that this method is similar to sysread. The differences are:
3528 *
3529 * - If the byte buffer is not empty, read from the byte buffer
3530 * instead of "sysread for buffered IO (IOError)".
3531 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3532 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3533 * readpartial retries the system call.
3534 *
3535 * The latter means that readpartial is non-blocking-flag insensitive.
3536 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3537 * if the fd is blocking mode.
3538 *
3539 * Examples:
3540 *
3541 * # # Returned Buffer Content Pipe Content
3542 * r, w = IO.pipe #
3543 * w << 'abc' # "" "abc".
3544 * r.readpartial(4096) # => "abc" "" ""
3545 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3546 *
3547 * # # Returned Buffer Content Pipe Content
3548 * r, w = IO.pipe #
3549 * w << 'abc' # "" "abc"
3550 * w.close # "" "abc" EOF
3551 * r.readpartial(4096) # => "abc" "" EOF
3552 * r.readpartial(4096) # raises EOFError
3553 *
3554 * # # Returned Buffer Content Pipe Content
3555 * r, w = IO.pipe #
3556 * w << "abc\ndef\n" # "" "abc\ndef\n"
3557 * r.gets # => "abc\n" "def\n" ""
3558 * w << "ghi\n" # "def\n" "ghi\n"
3559 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3560 * r.readpartial(4096) # => "ghi\n" "" ""
3561 *
3562 */
3563
3564static VALUE
3565io_readpartial(int argc, VALUE *argv, VALUE io)
3566{
3567 VALUE ret;
3568
3569 ret = io_getpartial(argc, argv, io, Qnil, 0);
3570 if (NIL_P(ret))
3571 rb_eof_error();
3572 return ret;
3573}
3574
3575static VALUE
3576io_nonblock_eof(int no_exception)
3577{
3578 if (!no_exception) {
3579 rb_eof_error();
3580 }
3581 return Qnil;
3582}
3583
3584/* :nodoc: */
3585static VALUE
3586io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3587{
3588 rb_io_t *fptr;
3589 long n, len;
3590 struct io_internal_read_struct iis;
3591 int shrinkable;
3592
3593 if ((len = NUM2LONG(length)) < 0) {
3594 rb_raise(rb_eArgError, "negative length %ld given", len);
3595 }
3596
3597 shrinkable = io_setstrbuf(&str, len);
3598 rb_bool_expected(ex, "exception", TRUE);
3599
3600 GetOpenFile(io, fptr);
3602
3603 if (len == 0) {
3604 io_set_read_length(str, 0, shrinkable);
3605 return str;
3606 }
3607
3608 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3609 if (n <= 0) {
3610 rb_fd_set_nonblock(fptr->fd);
3611 shrinkable |= io_setstrbuf(&str, len);
3612 iis.fptr = fptr;
3613 iis.nonblock = 1;
3614 iis.fd = fptr->fd;
3615 iis.buf = RSTRING_PTR(str);
3616 iis.capa = len;
3617 iis.timeout = NULL;
3618 n = io_read_memory_locktmp(str, &iis);
3619 if (n < 0) {
3620 int e = errno;
3621 if (io_again_p(e)) {
3622 if (!ex) return sym_wait_readable;
3623 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3624 e, "read would block");
3625 }
3626 rb_syserr_fail_path(e, fptr->pathv);
3627 }
3628 }
3629 io_set_read_length(str, n, shrinkable);
3630
3631 if (n == 0) {
3632 if (!ex) return Qnil;
3633 rb_eof_error();
3634 }
3635
3636 return str;
3637}
3638
3639/* :nodoc: */
3640static VALUE
3641io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3642{
3643 rb_io_t *fptr;
3644 long n;
3645
3646 if (!RB_TYPE_P(str, T_STRING))
3647 str = rb_obj_as_string(str);
3648 rb_bool_expected(ex, "exception", TRUE);
3649
3650 io = GetWriteIO(io);
3651 GetOpenFile(io, fptr);
3653
3654 if (io_fflush(fptr) < 0)
3655 rb_sys_fail_on_write(fptr);
3656
3657 rb_fd_set_nonblock(fptr->fd);
3658 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3659 RB_GC_GUARD(str);
3660
3661 if (n < 0) {
3662 int e = errno;
3663 if (io_again_p(e)) {
3664 if (!ex) {
3665 return sym_wait_writable;
3666 }
3667 else {
3668 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3669 }
3670 }
3671 rb_syserr_fail_path(e, fptr->pathv);
3672 }
3673
3674 return LONG2FIX(n);
3675}
3676
3677/*
3678 * call-seq:
3679 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3680 *
3681 * Reads bytes from the stream; the stream must be opened for reading
3682 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3683 *
3684 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3685 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3686 *
3687 * Returns a string (either a new string or the given +out_string+)
3688 * containing the bytes read.
3689 * The encoding of the string depends on both +maxLen+ and +out_string+:
3690 *
3691 * - +maxlen+ is +nil+: uses internal encoding of +self+
3692 * (regardless of whether +out_string+ was given).
3693 * - +maxlen+ not +nil+:
3694 *
3695 * - +out_string+ given: encoding of +out_string+ not modified.
3696 * - +out_string+ not given: ASCII-8BIT is used.
3697 *
3698 * <b>Without Argument +out_string+</b>
3699 *
3700 * When argument +out_string+ is omitted,
3701 * the returned value is a new string:
3702 *
3703 * f = File.new('t.txt')
3704 * f.read
3705 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3706 * f.rewind
3707 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3708 * f.read(30) # => "rth line\r\nFifth line\r\n"
3709 * f.read(30) # => nil
3710 * f.close
3711 *
3712 * If +maxlen+ is zero, returns an empty string.
3713 *
3714 * <b> With Argument +out_string+</b>
3715 *
3716 * When argument +out_string+ is given,
3717 * the returned value is +out_string+, whose content is replaced:
3718 *
3719 * f = File.new('t.txt')
3720 * s = 'foo' # => "foo"
3721 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3722 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3723 * f.rewind
3724 * s = 'bar'
3725 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3726 * s # => "First line\r\nSecond line\r\n\r\nFou"
3727 * s = 'baz'
3728 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3729 * s # => "rth line\r\nFifth line\r\n"
3730 * s = 'bat'
3731 * f.read(30, s) # => nil
3732 * s # => ""
3733 * f.close
3734 *
3735 * Note that this method behaves like the fread() function in C.
3736 * This means it retries to invoke read(2) system calls to read data
3737 * with the specified maxlen (or until EOF).
3738 *
3739 * This behavior is preserved even if the stream is in non-blocking mode.
3740 * (This method is non-blocking-flag insensitive as other methods.)
3741 *
3742 * If you need the behavior like a single read(2) system call,
3743 * consider #readpartial, #read_nonblock, and #sysread.
3744 *
3745 * Related: IO#write.
3746 */
3747
3748static VALUE
3749io_read(int argc, VALUE *argv, VALUE io)
3750{
3751 rb_io_t *fptr;
3752 long n, len;
3753 VALUE length, str;
3754 int shrinkable;
3755#if RUBY_CRLF_ENVIRONMENT
3756 int previous_mode;
3757#endif
3758
3759 rb_scan_args(argc, argv, "02", &length, &str);
3760
3761 if (NIL_P(length)) {
3762 GetOpenFile(io, fptr);
3764 return read_all(fptr, remain_size(fptr), str);
3765 }
3766 len = NUM2LONG(length);
3767 if (len < 0) {
3768 rb_raise(rb_eArgError, "negative length %ld given", len);
3769 }
3770
3771 shrinkable = io_setstrbuf(&str,len);
3772
3773 GetOpenFile(io, fptr);
3775 if (len == 0) {
3776 io_set_read_length(str, 0, shrinkable);
3777 return str;
3778 }
3779
3780 READ_CHECK(fptr);
3781#if RUBY_CRLF_ENVIRONMENT
3782 previous_mode = set_binary_mode_with_seek_cur(fptr);
3783#endif
3784 n = io_fread(str, 0, len, fptr);
3785 io_set_read_length(str, n, shrinkable);
3786#if RUBY_CRLF_ENVIRONMENT
3787 if (previous_mode == O_TEXT) {
3788 setmode(fptr->fd, O_TEXT);
3789 }
3790#endif
3791 if (n == 0) return Qnil;
3792
3793 return str;
3794}
3795
3796static void
3797rscheck(const char *rsptr, long rslen, VALUE rs)
3798{
3799 if (!rs) return;
3800 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3801 rb_raise(rb_eRuntimeError, "rs modified");
3802}
3803
3804static int
3805appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
3806{
3807 VALUE str = *strp;
3808 long limit = *lp;
3809
3810 if (NEED_READCONV(fptr)) {
3811 SET_BINARY_MODE(fptr);
3812 make_readconv(fptr, 0);
3813 do {
3814 const char *p, *e;
3815 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3816 if (searchlen) {
3817 p = READ_CHAR_PENDING_PTR(fptr);
3818 if (0 < limit && limit < searchlen)
3819 searchlen = (int)limit;
3820 e = memchr(p, delim, searchlen);
3821 if (e) {
3822 int len = (int)(e-p+1);
3823 if (NIL_P(str))
3824 *strp = str = rb_str_new(p, len);
3825 else
3826 rb_str_buf_cat(str, p, len);
3827 fptr->cbuf.off += len;
3828 fptr->cbuf.len -= len;
3829 limit -= len;
3830 *lp = limit;
3831 return delim;
3832 }
3833
3834 if (NIL_P(str))
3835 *strp = str = rb_str_new(p, searchlen);
3836 else
3837 rb_str_buf_cat(str, p, searchlen);
3838 fptr->cbuf.off += searchlen;
3839 fptr->cbuf.len -= searchlen;
3840 limit -= searchlen;
3841
3842 if (limit == 0) {
3843 *lp = limit;
3844 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3845 }
3846 }
3847 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3848 clear_readconv(fptr);
3849 *lp = limit;
3850 return EOF;
3851 }
3852
3853 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3854 do {
3855 long pending = READ_DATA_PENDING_COUNT(fptr);
3856 if (pending > 0) {
3857 const char *p = READ_DATA_PENDING_PTR(fptr);
3858 const char *e;
3859 long last;
3860
3861 if (limit > 0 && pending > limit) pending = limit;
3862 e = memchr(p, delim, pending);
3863 if (e) pending = e - p + 1;
3864 if (!NIL_P(str)) {
3865 last = RSTRING_LEN(str);
3866 rb_str_resize(str, last + pending);
3867 }
3868 else {
3869 last = 0;
3870 *strp = str = rb_str_buf_new(pending);
3871 rb_str_set_len(str, pending);
3872 }
3873 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3874 limit -= pending;
3875 *lp = limit;
3876 if (e) return delim;
3877 if (limit == 0)
3878 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3879 }
3880 READ_CHECK(fptr);
3881 } while (io_fillbuf(fptr) >= 0);
3882 *lp = limit;
3883 return EOF;
3884}
3885
3886static inline int
3887swallow(rb_io_t *fptr, int term)
3888{
3889 if (NEED_READCONV(fptr)) {
3890 rb_encoding *enc = io_read_encoding(fptr);
3891 int needconv = rb_enc_mbminlen(enc) != 1;
3892 SET_BINARY_MODE(fptr);
3893 make_readconv(fptr, 0);
3894 do {
3895 size_t cnt;
3896 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3897 const char *p = READ_CHAR_PENDING_PTR(fptr);
3898 int i;
3899 if (!needconv) {
3900 if (*p != term) return TRUE;
3901 i = (int)cnt;
3902 while (--i && *++p == term);
3903 }
3904 else {
3905 const char *e = p + cnt;
3906 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3907 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3908 i = (int)(e - p);
3909 }
3910 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3911 }
3912 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3913 return FALSE;
3914 }
3915
3916 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3917 do {
3918 size_t cnt;
3919 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3920 char buf[1024];
3921 const char *p = READ_DATA_PENDING_PTR(fptr);
3922 int i;
3923 if (cnt > sizeof buf) cnt = sizeof buf;
3924 if (*p != term) return TRUE;
3925 i = (int)cnt;
3926 while (--i && *++p == term);
3927 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
3928 rb_sys_fail_path(fptr->pathv);
3929 }
3930 READ_CHECK(fptr);
3931 } while (io_fillbuf(fptr) == 0);
3932 return FALSE;
3933}
3934
3935static VALUE
3936rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
3937{
3938 VALUE str = Qnil;
3939 int len = 0;
3940 long pos = 0;
3941 int cr = 0;
3942
3943 do {
3944 int pending = READ_DATA_PENDING_COUNT(fptr);
3945
3946 if (pending > 0) {
3947 const char *p = READ_DATA_PENDING_PTR(fptr);
3948 const char *e;
3949 int chomplen = 0;
3950
3951 e = memchr(p, '\n', pending);
3952 if (e) {
3953 pending = (int)(e - p + 1);
3954 if (chomp) {
3955 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
3956 }
3957 }
3958 if (NIL_P(str)) {
3959 str = rb_str_new(p, pending - chomplen);
3960 fptr->rbuf.off += pending;
3961 fptr->rbuf.len -= pending;
3962 }
3963 else {
3964 rb_str_resize(str, len + pending - chomplen);
3965 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
3966 fptr->rbuf.off += chomplen;
3967 fptr->rbuf.len -= chomplen;
3968 if (pending == 1 && chomplen == 1 && len > 0) {
3969 if (RSTRING_PTR(str)[len-1] == '\r') {
3970 rb_str_resize(str, --len);
3971 break;
3972 }
3973 }
3974 }
3975 len += pending - chomplen;
3976 if (cr != ENC_CODERANGE_BROKEN)
3977 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
3978 if (e) break;
3979 }
3980 READ_CHECK(fptr);
3981 } while (io_fillbuf(fptr) >= 0);
3982 if (NIL_P(str)) return Qnil;
3983
3984 str = io_enc_str(str, fptr);
3985 ENC_CODERANGE_SET(str, cr);
3986 fptr->lineno++;
3987
3988 return str;
3989}
3990
3992 VALUE io;
3993 VALUE rs;
3994 long limit;
3995 unsigned int chomp: 1;
3996};
3997
3998static void
3999extract_getline_opts(VALUE opts, struct getline_arg *args)
4000{
4001 int chomp = FALSE;
4002 if (!NIL_P(opts)) {
4003 static ID kwds[1];
4004 VALUE vchomp;
4005 if (!kwds[0]) {
4006 kwds[0] = rb_intern_const("chomp");
4007 }
4008 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4009 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4010 }
4011 args->chomp = chomp;
4012}
4013
4014static void
4015extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4016{
4017 VALUE rs = rb_rs, lim = Qnil;
4018
4019 if (argc == 1) {
4020 VALUE tmp = Qnil;
4021
4022 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4023 rs = tmp;
4024 }
4025 else {
4026 lim = argv[0];
4027 }
4028 }
4029 else if (2 <= argc) {
4030 rs = argv[0], lim = argv[1];
4031 if (!NIL_P(rs))
4032 StringValue(rs);
4033 }
4034 args->rs = rs;
4035 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4036}
4037
4038static void
4039check_getline_args(VALUE *rsp, long *limit, VALUE io)
4040{
4041 rb_io_t *fptr;
4042 VALUE rs = *rsp;
4043
4044 if (!NIL_P(rs)) {
4045 rb_encoding *enc_rs, *enc_io;
4046
4047 GetOpenFile(io, fptr);
4048 enc_rs = rb_enc_get(rs);
4049 enc_io = io_read_encoding(fptr);
4050 if (enc_io != enc_rs &&
4051 (!is_ascii_string(rs) ||
4052 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4053 if (rs == rb_default_rs) {
4054 rs = rb_enc_str_new(0, 0, enc_io);
4055 rb_str_buf_cat_ascii(rs, "\n");
4056 *rsp = rs;
4057 }
4058 else {
4059 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4060 rb_enc_name(enc_io),
4061 rb_enc_name(enc_rs));
4062 }
4063 }
4064 }
4065}
4066
4067static void
4068prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4069{
4070 VALUE opts;
4071 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4072 extract_getline_args(argc, argv, args);
4073 extract_getline_opts(opts, args);
4074 check_getline_args(&args->rs, &args->limit, io);
4075}
4076
4077static VALUE
4078rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4079{
4080 VALUE str = Qnil;
4081 int nolimit = 0;
4082 rb_encoding *enc;
4083
4085 if (NIL_P(rs) && limit < 0) {
4086 str = read_all(fptr, 0, Qnil);
4087 if (RSTRING_LEN(str) == 0) return Qnil;
4088 }
4089 else if (limit == 0) {
4090 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4091 }
4092 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4093 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4094 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4095 return rb_io_getline_fast(fptr, enc, chomp);
4096 }
4097 else {
4098 int c, newline = -1;
4099 const char *rsptr = 0;
4100 long rslen = 0;
4101 int rspara = 0;
4102 int extra_limit = 16;
4103 int chomp_cr = chomp;
4104
4105 SET_BINARY_MODE(fptr);
4106 enc = io_read_encoding(fptr);
4107
4108 if (!NIL_P(rs)) {
4109 rslen = RSTRING_LEN(rs);
4110 if (rslen == 0) {
4111 rsptr = "\n\n";
4112 rslen = 2;
4113 rspara = 1;
4114 swallow(fptr, '\n');
4115 rs = 0;
4116 if (!rb_enc_asciicompat(enc)) {
4117 rs = rb_usascii_str_new(rsptr, rslen);
4118 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
4119 OBJ_FREEZE(rs);
4120 rsptr = RSTRING_PTR(rs);
4121 rslen = RSTRING_LEN(rs);
4122 }
4123 }
4124 else {
4125 rsptr = RSTRING_PTR(rs);
4126 }
4127 newline = (unsigned char)rsptr[rslen - 1];
4128 chomp_cr = chomp && rslen == 1 && newline == '\n';
4129 }
4130
4131 /* MS - Optimization */
4132 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
4133 const char *s, *p, *pp, *e;
4134
4135 if (c == newline) {
4136 if (RSTRING_LEN(str) < rslen) continue;
4137 s = RSTRING_PTR(str);
4138 e = RSTRING_END(str);
4139 p = e - rslen;
4140 pp = rb_enc_left_char_head(s, p, e, enc);
4141 if (pp != p) continue;
4142 if (!rspara) rscheck(rsptr, rslen, rs);
4143 if (memcmp(p, rsptr, rslen) == 0) {
4144 if (chomp) {
4145 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4146 rb_str_set_len(str, p - s);
4147 }
4148 break;
4149 }
4150 }
4151 if (limit == 0) {
4152 s = RSTRING_PTR(str);
4153 p = RSTRING_END(str);
4154 pp = rb_enc_left_char_head(s, p-1, p, enc);
4155 if (extra_limit &&
4156 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4157 /* relax the limit while incomplete character.
4158 * extra_limit limits the relax length */
4159 limit = 1;
4160 extra_limit--;
4161 }
4162 else {
4163 nolimit = 1;
4164 break;
4165 }
4166 }
4167 }
4168
4169 if (rspara && c != EOF)
4170 swallow(fptr, '\n');
4171 if (!NIL_P(str))
4172 str = io_enc_str(str, fptr);
4173 }
4174
4175 if (!NIL_P(str) && !nolimit) {
4176 fptr->lineno++;
4177 }
4178
4179 return str;
4180}
4181
4182static VALUE
4183rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4184{
4185 rb_io_t *fptr;
4186 int old_lineno, new_lineno;
4187 VALUE str;
4188
4189 GetOpenFile(io, fptr);
4190 old_lineno = fptr->lineno;
4191 str = rb_io_getline_0(rs, limit, chomp, fptr);
4192 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4193 if (io == ARGF.current_file) {
4194 ARGF.lineno += new_lineno - old_lineno;
4195 ARGF.last_lineno = ARGF.lineno;
4196 }
4197 else {
4198 ARGF.last_lineno = new_lineno;
4199 }
4200 }
4201
4202 return str;
4203}
4204
4205static VALUE
4206rb_io_getline(int argc, VALUE *argv, VALUE io)
4207{
4208 struct getline_arg args;
4209
4210 prepare_getline_args(argc, argv, &args, io);
4211 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4212}
4213
4214VALUE
4216{
4217 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4218}
4219
4220VALUE
4221rb_io_gets_internal(VALUE io)
4222{
4223 rb_io_t *fptr;
4224 GetOpenFile(io, fptr);
4225 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4226}
4227
4228/*
4229 * call-seq:
4230 * gets(sep = $/, chomp: false) -> string or nil
4231 * gets(limit, chomp: false) -> string or nil
4232 * gets(sep, limit, chomp: false) -> string or nil
4233 *
4234 * Reads and returns a line from the stream;
4235 * assigns the return value to <tt>$_</tt>.
4236 * See {Line IO}[rdoc-ref:IO@Line+IO].
4237 *
4238 * With no arguments given, returns the next line
4239 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4240 *
4241 * f = File.open('t.txt')
4242 * f.gets # => "First line\n"
4243 * $_ # => "First line\n"
4244 * f.gets # => "\n"
4245 * f.gets # => "Fourth line\n"
4246 * f.gets # => "Fifth line\n"
4247 * f.gets # => nil
4248 * f.close
4249 *
4250 * With only string argument +sep+ given,
4251 * returns the next line as determined by line separator +sep+,
4252 * or +nil+ if none;
4253 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4254 *
4255 * f = File.new('t.txt')
4256 * f.gets('l') # => "First l"
4257 * f.gets('li') # => "ine\nSecond li"
4258 * f.gets('lin') # => "ne\n\nFourth lin"
4259 * f.gets # => "e\n"
4260 * f.close
4261 *
4262 * The two special values for +sep+ are honored:
4263 *
4264 * f = File.new('t.txt')
4265 * # Get all.
4266 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4267 * f.rewind
4268 * # Get paragraph (up to two line separators).
4269 * f.gets('') # => "First line\nSecond line\n\n"
4270 * f.close
4271 *
4272 * With only integer argument +limit+ given,
4273 * limits the number of bytes in the line;
4274 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4275 *
4276 * # No more than one line.
4277 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4278 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4279 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4280 *
4281 * With arguments +sep+ and +limit+ given,
4282 * combines the two behaviors:
4283 *
4284 * - Returns the next line as determined by line separator +sep+,
4285 * or +nil+ if none.
4286 * - But returns no more bytes than are allowed by the limit.
4287 *
4288 * Optional keyword argument +chomp+ specifies whether line separators
4289 * are to be omitted:
4290 *
4291 * f = File.open('t.txt')
4292 * # Chomp the lines.
4293 * f.gets(chomp: true) # => "First line"
4294 * f.gets(chomp: true) # => "Second line"
4295 * f.gets(chomp: true) # => ""
4296 * f.gets(chomp: true) # => "Fourth line"
4297 * f.gets(chomp: true) # => "Fifth line"
4298 * f.gets(chomp: true) # => nil
4299 * f.close
4300 *
4301 */
4302
4303static VALUE
4304rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4305{
4306 VALUE str;
4307
4308 str = rb_io_getline(argc, argv, io);
4309 rb_lastline_set(str);
4310
4311 return str;
4312}
4313
4314/*
4315 * call-seq:
4316 * lineno -> integer
4317 *
4318 * Returns the current line number for the stream;
4319 * see {Line Number}[rdoc-ref:IO@Line+Number].
4320 *
4321 */
4322
4323static VALUE
4324rb_io_lineno(VALUE io)
4325{
4326 rb_io_t *fptr;
4327
4328 GetOpenFile(io, fptr);
4330 return INT2NUM(fptr->lineno);
4331}
4332
4333/*
4334 * call-seq:
4335 * lineno = integer -> integer
4336 *
4337 * Sets and returns the line number for the stream;
4338 * see {Line Number}[rdoc-ref:IO@Line+Number].
4339 *
4340 */
4341
4342static VALUE
4343rb_io_set_lineno(VALUE io, VALUE lineno)
4344{
4345 rb_io_t *fptr;
4346
4347 GetOpenFile(io, fptr);
4349 fptr->lineno = NUM2INT(lineno);
4350 return lineno;
4351}
4352
4353/*
4354 * call-seq:
4355 * readline(sep = $/, chomp: false) -> string
4356 * readline(limit, chomp: false) -> string
4357 * readline(sep, limit, chomp: false) -> string
4358 *
4359 * Reads a line as with IO#gets, but raises EOFError if already at end-of-stream.
4360 *
4361 * Optional keyword argument +chomp+ specifies whether line separators
4362 * are to be omitted.
4363 */
4364
4365static VALUE
4366rb_io_readline(int argc, VALUE *argv, VALUE io)
4367{
4368 VALUE line = rb_io_gets_m(argc, argv, io);
4369
4370 if (NIL_P(line)) {
4371 rb_eof_error();
4372 }
4373 return line;
4374}
4375
4376static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4377
4378/*
4379 * call-seq:
4380 * readlines(sep = $/, chomp: false) -> array
4381 * readlines(limit, chomp: false) -> array
4382 * readlines(sep, limit, chomp: false) -> array
4383 *
4384 * Reads and returns all remaining line from the stream;
4385 * does not modify <tt>$_</tt>.
4386 * See {Line IO}[rdoc-ref:IO@Line+IO].
4387 *
4388 * With no arguments given, returns lines
4389 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4390 *
4391 * f = File.new('t.txt')
4392 * f.readlines
4393 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4394 * f.readlines # => []
4395 * f.close
4396 *
4397 * With only string argument +sep+ given,
4398 * returns lines as determined by line separator +sep+,
4399 * or +nil+ if none;
4400 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4401 *
4402 * f = File.new('t.txt')
4403 * f.readlines('li')
4404 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4405 * f.close
4406 *
4407 * The two special values for +sep+ are honored:
4408 *
4409 * f = File.new('t.txt')
4410 * # Get all into one string.
4411 * f.readlines(nil)
4412 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4413 * # Get paragraphs (up to two line separators).
4414 * f.rewind
4415 * f.readlines('')
4416 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4417 * f.close
4418 *
4419 * With only integer argument +limit+ given,
4420 * limits the number of bytes in each line;
4421 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4422 *
4423 * f = File.new('t.txt')
4424 * f.readlines(8)
4425 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4426 * f.close
4427 *
4428 * With arguments +sep+ and +limit+ given,
4429 * combines the two behaviors:
4430 *
4431 * - Returns lines as determined by line separator +sep+.
4432 * - But returns no more bytes in a line than are allowed by the limit.
4433 *
4434 * Optional keyword argument +chomp+ specifies whether line separators
4435 * are to be omitted:
4436 *
4437 * f = File.new('t.txt')
4438 * f.readlines(chomp: true)
4439 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4440 * f.close
4441 *
4442 */
4443
4444static VALUE
4445rb_io_readlines(int argc, VALUE *argv, VALUE io)
4446{
4447 struct getline_arg args;
4448
4449 prepare_getline_args(argc, argv, &args, io);
4450 return io_readlines(&args, io);
4451}
4452
4453static VALUE
4454io_readlines(const struct getline_arg *arg, VALUE io)
4455{
4456 VALUE line, ary;
4457
4458 if (arg->limit == 0)
4459 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4460 ary = rb_ary_new();
4461 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4462 rb_ary_push(ary, line);
4463 }
4464 return ary;
4465}
4466
4467/*
4468 * call-seq:
4469 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4470 * each_line(limit, chomp: false) {|line| ... } -> self
4471 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4472 * each_line -> enumerator
4473 *
4474 * Calls the block with each remaining line read from the stream;
4475 * returns +self+.
4476 * Does nothing if already at end-of-stream;
4477 * See {Line IO}[rdoc-ref:IO@Line+IO].
4478 *
4479 * With no arguments given, reads lines
4480 * as determined by line separator <tt>$/</tt>:
4481 *
4482 * f = File.new('t.txt')
4483 * f.each_line {|line| p line }
4484 * f.each_line {|line| fail 'Cannot happen' }
4485 * f.close
4486 *
4487 * Output:
4488 *
4489 * "First line\n"
4490 * "Second line\n"
4491 * "\n"
4492 * "Fourth line\n"
4493 * "Fifth line\n"
4494 *
4495 * With only string argument +sep+ given,
4496 * reads lines as determined by line separator +sep+;
4497 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4498 *
4499 * f = File.new('t.txt')
4500 * f.each_line('li') {|line| p line }
4501 * f.close
4502 *
4503 * Output:
4504 *
4505 * "First li"
4506 * "ne\nSecond li"
4507 * "ne\n\nFourth li"
4508 * "ne\nFifth li"
4509 * "ne\n"
4510 *
4511 * The two special values for +sep+ are honored:
4512 *
4513 * f = File.new('t.txt')
4514 * # Get all into one string.
4515 * f.each_line(nil) {|line| p line }
4516 * f.close
4517 *
4518 * Output:
4519 *
4520 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4521 *
4522 * f.rewind
4523 * # Get paragraphs (up to two line separators).
4524 * f.each_line('') {|line| p line }
4525 *
4526 * Output:
4527 *
4528 * "First line\nSecond line\n\n"
4529 * "Fourth line\nFifth line\n"
4530 *
4531 * With only integer argument +limit+ given,
4532 * limits the number of bytes in each line;
4533 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4534 *
4535 * f = File.new('t.txt')
4536 * f.each_line(8) {|line| p line }
4537 * f.close
4538 *
4539 * Output:
4540 *
4541 * "First li"
4542 * "ne\n"
4543 * "Second l"
4544 * "ine\n"
4545 * "\n"
4546 * "Fourth l"
4547 * "ine\n"
4548 * "Fifth li"
4549 * "ne\n"
4550 *
4551 * With arguments +sep+ and +limit+ given,
4552 * combines the two behaviors:
4553 *
4554 * - Calls with the next line as determined by line separator +sep+.
4555 * - But returns no more bytes than are allowed by the limit.
4556 *
4557 * Optional keyword argument +chomp+ specifies whether line separators
4558 * are to be omitted:
4559 *
4560 * f = File.new('t.txt')
4561 * f.each_line(chomp: true) {|line| p line }
4562 * f.close
4563 *
4564 * Output:
4565 *
4566 * "First line"
4567 * "Second line"
4568 * ""
4569 * "Fourth line"
4570 * "Fifth line"
4571 *
4572 * Returns an Enumerator if no block is given.
4573 *
4574 * IO#each is an alias for IO#each_line.
4575 *
4576 */
4577
4578static VALUE
4579rb_io_each_line(int argc, VALUE *argv, VALUE io)
4580{
4581 VALUE str;
4582 struct getline_arg args;
4583
4584 RETURN_ENUMERATOR(io, argc, argv);
4585 prepare_getline_args(argc, argv, &args, io);
4586 if (args.limit == 0)
4587 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4588 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4589 rb_yield(str);
4590 }
4591 return io;
4592}
4593
4594/*
4595 * call-seq:
4596 * each_byte {|byte| ... } -> self
4597 * each_byte -> enumerator
4598 *
4599 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4600 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4601 *
4602 * f = File.new('t.rus')
4603 * a = []
4604 * f.each_byte {|b| a << b }
4605 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4606 * f.close
4607 *
4608 * Returns an Enumerator if no block is given.
4609 *
4610 * Related: IO#each_char, IO#each_codepoint.
4611 *
4612 */
4613
4614static VALUE
4615rb_io_each_byte(VALUE io)
4616{
4617 rb_io_t *fptr;
4618
4619 RETURN_ENUMERATOR(io, 0, 0);
4620 GetOpenFile(io, fptr);
4621
4622 do {
4623 while (fptr->rbuf.len > 0) {
4624 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4625 fptr->rbuf.len--;
4626 rb_yield(INT2FIX(*p & 0xff));
4628 errno = 0;
4629 }
4630 READ_CHECK(fptr);
4631 } while (io_fillbuf(fptr) >= 0);
4632 return io;
4633}
4634
4635static VALUE
4636io_getc(rb_io_t *fptr, rb_encoding *enc)
4637{
4638 int r, n, cr = 0;
4639 VALUE str;
4640
4641 if (NEED_READCONV(fptr)) {
4642 rb_encoding *read_enc = io_read_encoding(fptr);
4643
4644 str = Qnil;
4645 SET_BINARY_MODE(fptr);
4646 make_readconv(fptr, 0);
4647
4648 while (1) {
4649 if (fptr->cbuf.len) {
4650 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4651 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4652 read_enc);
4653 if (!MBCLEN_NEEDMORE_P(r))
4654 break;
4655 if (fptr->cbuf.len == fptr->cbuf.capa) {
4656 rb_raise(rb_eIOError, "too long character");
4657 }
4658 }
4659
4660 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4661 if (fptr->cbuf.len == 0) {
4662 clear_readconv(fptr);
4663 return Qnil;
4664 }
4665 /* return an unit of an incomplete character just before EOF */
4666 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4667 fptr->cbuf.off += 1;
4668 fptr->cbuf.len -= 1;
4669 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4671 return str;
4672 }
4673 }
4674 if (MBCLEN_INVALID_P(r)) {
4675 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4676 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4677 read_enc);
4678 io_shift_cbuf(fptr, r, &str);
4680 }
4681 else {
4682 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4684 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4685 ISASCII(RSTRING_PTR(str)[0])) {
4686 cr = ENC_CODERANGE_7BIT;
4687 }
4688 }
4689 str = io_enc_str(str, fptr);
4690 ENC_CODERANGE_SET(str, cr);
4691 return str;
4692 }
4693
4694 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4695 if (io_fillbuf(fptr) < 0) {
4696 return Qnil;
4697 }
4698 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4699 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4700 fptr->rbuf.off += 1;
4701 fptr->rbuf.len -= 1;
4702 cr = ENC_CODERANGE_7BIT;
4703 }
4704 else {
4705 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4706 if (MBCLEN_CHARFOUND_P(r) &&
4707 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4708 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4709 fptr->rbuf.off += n;
4710 fptr->rbuf.len -= n;
4712 }
4713 else if (MBCLEN_NEEDMORE_P(r)) {
4714 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4715 fptr->rbuf.len = 0;
4716 getc_needmore:
4717 if (io_fillbuf(fptr) != -1) {
4718 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4719 fptr->rbuf.off++;
4720 fptr->rbuf.len--;
4721 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4722 if (MBCLEN_NEEDMORE_P(r)) {
4723 goto getc_needmore;
4724 }
4725 else if (MBCLEN_CHARFOUND_P(r)) {
4727 }
4728 }
4729 }
4730 else {
4731 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4732 fptr->rbuf.off++;
4733 fptr->rbuf.len--;
4734 }
4735 }
4736 if (!cr) cr = ENC_CODERANGE_BROKEN;
4737 str = io_enc_str(str, fptr);
4738 ENC_CODERANGE_SET(str, cr);
4739 return str;
4740}
4741
4742/*
4743 * call-seq:
4744 * each_char {|c| ... } -> self
4745 * each_char -> enumerator
4746 *
4747 * Calls the given block with each character in the stream; returns +self+.
4748 * See {Character IO}[rdoc-ref:IO@Character+IO].
4749 *
4750 * f = File.new('t.rus')
4751 * a = []
4752 * f.each_char {|c| a << c.ord }
4753 * a # => [1090, 1077, 1089, 1090]
4754 * f.close
4755 *
4756 * Returns an Enumerator if no block is given.
4757 *
4758 * Related: IO#each_byte, IO#each_codepoint.
4759 *
4760 */
4761
4762static VALUE
4763rb_io_each_char(VALUE io)
4764{
4765 rb_io_t *fptr;
4766 rb_encoding *enc;
4767 VALUE c;
4768
4769 RETURN_ENUMERATOR(io, 0, 0);
4770 GetOpenFile(io, fptr);
4772
4773 enc = io_input_encoding(fptr);
4774 READ_CHECK(fptr);
4775 while (!NIL_P(c = io_getc(fptr, enc))) {
4776 rb_yield(c);
4777 }
4778 return io;
4779}
4780
4781/*
4782 * call-seq:
4783 * each_codepoint {|c| ... } -> self
4784 * each_codepoint -> enumerator
4785 *
4786 * Calls the given block with each codepoint in the stream; returns +self+:
4787 *
4788 * f = File.new('t.rus')
4789 * a = []
4790 * f.each_codepoint {|c| a << c }
4791 * a # => [1090, 1077, 1089, 1090]
4792 * f.close
4793 *
4794 * Returns an Enumerator if no block is given.
4795 *
4796 * Related: IO#each_byte, IO#each_char.
4797 *
4798 */
4799
4800static VALUE
4801rb_io_each_codepoint(VALUE io)
4802{
4803 rb_io_t *fptr;
4804 rb_encoding *enc;
4805 unsigned int c;
4806 int r, n;
4807
4808 RETURN_ENUMERATOR(io, 0, 0);
4809 GetOpenFile(io, fptr);
4811
4812 READ_CHECK(fptr);
4813 if (NEED_READCONV(fptr)) {
4814 SET_BINARY_MODE(fptr);
4815 r = 1; /* no invalid char yet */
4816 for (;;) {
4817 make_readconv(fptr, 0);
4818 for (;;) {
4819 if (fptr->cbuf.len) {
4820 if (fptr->encs.enc)
4821 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4822 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4823 fptr->encs.enc);
4824 else
4825 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4826 if (!MBCLEN_NEEDMORE_P(r))
4827 break;
4828 if (fptr->cbuf.len == fptr->cbuf.capa) {
4829 rb_raise(rb_eIOError, "too long character");
4830 }
4831 }
4832 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4833 clear_readconv(fptr);
4834 if (!MBCLEN_CHARFOUND_P(r)) {
4835 enc = fptr->encs.enc;
4836 goto invalid;
4837 }
4838 return io;
4839 }
4840 }
4841 if (MBCLEN_INVALID_P(r)) {
4842 enc = fptr->encs.enc;
4843 goto invalid;
4844 }
4845 n = MBCLEN_CHARFOUND_LEN(r);
4846 if (fptr->encs.enc) {
4847 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4848 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4849 fptr->encs.enc);
4850 }
4851 else {
4852 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4853 }
4854 fptr->cbuf.off += n;
4855 fptr->cbuf.len -= n;
4856 rb_yield(UINT2NUM(c));
4858 }
4859 }
4860 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4861 enc = io_input_encoding(fptr);
4862 while (io_fillbuf(fptr) >= 0) {
4863 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4864 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4865 if (MBCLEN_CHARFOUND_P(r) &&
4866 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4867 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4868 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4869 fptr->rbuf.off += n;
4870 fptr->rbuf.len -= n;
4871 rb_yield(UINT2NUM(c));
4872 }
4873 else if (MBCLEN_INVALID_P(r)) {
4874 goto invalid;
4875 }
4876 else if (MBCLEN_NEEDMORE_P(r)) {
4877 char cbuf[8], *p = cbuf;
4878 int more = MBCLEN_NEEDMORE_LEN(r);
4879 if (more > numberof(cbuf)) goto invalid;
4880 more += n = fptr->rbuf.len;
4881 if (more > numberof(cbuf)) goto invalid;
4882 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4883 (p += n, (more -= n) > 0)) {
4884 if (io_fillbuf(fptr) < 0) goto invalid;
4885 if ((n = fptr->rbuf.len) > more) n = more;
4886 }
4887 r = rb_enc_precise_mbclen(cbuf, p, enc);
4888 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4889 c = rb_enc_codepoint(cbuf, p, enc);
4890 rb_yield(UINT2NUM(c));
4891 }
4892 else {
4893 continue;
4894 }
4896 }
4897 return io;
4898
4899 invalid:
4900 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4902}
4903
4904/*
4905 * call-seq:
4906 * getc -> character or nil
4907 *
4908 * Reads and returns the next 1-character string from the stream;
4909 * returns +nil+ if already at end-of-stream.
4910 * See {Character IO}[rdoc-ref:IO@Character+IO].
4911 *
4912 * f = File.open('t.txt')
4913 * f.getc # => "F"
4914 * f.close
4915 * f = File.open('t.rus')
4916 * f.getc.ord # => 1090
4917 * f.close
4918 *
4919 * Related: IO#readchar (may raise EOFError).
4920 *
4921 */
4922
4923static VALUE
4924rb_io_getc(VALUE io)
4925{
4926 rb_io_t *fptr;
4927 rb_encoding *enc;
4928
4929 GetOpenFile(io, fptr);
4931
4932 enc = io_input_encoding(fptr);
4933 READ_CHECK(fptr);
4934 return io_getc(fptr, enc);
4935}
4936
4937/*
4938 * call-seq:
4939 * readchar -> string
4940 *
4941 * Reads and returns the next 1-character string from the stream;
4942 * raises EOFError if already at end-of-stream.
4943 * See {Character IO}[rdoc-ref:IO@Character+IO].
4944 *
4945 * f = File.open('t.txt')
4946 * f.readchar # => "F"
4947 * f.close
4948 * f = File.open('t.rus')
4949 * f.readchar.ord # => 1090
4950 * f.close
4951 *
4952 * Related: IO#getc (will not raise EOFError).
4953 *
4954 */
4955
4956static VALUE
4957rb_io_readchar(VALUE io)
4958{
4959 VALUE c = rb_io_getc(io);
4960
4961 if (NIL_P(c)) {
4962 rb_eof_error();
4963 }
4964 return c;
4965}
4966
4967/*
4968 * call-seq:
4969 * getbyte -> integer or nil
4970 *
4971 * Reads and returns the next byte (in range 0..255) from the stream;
4972 * returns +nil+ if already at end-of-stream.
4973 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4974 *
4975 * f = File.open('t.txt')
4976 * f.getbyte # => 70
4977 * f.close
4978 * f = File.open('t.rus')
4979 * f.getbyte # => 209
4980 * f.close
4981 *
4982 * Related: IO#readbyte (may raise EOFError).
4983 */
4984
4985VALUE
4987{
4988 rb_io_t *fptr;
4989 int c;
4990
4991 GetOpenFile(io, fptr);
4993 READ_CHECK(fptr);
4994 VALUE r_stdout = rb_ractor_stdout();
4995 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
4996 rb_io_t *ofp;
4997 GetOpenFile(r_stdout, ofp);
4998 if (ofp->mode & FMODE_TTY) {
4999 rb_io_flush(r_stdout);
5000 }
5001 }
5002 if (io_fillbuf(fptr) < 0) {
5003 return Qnil;
5004 }
5005 fptr->rbuf.off++;
5006 fptr->rbuf.len--;
5007 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5008 return INT2FIX(c & 0xff);
5009}
5010
5011/*
5012 * call-seq:
5013 * readbyte -> integer
5014 *
5015 * Reads and returns the next byte (in range 0..255) from the stream;
5016 * raises EOFError if already at end-of-stream.
5017 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5018 *
5019 * f = File.open('t.txt')
5020 * f.readbyte # => 70
5021 * f.close
5022 * f = File.open('t.rus')
5023 * f.readbyte # => 209
5024 * f.close
5025 *
5026 * Related: IO#getbyte (will not raise EOFError).
5027 *
5028 */
5029
5030static VALUE
5031rb_io_readbyte(VALUE io)
5032{
5033 VALUE c = rb_io_getbyte(io);
5034
5035 if (NIL_P(c)) {
5036 rb_eof_error();
5037 }
5038 return c;
5039}
5040
5041/*
5042 * call-seq:
5043 * ungetbyte(integer) -> nil
5044 * ungetbyte(string) -> nil
5045 *
5046 * Pushes back ("unshifts") the given data onto the stream's buffer,
5047 * placing the data so that it is next to be read; returns +nil+.
5048 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5049 *
5050 * Note that:
5051 *
5052 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5053 * - Calling #rewind on the stream discards the pushed-back data.
5054 *
5055 * When argument +integer+ is given, uses only its low-order byte:
5056 *
5057 * File.write('t.tmp', '012')
5058 * f = File.open('t.tmp')
5059 * f.ungetbyte(0x41) # => nil
5060 * f.read # => "A012"
5061 * f.rewind
5062 * f.ungetbyte(0x4243) # => nil
5063 * f.read # => "C012"
5064 * f.close
5065 *
5066 * When argument +string+ is given, uses all bytes:
5067 *
5068 * File.write('t.tmp', '012')
5069 * f = File.open('t.tmp')
5070 * f.ungetbyte('A') # => nil
5071 * f.read # => "A012"
5072 * f.rewind
5073 * f.ungetbyte('BCDE') # => nil
5074 * f.read # => "BCDE012"
5075 * f.close
5076 *
5077 */
5078
5079VALUE
5081{
5082 rb_io_t *fptr;
5083
5084 GetOpenFile(io, fptr);
5086 switch (TYPE(b)) {
5087 case T_NIL:
5088 return Qnil;
5089 case T_FIXNUM:
5090 case T_BIGNUM: ;
5091 VALUE v = rb_int_modulo(b, INT2FIX(256));
5092 unsigned char c = NUM2INT(v) & 0xFF;
5093 b = rb_str_new((const char *)&c, 1);
5094 break;
5095 default:
5096 SafeStringValue(b);
5097 }
5098 io_ungetbyte(b, fptr);
5099 return Qnil;
5100}
5101
5102/*
5103 * call-seq:
5104 * ungetc(integer) -> nil
5105 * ungetc(string) -> nil
5106 *
5107 * Pushes back ("unshifts") the given data onto the stream's buffer,
5108 * placing the data so that it is next to be read; returns +nil+.
5109 * See {Character IO}[rdoc-ref:IO@Character+IO].
5110 *
5111 * Note that:
5112 *
5113 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5114 * - Calling #rewind on the stream discards the pushed-back data.
5115 *
5116 * When argument +integer+ is given, interprets the integer as a character:
5117 *
5118 * File.write('t.tmp', '012')
5119 * f = File.open('t.tmp')
5120 * f.ungetc(0x41) # => nil
5121 * f.read # => "A012"
5122 * f.rewind
5123 * f.ungetc(0x0442) # => nil
5124 * f.getc.ord # => 1090
5125 * f.close
5126 *
5127 * When argument +string+ is given, uses all characters:
5128 *
5129 * File.write('t.tmp', '012')
5130 * f = File.open('t.tmp')
5131 * f.ungetc('A') # => nil
5132 * f.read # => "A012"
5133 * f.rewind
5134 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5135 * f.getc.ord # => 1090
5136 * f.getc.ord # => 1077
5137 * f.getc.ord # => 1089
5138 * f.getc.ord # => 1090
5139 * f.close
5140 *
5141 */
5142
5143VALUE
5145{
5146 rb_io_t *fptr;
5147 long len;
5148
5149 GetOpenFile(io, fptr);
5151 if (FIXNUM_P(c)) {
5152 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5153 }
5154 else if (RB_BIGNUM_TYPE_P(c)) {
5155 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5156 }
5157 else {
5158 SafeStringValue(c);
5159 }
5160 if (NEED_READCONV(fptr)) {
5161 SET_BINARY_MODE(fptr);
5162 len = RSTRING_LEN(c);
5163#if SIZEOF_LONG > SIZEOF_INT
5164 if (len > INT_MAX)
5165 rb_raise(rb_eIOError, "ungetc failed");
5166#endif
5167 make_readconv(fptr, (int)len);
5168 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5169 rb_raise(rb_eIOError, "ungetc failed");
5170 if (fptr->cbuf.off < len) {
5171 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5172 fptr->cbuf.ptr+fptr->cbuf.off,
5173 char, fptr->cbuf.len);
5174 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5175 }
5176 fptr->cbuf.off -= (int)len;
5177 fptr->cbuf.len += (int)len;
5178 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5179 }
5180 else {
5181 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5182 io_ungetbyte(c, fptr);
5183 }
5184 return Qnil;
5185}
5186
5187/*
5188 * call-seq:
5189 * isatty -> true or false
5190 *
5191 * Returns +true+ if the stream is associated with a terminal device (tty),
5192 * +false+ otherwise:
5193 *
5194 * f = File.new('t.txt').isatty #=> false
5195 * f.close
5196 * f = File.new('/dev/tty').isatty #=> true
5197 * f.close
5198 *
5199 * IO#tty? is an alias for IO#isatty.
5200 *
5201 */
5202
5203static VALUE
5204rb_io_isatty(VALUE io)
5205{
5206 rb_io_t *fptr;
5207
5208 GetOpenFile(io, fptr);
5209 return RBOOL(isatty(fptr->fd) != 0);
5210}
5211
5212#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5213/*
5214 * call-seq:
5215 * close_on_exec? -> true or false
5216 *
5217 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5218 *
5219 * f = File.open('t.txt')
5220 * f.close_on_exec? # => true
5221 * f.close_on_exec = false
5222 * f.close_on_exec? # => false
5223 * f.close
5224 *
5225 */
5226
5227static VALUE
5228rb_io_close_on_exec_p(VALUE io)
5229{
5230 rb_io_t *fptr;
5231 VALUE write_io;
5232 int fd, ret;
5233
5234 write_io = GetWriteIO(io);
5235 if (io != write_io) {
5236 GetOpenFile(write_io, fptr);
5237 if (fptr && 0 <= (fd = fptr->fd)) {
5238 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5239 if (!(ret & FD_CLOEXEC)) return Qfalse;
5240 }
5241 }
5242
5243 GetOpenFile(io, fptr);
5244 if (fptr && 0 <= (fd = fptr->fd)) {
5245 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5246 if (!(ret & FD_CLOEXEC)) return Qfalse;
5247 }
5248 return Qtrue;
5249}
5250#else
5251#define rb_io_close_on_exec_p rb_f_notimplement
5252#endif
5253
5254#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5255/*
5256 * call-seq:
5257 * self.close_on_exec = bool -> true or false
5258 *
5259 * Sets a close-on-exec flag.
5260 *
5261 * f = open("/dev/null")
5262 * f.close_on_exec = true
5263 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5264 * f.closed? #=> false
5265 *
5266 * Ruby sets close-on-exec flags of all file descriptors by default
5267 * since Ruby 2.0.0.
5268 * So you don't need to set by yourself.
5269 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5270 * if another thread use fork() and exec() (via system() method for example).
5271 * If you really needs file descriptor inheritance to child process,
5272 * use spawn()'s argument such as fd=>fd.
5273 */
5274
5275static VALUE
5276rb_io_set_close_on_exec(VALUE io, VALUE arg)
5277{
5278 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5279 rb_io_t *fptr;
5280 VALUE write_io;
5281 int fd, ret;
5282
5283 write_io = GetWriteIO(io);
5284 if (io != write_io) {
5285 GetOpenFile(write_io, fptr);
5286 if (fptr && 0 <= (fd = fptr->fd)) {
5287 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5288 if ((ret & FD_CLOEXEC) != flag) {
5289 ret = (ret & ~FD_CLOEXEC) | flag;
5290 ret = fcntl(fd, F_SETFD, ret);
5291 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5292 }
5293 }
5294
5295 }
5296
5297 GetOpenFile(io, fptr);
5298 if (fptr && 0 <= (fd = fptr->fd)) {
5299 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5300 if ((ret & FD_CLOEXEC) != flag) {
5301 ret = (ret & ~FD_CLOEXEC) | flag;
5302 ret = fcntl(fd, F_SETFD, ret);
5303 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5304 }
5305 }
5306 return Qnil;
5307}
5308#else
5309#define rb_io_set_close_on_exec rb_f_notimplement
5310#endif
5311
5312#define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
5313#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5314
5315static VALUE
5316finish_writeconv(rb_io_t *fptr, int noalloc)
5317{
5318 unsigned char *ds, *dp, *de;
5320
5321 if (!fptr->wbuf.ptr) {
5322 unsigned char buf[1024];
5323
5325 while (res == econv_destination_buffer_full) {
5326 ds = dp = buf;
5327 de = buf + sizeof(buf);
5328 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5329 while (dp-ds) {
5330 size_t remaining = dp-ds;
5331 long result = rb_io_write_memory(fptr, ds, remaining);
5332
5333 if (result > 0) {
5334 ds += result;
5335 if ((size_t)result == remaining) break;
5336 }
5337 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5338 if (fptr->fd < 0)
5339 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5340 }
5341 else {
5342 return noalloc ? Qtrue : INT2NUM(errno);
5343 }
5344 }
5345 if (res == econv_invalid_byte_sequence ||
5346 res == econv_incomplete_input ||
5348 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5349 }
5350 }
5351
5352 return Qnil;
5353 }
5354
5356 while (res == econv_destination_buffer_full) {
5357 if (fptr->wbuf.len == fptr->wbuf.capa) {
5358 if (io_fflush(fptr) < 0) {
5359 return noalloc ? Qtrue : INT2NUM(errno);
5360 }
5361 }
5362
5363 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5364 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5365 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5366 fptr->wbuf.len += (int)(dp - ds);
5367 if (res == econv_invalid_byte_sequence ||
5368 res == econv_incomplete_input ||
5370 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5371 }
5372 }
5373 return Qnil;
5374}
5375
5377 rb_io_t *fptr;
5378 int noalloc;
5379};
5380
5381static VALUE
5382finish_writeconv_sync(VALUE arg)
5383{
5384 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5385 return finish_writeconv(p->fptr, p->noalloc);
5386}
5387
5388static void*
5389nogvl_close(void *ptr)
5390{
5391 int *fd = ptr;
5392
5393 return (void*)(intptr_t)close(*fd);
5394}
5395
5396static int
5397maygvl_close(int fd, int keepgvl)
5398{
5399 if (keepgvl)
5400 return close(fd);
5401
5402 /*
5403 * close() may block for certain file types (NFS, SO_LINGER sockets,
5404 * inotify), so let other threads run.
5405 */
5406 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
5407}
5408
5409static void*
5410nogvl_fclose(void *ptr)
5411{
5412 FILE *file = ptr;
5413
5414 return (void*)(intptr_t)fclose(file);
5415}
5416
5417static int
5418maygvl_fclose(FILE *file, int keepgvl)
5419{
5420 if (keepgvl)
5421 return fclose(file);
5422
5423 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
5424}
5425
5426static void free_io_buffer(rb_io_buffer_t *buf);
5427static void clear_codeconv(rb_io_t *fptr);
5428
5429static void
5430fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5431 struct ccan_list_head *busy)
5432{
5433 VALUE error = Qnil;
5434 int fd = fptr->fd;
5435 FILE *stdio_file = fptr->stdio_file;
5436 int mode = fptr->mode;
5437
5438 if (fptr->writeconv) {
5439 if (!NIL_P(fptr->write_lock) && !noraise) {
5440 struct finish_writeconv_arg arg;
5441 arg.fptr = fptr;
5442 arg.noalloc = noraise;
5443 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5444 }
5445 else {
5446 error = finish_writeconv(fptr, noraise);
5447 }
5448 }
5449 if (fptr->wbuf.len) {
5450 if (noraise) {
5451 io_flush_buffer_sync(fptr);
5452 }
5453 else {
5454 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5455 error = INT2NUM(errno);
5456 }
5457 }
5458 }
5459
5460 int done = 0;
5461
5462 if (IS_PREP_STDIO(fptr) || fd <= 2) {
5463 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5464 done = 1;
5465 }
5466
5467 fptr->fd = -1;
5468 fptr->stdio_file = 0;
5470
5471 // Ensure waiting_fd users do not hit EBADF.
5472 if (busy) {
5473 // Wait for them to exit before we call close().
5474 do rb_thread_schedule(); while (!ccan_list_empty(busy));
5475 }
5476
5477 // Disable for now.
5478 // if (!done && fd >= 0) {
5479 // VALUE scheduler = rb_fiber_scheduler_current();
5480 // if (scheduler != Qnil) {
5481 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5482 // if (!UNDEF_P(result)) done = 1;
5483 // }
5484 // }
5485
5486 if (!done && stdio_file) {
5487 // stdio_file is deallocated anyway even if fclose failed.
5488 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5489 if (!noraise) {
5490 error = INT2NUM(errno);
5491 }
5492 }
5493
5494 done = 1;
5495 }
5496
5497 if (!done && fd >= 0) {
5498 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5499 // We assumes it is closed.
5500
5501 keepgvl |= !(mode & FMODE_WRITABLE);
5502 keepgvl |= noraise;
5503 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5504 if (!noraise) {
5505 error = INT2NUM(errno);
5506 }
5507 }
5508
5509 done = 1;
5510 }
5511
5512 if (!NIL_P(error) && !noraise) {
5513 if (RB_INTEGER_TYPE_P(error))
5514 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5515 else
5516 rb_exc_raise(error);
5517 }
5518}
5519
5520static void
5521fptr_finalize(rb_io_t *fptr, int noraise)
5522{
5523 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5524 free_io_buffer(&fptr->rbuf);
5525 free_io_buffer(&fptr->wbuf);
5526 clear_codeconv(fptr);
5527}
5528
5529static void
5530rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5531{
5532 if (fptr->finalize) {
5533 (*fptr->finalize)(fptr, noraise);
5534 }
5535 else {
5536 fptr_finalize(fptr, noraise);
5537 }
5538}
5539
5540static void
5541free_io_buffer(rb_io_buffer_t *buf)
5542{
5543 if (buf->ptr) {
5544 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5545 buf->ptr = NULL;
5546 }
5547}
5548
5549static void
5550clear_readconv(rb_io_t *fptr)
5551{
5552 if (fptr->readconv) {
5553 rb_econv_close(fptr->readconv);
5554 fptr->readconv = NULL;
5555 }
5556 free_io_buffer(&fptr->cbuf);
5557}
5558
5559static void
5560clear_writeconv(rb_io_t *fptr)
5561{
5562 if (fptr->writeconv) {
5564 fptr->writeconv = NULL;
5565 }
5566 fptr->writeconv_initialized = 0;
5567}
5568
5569static void
5570clear_codeconv(rb_io_t *fptr)
5571{
5572 clear_readconv(fptr);
5573 clear_writeconv(fptr);
5574}
5575
5576void
5577rb_io_fptr_finalize_internal(void *ptr)
5578{
5579 rb_io_t *fptr = ptr;
5580
5581 if (!ptr) return;
5582 fptr->pathv = Qnil;
5583 if (0 <= fptr->fd)
5584 rb_io_fptr_cleanup(fptr, TRUE);
5585 fptr->write_lock = Qnil;
5586 free_io_buffer(&fptr->rbuf);
5587 free_io_buffer(&fptr->wbuf);
5588 clear_codeconv(fptr);
5589 free(fptr);
5590}
5591
5592#undef rb_io_fptr_finalize
5593int
5594rb_io_fptr_finalize(rb_io_t *fptr)
5595{
5596 if (!fptr) {
5597 return 0;
5598 }
5599 else {
5600 rb_io_fptr_finalize_internal(fptr);
5601 return 1;
5602 }
5603}
5604#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5605
5606RUBY_FUNC_EXPORTED size_t
5607rb_io_memsize(const rb_io_t *fptr)
5608{
5609 size_t size = sizeof(rb_io_t);
5610 size += fptr->rbuf.capa;
5611 size += fptr->wbuf.capa;
5612 size += fptr->cbuf.capa;
5613 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5614 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5615 return size;
5616}
5617
5618#ifdef _WIN32
5619/* keep GVL while closing to prevent crash on Windows */
5620# define KEEPGVL TRUE
5621#else
5622# define KEEPGVL FALSE
5623#endif
5624
5625int rb_notify_fd_close(int fd, struct ccan_list_head *);
5626static rb_io_t *
5627io_close_fptr(VALUE io)
5628{
5629 rb_io_t *fptr;
5630 VALUE write_io;
5631 rb_io_t *write_fptr;
5632 struct ccan_list_head busy;
5633
5634 ccan_list_head_init(&busy);
5635 write_io = GetWriteIO(io);
5636 if (io != write_io) {
5637 write_fptr = RFILE(write_io)->fptr;
5638 if (write_fptr && 0 <= write_fptr->fd) {
5639 rb_io_fptr_cleanup(write_fptr, TRUE);
5640 }
5641 }
5642
5643 fptr = RFILE(io)->fptr;
5644 if (!fptr) return 0;
5645 if (fptr->fd < 0) return 0;
5646
5647 if (rb_notify_fd_close(fptr->fd, &busy)) {
5648 /* calls close(fptr->fd): */
5649 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5650 }
5651 rb_io_fptr_cleanup(fptr, FALSE);
5652 return fptr;
5653}
5654
5655static void
5656fptr_waitpid(rb_io_t *fptr, int nohang)
5657{
5658 int status;
5659 if (fptr->pid) {
5660 rb_last_status_clear();
5661 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5662 fptr->pid = 0;
5663 }
5664}
5665
5666VALUE
5668{
5669 rb_io_t *fptr = io_close_fptr(io);
5670 if (fptr) fptr_waitpid(fptr, 0);
5671 return Qnil;
5672}
5673
5674/*
5675 * call-seq:
5676 * close -> nil
5677 *
5678 * Closes the stream for both reading and writing
5679 * if open for either or both; returns +nil+.
5680 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5681 *
5682 * If the stream is open for writing, flushes any buffered writes
5683 * to the operating system before closing.
5684 *
5685 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5686 * (child exit status).
5687 *
5688 * Example:
5689 *
5690 * IO.popen('ruby', 'r+') do |pipe|
5691 * puts pipe.closed?
5692 * pipe.close
5693 * puts $?
5694 * puts pipe.closed?
5695 * end
5696 *
5697 * Output:
5698 *
5699 * false
5700 * pid 13760 exit 0
5701 * true
5702 *
5703 * Related: IO#close_read, IO#close_write, IO#closed?.
5704 */
5705
5706static VALUE
5707rb_io_close_m(VALUE io)
5708{
5709 rb_io_t *fptr = rb_io_get_fptr(io);
5710 if (fptr->fd < 0) {
5711 return Qnil;
5712 }
5713 rb_io_close(io);
5714 return Qnil;
5715}
5716
5717static VALUE
5718io_call_close(VALUE io)
5719{
5720 rb_check_funcall(io, rb_intern("close"), 0, 0);
5721 return io;
5722}
5723
5724static VALUE
5725ignore_closed_stream(VALUE io, VALUE exc)
5726{
5727 enum {mesg_len = sizeof(closed_stream)-1};
5728 VALUE mesg = rb_attr_get(exc, idMesg);
5729 if (!RB_TYPE_P(mesg, T_STRING) ||
5730 RSTRING_LEN(mesg) != mesg_len ||
5731 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5732 rb_exc_raise(exc);
5733 }
5734 return io;
5735}
5736
5737static VALUE
5738io_close(VALUE io)
5739{
5740 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5741 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5742 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5743 rb_eIOError, (VALUE)0);
5744 return io;
5745}
5746
5747/*
5748 * call-seq:
5749 * closed? -> true or false
5750 *
5751 * Returns +true+ if the stream is closed for both reading and writing,
5752 * +false+ otherwise.
5753 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5754 *
5755 * IO.popen('ruby', 'r+') do |pipe|
5756 * puts pipe.closed?
5757 * pipe.close_read
5758 * puts pipe.closed?
5759 * pipe.close_write
5760 * puts pipe.closed?
5761 * end
5762 *
5763 * Output:
5764 *
5765 * false
5766 * false
5767 * true
5768 *
5769 * Related: IO#close_read, IO#close_write, IO#close.
5770 */
5771
5772
5773static VALUE
5774rb_io_closed(VALUE io)
5775{
5776 rb_io_t *fptr;
5777 VALUE write_io;
5778 rb_io_t *write_fptr;
5779
5780 write_io = GetWriteIO(io);
5781 if (io != write_io) {
5782 write_fptr = RFILE(write_io)->fptr;
5783 if (write_fptr && 0 <= write_fptr->fd) {
5784 return Qfalse;
5785 }
5786 }
5787
5788 fptr = rb_io_get_fptr(io);
5789 return RBOOL(0 > fptr->fd);
5790}
5791
5792/*
5793 * call-seq:
5794 * close_read -> nil
5795 *
5796 * Closes the stream for reading if open for reading;
5797 * returns +nil+.
5798 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5799 *
5800 * If the stream was opened by IO.popen and is also closed for writing,
5801 * sets global variable <tt>$?</tt> (child exit status).
5802 *
5803 * Example:
5804 *
5805 * IO.popen('ruby', 'r+') do |pipe|
5806 * puts pipe.closed?
5807 * pipe.close_write
5808 * puts pipe.closed?
5809 * pipe.close_read
5810 * puts $?
5811 * puts pipe.closed?
5812 * end
5813 *
5814 * Output:
5815 *
5816 * false
5817 * false
5818 * pid 14748 exit 0
5819 * true
5820 *
5821 * Related: IO#close, IO#close_write, IO#closed?.
5822 */
5823
5824static VALUE
5825rb_io_close_read(VALUE io)
5826{
5827 rb_io_t *fptr;
5828 VALUE write_io;
5829
5830 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5831 if (fptr->fd < 0) return Qnil;
5832 if (is_socket(fptr->fd, fptr->pathv)) {
5833#ifndef SHUT_RD
5834# define SHUT_RD 0
5835#endif
5836 if (shutdown(fptr->fd, SHUT_RD) < 0)
5837 rb_sys_fail_path(fptr->pathv);
5838 fptr->mode &= ~FMODE_READABLE;
5839 if (!(fptr->mode & FMODE_WRITABLE))
5840 return rb_io_close(io);
5841 return Qnil;
5842 }
5843
5844 write_io = GetWriteIO(io);
5845 if (io != write_io) {
5846 rb_io_t *wfptr;
5847 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5848 wfptr->pid = fptr->pid;
5849 fptr->pid = 0;
5850 RFILE(io)->fptr = wfptr;
5851 /* bind to write_io temporarily to get rid of memory/fd leak */
5852 fptr->tied_io_for_writing = 0;
5853 RFILE(write_io)->fptr = fptr;
5854 rb_io_fptr_cleanup(fptr, FALSE);
5855 /* should not finalize fptr because another thread may be reading it */
5856 return Qnil;
5857 }
5858
5859 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5860 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5861 }
5862 return rb_io_close(io);
5863}
5864
5865/*
5866 * call-seq:
5867 * close_write -> nil
5868 *
5869 * Closes the stream for writing if open for writing;
5870 * returns +nil+.
5871 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5872 *
5873 * Flushes any buffered writes to the operating system before closing.
5874 *
5875 * If the stream was opened by IO.popen and is also closed for reading,
5876 * sets global variable <tt>$?</tt> (child exit status).
5877 *
5878 * IO.popen('ruby', 'r+') do |pipe|
5879 * puts pipe.closed?
5880 * pipe.close_read
5881 * puts pipe.closed?
5882 * pipe.close_write
5883 * puts $?
5884 * puts pipe.closed?
5885 * end
5886 *
5887 * Output:
5888 *
5889 * false
5890 * false
5891 * pid 15044 exit 0
5892 * true
5893 *
5894 * Related: IO#close, IO#close_read, IO#closed?.
5895 */
5896
5897static VALUE
5898rb_io_close_write(VALUE io)
5899{
5900 rb_io_t *fptr;
5901 VALUE write_io;
5902
5903 write_io = GetWriteIO(io);
5904 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5905 if (fptr->fd < 0) return Qnil;
5906 if (is_socket(fptr->fd, fptr->pathv)) {
5907#ifndef SHUT_WR
5908# define SHUT_WR 1
5909#endif
5910 if (shutdown(fptr->fd, SHUT_WR) < 0)
5911 rb_sys_fail_path(fptr->pathv);
5912 fptr->mode &= ~FMODE_WRITABLE;
5913 if (!(fptr->mode & FMODE_READABLE))
5914 return rb_io_close(write_io);
5915 return Qnil;
5916 }
5917
5918 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
5919 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
5920 }
5921
5922 if (io != write_io) {
5923 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5924 fptr->tied_io_for_writing = 0;
5925 }
5926 rb_io_close(write_io);
5927 return Qnil;
5928}
5929
5930/*
5931 * call-seq:
5932 * sysseek(offset, whence = IO::SEEK_SET) -> integer
5933 *
5934 * Behaves like IO#seek, except that it:
5935 *
5936 * - Uses low-level system functions.
5937 * - Returns the new position.
5938 *
5939 */
5940
5941static VALUE
5942rb_io_sysseek(int argc, VALUE *argv, VALUE io)
5943{
5944 VALUE offset, ptrname;
5945 int whence = SEEK_SET;
5946 rb_io_t *fptr;
5947 rb_off_t pos;
5948
5949 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
5950 whence = interpret_seek_whence(ptrname);
5951 }
5952 pos = NUM2OFFT(offset);
5953 GetOpenFile(io, fptr);
5954 if ((fptr->mode & FMODE_READABLE) &&
5955 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5956 rb_raise(rb_eIOError, "sysseek for buffered IO");
5957 }
5958 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
5959 rb_warn("sysseek for buffered IO");
5960 }
5961 errno = 0;
5962 pos = lseek(fptr->fd, pos, whence);
5963 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
5964
5965 return OFFT2NUM(pos);
5966}
5967
5968/*
5969 * call-seq:
5970 * syswrite(object) -> integer
5971 *
5972 * Writes the given +object+ to self, which must be opened for writing (see Modes);
5973 * returns the number bytes written.
5974 * If +object+ is not a string is converted via method to_s:
5975 *
5976 * f = File.new('t.tmp', 'w')
5977 * f.syswrite('foo') # => 3
5978 * f.syswrite(30) # => 2
5979 * f.syswrite(:foo) # => 3
5980 * f.close
5981 *
5982 * This methods should not be used with other stream-writer methods.
5983 *
5984 */
5985
5986static VALUE
5987rb_io_syswrite(VALUE io, VALUE str)
5988{
5989 VALUE tmp;
5990 rb_io_t *fptr;
5991 long n, len;
5992 const char *ptr;
5993
5994 if (!RB_TYPE_P(str, T_STRING))
5995 str = rb_obj_as_string(str);
5996
5997 io = GetWriteIO(io);
5998 GetOpenFile(io, fptr);
6000
6001 if (fptr->wbuf.len) {
6002 rb_warn("syswrite for buffered IO");
6003 }
6004
6005 tmp = rb_str_tmp_frozen_acquire(str);
6006 RSTRING_GETMEM(tmp, ptr, len);
6007 n = rb_io_write_memory(fptr, ptr, len);
6008 if (n < 0) rb_sys_fail_path(fptr->pathv);
6009 rb_str_tmp_frozen_release(str, tmp);
6010
6011 return LONG2FIX(n);
6012}
6013
6014/*
6015 * call-seq:
6016 * sysread(maxlen) -> string
6017 * sysread(maxlen, out_string) -> string
6018 *
6019 * Behaves like IO#readpartial, except that it uses low-level system functions.
6020 *
6021 * This method should not be used with other stream-reader methods.
6022 *
6023 */
6024
6025static VALUE
6026rb_io_sysread(int argc, VALUE *argv, VALUE io)
6027{
6028 VALUE len, str;
6029 rb_io_t *fptr;
6030 long n, ilen;
6031 struct io_internal_read_struct iis;
6032 int shrinkable;
6033
6034 rb_scan_args(argc, argv, "11", &len, &str);
6035 ilen = NUM2LONG(len);
6036
6037 shrinkable = io_setstrbuf(&str, ilen);
6038 if (ilen == 0) return str;
6039
6040 GetOpenFile(io, fptr);
6042
6043 if (READ_DATA_BUFFERED(fptr)) {
6044 rb_raise(rb_eIOError, "sysread for buffered IO");
6045 }
6046
6047 rb_io_check_closed(fptr);
6048
6049 io_setstrbuf(&str, ilen);
6050 iis.th = rb_thread_current();
6051 iis.fptr = fptr;
6052 iis.nonblock = 0;
6053 iis.fd = fptr->fd;
6054 iis.buf = RSTRING_PTR(str);
6055 iis.capa = ilen;
6056 iis.timeout = NULL;
6057 n = io_read_memory_locktmp(str, &iis);
6058
6059 if (n < 0) {
6060 rb_sys_fail_path(fptr->pathv);
6061 }
6062
6063 io_set_read_length(str, n, shrinkable);
6064
6065 if (n == 0 && ilen > 0) {
6066 rb_eof_error();
6067 }
6068
6069 return str;
6070}
6071
6072#if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
6073struct prdwr_internal_arg {
6074 int fd;
6075 void *buf;
6076 size_t count;
6077 rb_off_t offset;
6078};
6079#endif /* HAVE_PREAD || HAVE_PWRITE */
6080
6081#if defined(HAVE_PREAD)
6082static VALUE
6083internal_pread_func(void *arg)
6084{
6085 struct prdwr_internal_arg *p = arg;
6086 return (VALUE)pread(p->fd, p->buf, p->count, p->offset);
6087}
6088
6089static VALUE
6090pread_internal_call(VALUE arg)
6091{
6092 struct prdwr_internal_arg *p = (struct prdwr_internal_arg *)arg;
6093 return rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
6094}
6095
6096/*
6097 * call-seq:
6098 * pread(maxlen, offset) -> string
6099 * pread(maxlen, offset, out_string) -> string
6100 *
6101 * Behaves like IO#readpartial, except that it:
6102 *
6103 * - Reads at the given +offset+ (in bytes).
6104 * - Disregards, and does not modify, the stream's position
6105 * (see {Position}[rdoc-ref:IO@Position]).
6106 * - Bypasses any user space buffering in the stream.
6107 *
6108 * Because this method does not disturb the stream's state
6109 * (its position, in particular), +pread+ allows multiple threads and processes
6110 * to use the same \IO object for reading at various offsets.
6111 *
6112 * f = File.open('t.txt')
6113 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6114 * f.pos # => 52
6115 * # Read 12 bytes at offset 0.
6116 * f.pread(12, 0) # => "First line\n"
6117 * # Read 9 bytes at offset 8.
6118 * f.pread(9, 8) # => "ne\nSecon"
6119 * f.close
6120 *
6121 * Not available on some platforms.
6122 *
6123 */
6124static VALUE
6125rb_io_pread(int argc, VALUE *argv, VALUE io)
6126{
6127 VALUE len, offset, str;
6128 rb_io_t *fptr;
6129 ssize_t n;
6130 struct prdwr_internal_arg arg;
6131 int shrinkable;
6132
6133 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6134 arg.count = NUM2SIZET(len);
6135 arg.offset = NUM2OFFT(offset);
6136
6137 shrinkable = io_setstrbuf(&str, (long)arg.count);
6138 if (arg.count == 0) return str;
6139 arg.buf = RSTRING_PTR(str);
6140
6141 GetOpenFile(io, fptr);
6143
6144 arg.fd = fptr->fd;
6145 rb_io_check_closed(fptr);
6146
6147 rb_str_locktmp(str);
6148 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6149
6150 if (n < 0) {
6151 rb_sys_fail_path(fptr->pathv);
6152 }
6153 io_set_read_length(str, n, shrinkable);
6154 if (n == 0 && arg.count > 0) {
6155 rb_eof_error();
6156 }
6157
6158 return str;
6159}
6160#else
6161# define rb_io_pread rb_f_notimplement
6162#endif /* HAVE_PREAD */
6163
6164#if defined(HAVE_PWRITE)
6165static VALUE
6166internal_pwrite_func(void *ptr)
6167{
6168 struct prdwr_internal_arg *arg = ptr;
6169
6170 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6171}
6172
6173/*
6174 * call-seq:
6175 * pwrite(object, offset) -> integer
6176 *
6177 * Behaves like IO#write, except that it:
6178 *
6179 * - Writes at the given +offset+ (in bytes).
6180 * - Disregards, and does not modify, the stream's position
6181 * (see {Position}[rdoc-ref:IO@Position]).
6182 * - Bypasses any user space buffering in the stream.
6183 *
6184 * Because this method does not disturb the stream's state
6185 * (its position, in particular), +pwrite+ allows multiple threads and processes
6186 * to use the same \IO object for writing at various offsets.
6187 *
6188 * f = File.open('t.tmp', 'w+')
6189 * # Write 6 bytes at offset 3.
6190 * f.pwrite('ABCDEF', 3) # => 6
6191 * f.rewind
6192 * f.read # => "\u0000\u0000\u0000ABCDEF"
6193 * f.close
6194 *
6195 * Not available on some platforms.
6196 *
6197 */
6198static VALUE
6199rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6200{
6201 rb_io_t *fptr;
6202 ssize_t n;
6203 struct prdwr_internal_arg arg;
6204 VALUE tmp;
6205
6206 if (!RB_TYPE_P(str, T_STRING))
6207 str = rb_obj_as_string(str);
6208
6209 arg.offset = NUM2OFFT(offset);
6210
6211 io = GetWriteIO(io);
6212 GetOpenFile(io, fptr);
6214 arg.fd = fptr->fd;
6215
6216 tmp = rb_str_tmp_frozen_acquire(str);
6217 arg.buf = RSTRING_PTR(tmp);
6218 arg.count = (size_t)RSTRING_LEN(tmp);
6219
6220 n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
6221 if (n < 0) rb_sys_fail_path(fptr->pathv);
6222 rb_str_tmp_frozen_release(str, tmp);
6223
6224 return SSIZET2NUM(n);
6225}
6226#else
6227# define rb_io_pwrite rb_f_notimplement
6228#endif /* HAVE_PWRITE */
6229
6230VALUE
6232{
6233 rb_io_t *fptr;
6234
6235 GetOpenFile(io, fptr);
6236 if (fptr->readconv)
6238 if (fptr->writeconv)
6240 fptr->mode |= FMODE_BINMODE;
6241 fptr->mode &= ~FMODE_TEXTMODE;
6242 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6243#ifdef O_BINARY
6244 if (!fptr->readconv) {
6245 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6246 }
6247 else {
6248 setmode(fptr->fd, O_BINARY);
6249 }
6250#endif
6251 return io;
6252}
6253
6254static void
6255io_ascii8bit_binmode(rb_io_t *fptr)
6256{
6257 if (fptr->readconv) {
6258 rb_econv_close(fptr->readconv);
6259 fptr->readconv = NULL;
6260 }
6261 if (fptr->writeconv) {
6263 fptr->writeconv = NULL;
6264 }
6265 fptr->mode |= FMODE_BINMODE;
6266 fptr->mode &= ~FMODE_TEXTMODE;
6267 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6268
6269 fptr->encs.enc = rb_ascii8bit_encoding();
6270 fptr->encs.enc2 = NULL;
6271 fptr->encs.ecflags = 0;
6272 fptr->encs.ecopts = Qnil;
6273 clear_codeconv(fptr);
6274}
6275
6276VALUE
6278{
6279 rb_io_t *fptr;
6280
6281 GetOpenFile(io, fptr);
6282 io_ascii8bit_binmode(fptr);
6283
6284 return io;
6285}
6286
6287/*
6288 * call-seq:
6289 * binmode -> self
6290 *
6291 * Sets the stream's data mode as binary
6292 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6293 *
6294 * A stream's data mode may not be changed from binary to text.
6295 *
6296 */
6297
6298static VALUE
6299rb_io_binmode_m(VALUE io)
6300{
6301 VALUE write_io;
6302
6304
6305 write_io = GetWriteIO(io);
6306 if (write_io != io)
6307 rb_io_ascii8bit_binmode(write_io);
6308 return io;
6309}
6310
6311/*
6312 * call-seq:
6313 * binmode? -> true or false
6314 *
6315 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6316 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6317 *
6318 */
6319static VALUE
6320rb_io_binmode_p(VALUE io)
6321{
6322 rb_io_t *fptr;
6323 GetOpenFile(io, fptr);
6324 return RBOOL(fptr->mode & FMODE_BINMODE);
6325}
6326
6327static const char*
6328rb_io_fmode_modestr(int fmode)
6329{
6330 if (fmode & FMODE_APPEND) {
6331 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6332 return MODE_BTMODE("a+", "ab+", "at+");
6333 }
6334 return MODE_BTMODE("a", "ab", "at");
6335 }
6336 switch (fmode & FMODE_READWRITE) {
6337 default:
6338 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6339 case FMODE_READABLE:
6340 return MODE_BTMODE("r", "rb", "rt");
6341 case FMODE_WRITABLE:
6342 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6343 case FMODE_READWRITE:
6344 if (fmode & FMODE_CREATE) {
6345 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6346 }
6347 return MODE_BTMODE("r+", "rb+", "rt+");
6348 }
6349}
6350
6351static const char bom_prefix[] = "bom|";
6352static const char utf_prefix[] = "utf-";
6353enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6354enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6355
6356static int
6357io_encname_bom_p(const char *name, long len)
6358{
6359 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6360}
6361
6362int
6363rb_io_modestr_fmode(const char *modestr)
6364{
6365 int fmode = 0;
6366 const char *m = modestr, *p = NULL;
6367
6368 switch (*m++) {
6369 case 'r':
6370 fmode |= FMODE_READABLE;
6371 break;
6372 case 'w':
6374 break;
6375 case 'a':
6377 break;
6378 default:
6379 goto error;
6380 }
6381
6382 while (*m) {
6383 switch (*m++) {
6384 case 'b':
6385 fmode |= FMODE_BINMODE;
6386 break;
6387 case 't':
6388 fmode |= FMODE_TEXTMODE;
6389 break;
6390 case '+':
6391 fmode |= FMODE_READWRITE;
6392 break;
6393 case 'x':
6394 if (modestr[0] != 'w')
6395 goto error;
6396 fmode |= FMODE_EXCL;
6397 break;
6398 default:
6399 goto error;
6400 case ':':
6401 p = strchr(m, ':');
6402 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6403 fmode |= FMODE_SETENC_BY_BOM;
6404 goto finished;
6405 }
6406 }
6407
6408 finished:
6409 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6410 goto error;
6411
6412 return fmode;
6413
6414 error:
6415 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6417}
6418
6419int
6420rb_io_oflags_fmode(int oflags)
6421{
6422 int fmode = 0;
6423
6424 switch (oflags & O_ACCMODE) {
6425 case O_RDONLY:
6426 fmode = FMODE_READABLE;
6427 break;
6428 case O_WRONLY:
6429 fmode = FMODE_WRITABLE;
6430 break;
6431 case O_RDWR:
6432 fmode = FMODE_READWRITE;
6433 break;
6434 }
6435
6436 if (oflags & O_APPEND) {
6437 fmode |= FMODE_APPEND;
6438 }
6439 if (oflags & O_TRUNC) {
6440 fmode |= FMODE_TRUNC;
6441 }
6442 if (oflags & O_CREAT) {
6443 fmode |= FMODE_CREATE;
6444 }
6445 if (oflags & O_EXCL) {
6446 fmode |= FMODE_EXCL;
6447 }
6448#ifdef O_BINARY
6449 if (oflags & O_BINARY) {
6450 fmode |= FMODE_BINMODE;
6451 }
6452#endif
6453
6454 return fmode;
6455}
6456
6457static int
6458rb_io_fmode_oflags(int fmode)
6459{
6460 int oflags = 0;
6461
6462 switch (fmode & FMODE_READWRITE) {
6463 case FMODE_READABLE:
6464 oflags |= O_RDONLY;
6465 break;
6466 case FMODE_WRITABLE:
6467 oflags |= O_WRONLY;
6468 break;
6469 case FMODE_READWRITE:
6470 oflags |= O_RDWR;
6471 break;
6472 }
6473
6474 if (fmode & FMODE_APPEND) {
6475 oflags |= O_APPEND;
6476 }
6477 if (fmode & FMODE_TRUNC) {
6478 oflags |= O_TRUNC;
6479 }
6480 if (fmode & FMODE_CREATE) {
6481 oflags |= O_CREAT;
6482 }
6483 if (fmode & FMODE_EXCL) {
6484 oflags |= O_EXCL;
6485 }
6486#ifdef O_BINARY
6487 if (fmode & FMODE_BINMODE) {
6488 oflags |= O_BINARY;
6489 }
6490#endif
6491
6492 return oflags;
6493}
6494
6495int
6496rb_io_modestr_oflags(const char *modestr)
6497{
6498 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6499}
6500
6501static const char*
6502rb_io_oflags_modestr(int oflags)
6503{
6504#ifdef O_BINARY
6505# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6506#else
6507# define MODE_BINARY(a,b) (a)
6508#endif
6509 int accmode;
6510 if (oflags & O_EXCL) {
6511 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6512 }
6513 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6514 if (oflags & O_APPEND) {
6515 if (accmode == O_WRONLY) {
6516 return MODE_BINARY("a", "ab");
6517 }
6518 if (accmode == O_RDWR) {
6519 return MODE_BINARY("a+", "ab+");
6520 }
6521 }
6522 switch (accmode) {
6523 default:
6524 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6525 case O_RDONLY:
6526 return MODE_BINARY("r", "rb");
6527 case O_WRONLY:
6528 return MODE_BINARY("w", "wb");
6529 case O_RDWR:
6530 if (oflags & O_TRUNC) {
6531 return MODE_BINARY("w+", "wb+");
6532 }
6533 return MODE_BINARY("r+", "rb+");
6534 }
6535}
6536
6537/*
6538 * Convert external/internal encodings to enc/enc2
6539 * NULL => use default encoding
6540 * Qnil => no encoding specified (internal only)
6541 */
6542static void
6543rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6544{
6545 int default_ext = 0;
6546
6547 if (ext == NULL) {
6548 ext = rb_default_external_encoding();
6549 default_ext = 1;
6550 }
6551 if (rb_is_ascii8bit_enc(ext)) {
6552 /* If external is ASCII-8BIT, no transcoding */
6553 intern = NULL;
6554 }
6555 else if (intern == NULL) {
6556 intern = rb_default_internal_encoding();
6557 }
6558 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6559 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6560 /* No internal encoding => use external + no transcoding */
6561 *enc = (default_ext && intern != ext) ? NULL : ext;
6562 *enc2 = NULL;
6563 }
6564 else {
6565 *enc = intern;
6566 *enc2 = ext;
6567 }
6568}
6569
6570static void
6571unsupported_encoding(const char *name, rb_encoding *enc)
6572{
6573 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6574}
6575
6576static void
6577parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6578 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6579{
6580 const char *p;
6581 char encname[ENCODING_MAXNAMELEN+1];
6582 int idx, idx2;
6583 int fmode = fmode_p ? *fmode_p : 0;
6584 rb_encoding *ext_enc, *int_enc;
6585 long len;
6586
6587 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6588
6589 p = strrchr(estr, ':');
6590 len = p ? (p++ - estr) : (long)strlen(estr);
6591 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6592 estr += bom_prefix_len;
6593 len -= bom_prefix_len;
6594 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6595 fmode |= FMODE_SETENC_BY_BOM;
6596 }
6597 else {
6598 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6599 fmode &= ~FMODE_SETENC_BY_BOM;
6600 }
6601 }
6602 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6603 idx = -1;
6604 }
6605 else {
6606 if (p) {
6607 memcpy(encname, estr, len);
6608 encname[len] = '\0';
6609 estr = encname;
6610 }
6611 idx = rb_enc_find_index(estr);
6612 }
6613 if (fmode_p) *fmode_p = fmode;
6614
6615 if (idx >= 0)
6616 ext_enc = rb_enc_from_index(idx);
6617 else {
6618 if (idx != -2)
6619 unsupported_encoding(estr, estr_enc);
6620 ext_enc = NULL;
6621 }
6622
6623 int_enc = NULL;
6624 if (p) {
6625 if (*p == '-' && *(p+1) == '\0') {
6626 /* Special case - "-" => no transcoding */
6627 int_enc = (rb_encoding *)Qnil;
6628 }
6629 else {
6630 idx2 = rb_enc_find_index(p);
6631 if (idx2 < 0)
6632 unsupported_encoding(p, estr_enc);
6633 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6634 int_enc = (rb_encoding *)Qnil;
6635 }
6636 else
6637 int_enc = rb_enc_from_index(idx2);
6638 }
6639 }
6640
6641 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6642}
6643
6644int
6645rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6646{
6647 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6648 int extracted = 0;
6649 rb_encoding *extencoding = NULL;
6650 rb_encoding *intencoding = NULL;
6651
6652 if (!NIL_P(opt)) {
6653 VALUE v;
6654 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6655 if (v != Qnil) encoding = v;
6656 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6657 if (v != Qnil) extenc = v;
6658 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6659 if (!UNDEF_P(v)) intenc = v;
6660 }
6661 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6662 if (!NIL_P(ruby_verbose)) {
6663 int idx = rb_to_encoding_index(encoding);
6664 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6665 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6666 encoding, UNDEF_P(extenc) ? "internal" : "external");
6667 }
6668 encoding = Qnil;
6669 }
6670 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6671 extencoding = rb_to_encoding(extenc);
6672 }
6673 if (!UNDEF_P(intenc)) {
6674 if (NIL_P(intenc)) {
6675 /* internal_encoding: nil => no transcoding */
6676 intencoding = (rb_encoding *)Qnil;
6677 }
6678 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6679 char *p = StringValueCStr(tmp);
6680
6681 if (*p == '-' && *(p+1) == '\0') {
6682 /* Special case - "-" => no transcoding */
6683 intencoding = (rb_encoding *)Qnil;
6684 }
6685 else {
6686 intencoding = rb_to_encoding(intenc);
6687 }
6688 }
6689 else {
6690 intencoding = rb_to_encoding(intenc);
6691 }
6692 if (extencoding == intencoding) {
6693 intencoding = (rb_encoding *)Qnil;
6694 }
6695 }
6696 if (!NIL_P(encoding)) {
6697 extracted = 1;
6698 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6699 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6700 enc_p, enc2_p, fmode_p);
6701 }
6702 else {
6703 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6704 }
6705 }
6706 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6707 extracted = 1;
6708 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6709 }
6710 return extracted;
6711}
6712
6713typedef struct rb_io_enc_t convconfig_t;
6714
6715static void
6716validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6717{
6718 int fmode = *fmode_p;
6719
6720 if ((fmode & FMODE_READABLE) &&
6721 !enc2 &&
6722 !(fmode & FMODE_BINMODE) &&
6723 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6724 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6725
6726 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6727 rb_raise(rb_eArgError, "newline decorator with binary mode");
6728 }
6729 if (!(fmode & FMODE_BINMODE) &&
6730 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6731 fmode |= FMODE_TEXTMODE;
6732 *fmode_p = fmode;
6733 }
6734#if !DEFAULT_TEXTMODE
6735 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6736 fmode &= ~FMODE_TEXTMODE;
6737 *fmode_p = fmode;
6738 }
6739#endif
6740}
6741
6742static void
6743extract_binmode(VALUE opthash, int *fmode)
6744{
6745 if (!NIL_P(opthash)) {
6746 VALUE v;
6747 v = rb_hash_aref(opthash, sym_textmode);
6748 if (!NIL_P(v)) {
6749 if (*fmode & FMODE_TEXTMODE)
6750 rb_raise(rb_eArgError, "textmode specified twice");
6751 if (*fmode & FMODE_BINMODE)
6752 rb_raise(rb_eArgError, "both textmode and binmode specified");
6753 if (RTEST(v))
6754 *fmode |= FMODE_TEXTMODE;
6755 }
6756 v = rb_hash_aref(opthash, sym_binmode);
6757 if (!NIL_P(v)) {
6758 if (*fmode & FMODE_BINMODE)
6759 rb_raise(rb_eArgError, "binmode specified twice");
6760 if (*fmode & FMODE_TEXTMODE)
6761 rb_raise(rb_eArgError, "both textmode and binmode specified");
6762 if (RTEST(v))
6763 *fmode |= FMODE_BINMODE;
6764 }
6765
6766 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6767 rb_raise(rb_eArgError, "both textmode and binmode specified");
6768 }
6769}
6770
6771void
6772rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6773 int *oflags_p, int *fmode_p, convconfig_t *convconfig_p)
6774{
6775 VALUE vmode;
6776 int oflags, fmode;
6777 rb_encoding *enc, *enc2;
6778 int ecflags;
6779 VALUE ecopts;
6780 int has_enc = 0, has_vmode = 0;
6781 VALUE intmode;
6782
6783 vmode = *vmode_p;
6784
6785 /* Set to defaults */
6786 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6787
6788 vmode_handle:
6789 if (NIL_P(vmode)) {
6790 fmode = FMODE_READABLE;
6791 oflags = O_RDONLY;
6792 }
6793 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6794 vmode = intmode;
6795 oflags = NUM2INT(intmode);
6796 fmode = rb_io_oflags_fmode(oflags);
6797 }
6798 else {
6799 const char *p;
6800
6801 SafeStringValue(vmode);
6802 p = StringValueCStr(vmode);
6803 fmode = rb_io_modestr_fmode(p);
6804 oflags = rb_io_fmode_oflags(fmode);
6805 p = strchr(p, ':');
6806 if (p) {
6807 has_enc = 1;
6808 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6809 }
6810 else {
6811 rb_encoding *e;
6812
6813 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6814 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6815 }
6816 }
6817
6818 if (NIL_P(opthash)) {
6819 ecflags = (fmode & FMODE_READABLE) ?
6822#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6823 ecflags |= (fmode & FMODE_WRITABLE) ?
6824 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6825 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6826#endif
6827 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6828 ecopts = Qnil;
6829 if (fmode & FMODE_BINMODE) {
6830#ifdef O_BINARY
6831 oflags |= O_BINARY;
6832#endif
6833 if (!has_enc)
6834 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6835 }
6836#if DEFAULT_TEXTMODE
6837 else if (NIL_P(vmode)) {
6838 fmode |= DEFAULT_TEXTMODE;
6839 }
6840#endif
6841 }
6842 else {
6843 VALUE v;
6844 if (!has_vmode) {
6845 v = rb_hash_aref(opthash, sym_mode);
6846 if (!NIL_P(v)) {
6847 if (!NIL_P(vmode)) {
6848 rb_raise(rb_eArgError, "mode specified twice");
6849 }
6850 has_vmode = 1;
6851 vmode = v;
6852 goto vmode_handle;
6853 }
6854 }
6855 v = rb_hash_aref(opthash, sym_flags);
6856 if (!NIL_P(v)) {
6857 v = rb_to_int(v);
6858 oflags |= NUM2INT(v);
6859 vmode = INT2NUM(oflags);
6860 fmode = rb_io_oflags_fmode(oflags);
6861 }
6862 extract_binmode(opthash, &fmode);
6863 if (fmode & FMODE_BINMODE) {
6864#ifdef O_BINARY
6865 oflags |= O_BINARY;
6866#endif
6867 if (!has_enc)
6868 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6869 }
6870#if DEFAULT_TEXTMODE
6871 else if (NIL_P(vmode)) {
6872 fmode |= DEFAULT_TEXTMODE;
6873 }
6874#endif
6875 v = rb_hash_aref(opthash, sym_perm);
6876 if (!NIL_P(v)) {
6877 if (vperm_p) {
6878 if (!NIL_P(*vperm_p)) {
6879 rb_raise(rb_eArgError, "perm specified twice");
6880 }
6881 *vperm_p = v;
6882 }
6883 else {
6884 /* perm no use, just ignore */
6885 }
6886 }
6887 ecflags = (fmode & FMODE_READABLE) ?
6890#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6891 ecflags |= (fmode & FMODE_WRITABLE) ?
6892 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6893 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6894#endif
6895
6896 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6897 if (has_enc) {
6898 rb_raise(rb_eArgError, "encoding specified twice");
6899 }
6900 }
6901 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6903 }
6904
6905 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6906
6907 *vmode_p = vmode;
6908
6909 *oflags_p = oflags;
6910 *fmode_p = fmode;
6911 convconfig_p->enc = enc;
6912 convconfig_p->enc2 = enc2;
6913 convconfig_p->ecflags = ecflags;
6914 convconfig_p->ecopts = ecopts;
6915}
6916
6918 VALUE fname;
6919 int oflags;
6920 mode_t perm;
6921};
6922
6923static void *
6924sysopen_func(void *ptr)
6925{
6926 const struct sysopen_struct *data = ptr;
6927 const char *fname = RSTRING_PTR(data->fname);
6928 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
6929}
6930
6931static inline int
6932rb_sysopen_internal(struct sysopen_struct *data)
6933{
6934 int fd;
6935 fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
6936 if (0 <= fd)
6937 rb_update_max_fd(fd);
6938 return fd;
6939}
6940
6941static int
6942rb_sysopen(VALUE fname, int oflags, mode_t perm)
6943{
6944 int fd;
6945 struct sysopen_struct data;
6946
6947 data.fname = rb_str_encode_ospath(fname);
6948 StringValueCStr(data.fname);
6949 data.oflags = oflags;
6950 data.perm = perm;
6951
6952 fd = rb_sysopen_internal(&data);
6953 if (fd < 0) {
6954 int e = errno;
6955 if (rb_gc_for_fd(e)) {
6956 fd = rb_sysopen_internal(&data);
6957 }
6958 if (fd < 0) {
6959 rb_syserr_fail_path(e, fname);
6960 }
6961 }
6962 return fd;
6963}
6964
6965FILE *
6966rb_fdopen(int fd, const char *modestr)
6967{
6968 FILE *file;
6969
6970#if defined(__sun)
6971 errno = 0;
6972#endif
6973 file = fdopen(fd, modestr);
6974 if (!file) {
6975 int e = errno;
6976#if defined(__sun)
6977 if (e == 0) {
6978 rb_gc();
6979 errno = 0;
6980 file = fdopen(fd, modestr);
6981 }
6982 else
6983#endif
6984 if (rb_gc_for_fd(e)) {
6985 file = fdopen(fd, modestr);
6986 }
6987 if (!file) {
6988#ifdef _WIN32
6989 if (e == 0) e = EINVAL;
6990#elif defined(__sun)
6991 if (e == 0) e = EMFILE;
6992#endif
6993 rb_syserr_fail(e, 0);
6994 }
6995 }
6996
6997 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
6998#ifdef USE_SETVBUF
6999 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7000 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7001#endif
7002 return file;
7003}
7004
7005static int
7006io_check_tty(rb_io_t *fptr)
7007{
7008 int t = isatty(fptr->fd);
7009 if (t)
7010 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7011 return t;
7012}
7013
7014static VALUE rb_io_internal_encoding(VALUE);
7015static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7016
7017static int
7018io_strip_bom(VALUE io)
7019{
7020 VALUE b1, b2, b3, b4;
7021 rb_io_t *fptr;
7022
7023 GetOpenFile(io, fptr);
7024 if (!(fptr->mode & FMODE_READABLE)) return 0;
7025 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7026 switch (b1) {
7027 case INT2FIX(0xEF):
7028 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7029 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7030 if (b3 == INT2FIX(0xBF)) {
7031 return rb_utf8_encindex();
7032 }
7033 rb_io_ungetbyte(io, b3);
7034 }
7035 rb_io_ungetbyte(io, b2);
7036 break;
7037
7038 case INT2FIX(0xFE):
7039 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7040 if (b2 == INT2FIX(0xFF)) {
7041 return ENCINDEX_UTF_16BE;
7042 }
7043 rb_io_ungetbyte(io, b2);
7044 break;
7045
7046 case INT2FIX(0xFF):
7047 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7048 if (b2 == INT2FIX(0xFE)) {
7049 b3 = rb_io_getbyte(io);
7050 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7051 if (b4 == INT2FIX(0)) {
7052 return ENCINDEX_UTF_32LE;
7053 }
7054 rb_io_ungetbyte(io, b4);
7055 }
7056 rb_io_ungetbyte(io, b3);
7057 return ENCINDEX_UTF_16LE;
7058 }
7059 rb_io_ungetbyte(io, b2);
7060 break;
7061
7062 case INT2FIX(0):
7063 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7064 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7065 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7066 if (b4 == INT2FIX(0xFF)) {
7067 return ENCINDEX_UTF_32BE;
7068 }
7069 rb_io_ungetbyte(io, b4);
7070 }
7071 rb_io_ungetbyte(io, b3);
7072 }
7073 rb_io_ungetbyte(io, b2);
7074 break;
7075 }
7076 rb_io_ungetbyte(io, b1);
7077 return 0;
7078}
7079
7080static rb_encoding *
7081io_set_encoding_by_bom(VALUE io)
7082{
7083 int idx = io_strip_bom(io);
7084 rb_io_t *fptr;
7085 rb_encoding *extenc = NULL;
7086
7087 GetOpenFile(io, fptr);
7088 if (idx) {
7089 extenc = rb_enc_from_index(idx);
7090 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7091 rb_io_internal_encoding(io), Qnil);
7092 }
7093 else {
7094 fptr->encs.enc2 = NULL;
7095 }
7096 return extenc;
7097}
7098
7099static VALUE
7100rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7101 const convconfig_t *convconfig, mode_t perm)
7102{
7103 VALUE pathv;
7104 rb_io_t *fptr;
7105 convconfig_t cc;
7106 if (!convconfig) {
7107 /* Set to default encodings */
7108 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7109 cc.ecflags = 0;
7110 cc.ecopts = Qnil;
7111 convconfig = &cc;
7112 }
7113 validate_enc_binmode(&fmode, convconfig->ecflags,
7114 convconfig->enc, convconfig->enc2);
7115
7116 MakeOpenFile(io, fptr);
7117 fptr->mode = fmode;
7118 fptr->encs = *convconfig;
7119 pathv = rb_str_new_frozen(filename);
7120#ifdef O_TMPFILE
7121 if (!(oflags & O_TMPFILE)) {
7122 fptr->pathv = pathv;
7123 }
7124#else
7125 fptr->pathv = pathv;
7126#endif
7127 fptr->fd = rb_sysopen(pathv, oflags, perm);
7128 io_check_tty(fptr);
7129 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7130
7131 return io;
7132}
7133
7134static VALUE
7135rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7136{
7137 int fmode = rb_io_modestr_fmode(modestr);
7138 const char *p = strchr(modestr, ':');
7139 convconfig_t convconfig;
7140
7141 if (p) {
7142 parse_mode_enc(p+1, rb_usascii_encoding(),
7143 &convconfig.enc, &convconfig.enc2, &fmode);
7144 convconfig.ecflags = 0;
7145 convconfig.ecopts = Qnil;
7146 }
7147 else {
7148 rb_encoding *e;
7149 /* Set to default encodings */
7150
7151 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7152 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7153 convconfig.ecflags = 0;
7154 convconfig.ecopts = Qnil;
7155 }
7156
7157 return rb_file_open_generic(io, filename,
7158 rb_io_fmode_oflags(fmode),
7159 fmode,
7160 &convconfig,
7161 0666);
7162}
7163
7164VALUE
7165rb_file_open_str(VALUE fname, const char *modestr)
7166{
7167 FilePathValue(fname);
7168 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7169}
7170
7171VALUE
7172rb_file_open(const char *fname, const char *modestr)
7173{
7174 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7175}
7176
7177#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7178static struct pipe_list {
7179 rb_io_t *fptr;
7180 struct pipe_list *next;
7181} *pipe_list;
7182
7183static void
7184pipe_add_fptr(rb_io_t *fptr)
7185{
7186 struct pipe_list *list;
7187
7188 list = ALLOC(struct pipe_list);
7189 list->fptr = fptr;
7190 list->next = pipe_list;
7191 pipe_list = list;
7192}
7193
7194static void
7195pipe_del_fptr(rb_io_t *fptr)
7196{
7197 struct pipe_list **prev = &pipe_list;
7198 struct pipe_list *tmp;
7199
7200 while ((tmp = *prev) != 0) {
7201 if (tmp->fptr == fptr) {
7202 *prev = tmp->next;
7203 free(tmp);
7204 return;
7205 }
7206 prev = &tmp->next;
7207 }
7208}
7209
7210#if defined (_WIN32) || defined(__CYGWIN__)
7211static void
7212pipe_atexit(void)
7213{
7214 struct pipe_list *list = pipe_list;
7215 struct pipe_list *tmp;
7216
7217 while (list) {
7218 tmp = list->next;
7219 rb_io_fptr_finalize(list->fptr);
7220 list = tmp;
7221 }
7222}
7223#endif
7224
7225static void
7226pipe_finalize(rb_io_t *fptr, int noraise)
7227{
7228#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7229 int status = 0;
7230 if (fptr->stdio_file) {
7231 status = pclose(fptr->stdio_file);
7232 }
7233 fptr->fd = -1;
7234 fptr->stdio_file = 0;
7235 rb_last_status_set(status, fptr->pid);
7236#else
7237 fptr_finalize(fptr, noraise);
7238#endif
7239 pipe_del_fptr(fptr);
7240}
7241#endif
7242
7243static void
7244fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7245{
7246#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7247 void (*const old_finalize)(struct rb_io_t*,int) = fptr->finalize;
7248
7249 if (old_finalize == orig->finalize) return;
7250#endif
7251
7252 fptr->finalize = orig->finalize;
7253
7254#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7255 if (old_finalize != pipe_finalize) {
7256 struct pipe_list *list;
7257 for (list = pipe_list; list; list = list->next) {
7258 if (list->fptr == fptr) break;
7259 }
7260 if (!list) pipe_add_fptr(fptr);
7261 }
7262 else {
7263 pipe_del_fptr(fptr);
7264 }
7265#endif
7266}
7267
7268void
7270{
7272 fptr->mode |= FMODE_SYNC;
7273}
7274
7275void
7276rb_io_unbuffered(rb_io_t *fptr)
7277{
7278 rb_io_synchronized(fptr);
7279}
7280
7281int
7282rb_pipe(int *pipes)
7283{
7284 int ret;
7285 ret = rb_cloexec_pipe(pipes);
7286 if (ret < 0) {
7287 if (rb_gc_for_fd(errno)) {
7288 ret = rb_cloexec_pipe(pipes);
7289 }
7290 }
7291 if (ret == 0) {
7292 rb_update_max_fd(pipes[0]);
7293 rb_update_max_fd(pipes[1]);
7294 }
7295 return ret;
7296}
7297
7298#ifdef _WIN32
7299#define HAVE_SPAWNV 1
7300#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7301#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7302#endif
7303
7304#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7305struct popen_arg {
7306 VALUE execarg_obj;
7307 struct rb_execarg *eargp;
7308 int modef;
7309 int pair[2];
7310 int write_pair[2];
7311};
7312#endif
7313
7314#ifdef HAVE_WORKING_FORK
7315# ifndef __EMSCRIPTEN__
7316static void
7317popen_redirect(struct popen_arg *p)
7318{
7319 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7320 close(p->write_pair[1]);
7321 if (p->write_pair[0] != 0) {
7322 dup2(p->write_pair[0], 0);
7323 close(p->write_pair[0]);
7324 }
7325 close(p->pair[0]);
7326 if (p->pair[1] != 1) {
7327 dup2(p->pair[1], 1);
7328 close(p->pair[1]);
7329 }
7330 }
7331 else if (p->modef & FMODE_READABLE) {
7332 close(p->pair[0]);
7333 if (p->pair[1] != 1) {
7334 dup2(p->pair[1], 1);
7335 close(p->pair[1]);
7336 }
7337 }
7338 else {
7339 close(p->pair[1]);
7340 if (p->pair[0] != 0) {
7341 dup2(p->pair[0], 0);
7342 close(p->pair[0]);
7343 }
7344 }
7345}
7346# endif
7347
7348#if defined(__linux__)
7349/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7350 * Since /proc may not be available, linux_get_maxfd is just a hint.
7351 * This function, linux_get_maxfd, must be async-signal-safe.
7352 * I.e. opendir() is not usable.
7353 *
7354 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7355 * However they are easy to re-implement in async-signal-safe manner.
7356 * (Also note that there is missing/memcmp.c.)
7357 */
7358static int
7359linux_get_maxfd(void)
7360{
7361 int fd;
7362 char buf[4096], *p, *np, *e;
7363 ssize_t ss;
7364 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7365 if (fd < 0) return fd;
7366 ss = read(fd, buf, sizeof(buf));
7367 if (ss < 0) goto err;
7368 p = buf;
7369 e = buf + ss;
7370 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7371 (np = memchr(p, '\n', e-p)) != NULL) {
7372 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7373 int fdsize;
7374 p += sizeof("FDSize:")-1;
7375 *np = '\0';
7376 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7377 close(fd);
7378 return fdsize;
7379 }
7380 p = np+1;
7381 }
7382 /* fall through */
7383
7384 err:
7385 close(fd);
7386 return (int)ss;
7387}
7388#endif
7389
7390/* This function should be async-signal-safe. */
7391void
7392rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7393{
7394#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7395 int fd, ret;
7396 int max = (int)max_file_descriptor;
7397# ifdef F_MAXFD
7398 /* F_MAXFD is available since NetBSD 2.0. */
7399 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7400 if (ret != -1)
7401 maxhint = max = ret;
7402# elif defined(__linux__)
7403 ret = linux_get_maxfd();
7404 if (maxhint < ret)
7405 maxhint = ret;
7406 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7407# endif
7408 if (max < maxhint)
7409 max = maxhint;
7410 for (fd = lowfd; fd <= max; fd++) {
7411 if (!NIL_P(noclose_fds) &&
7412 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7413 continue;
7414 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7415 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7416 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7417 }
7418# define CONTIGUOUS_CLOSED_FDS 20
7419 if (ret != -1) {
7420 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7421 max = fd + CONTIGUOUS_CLOSED_FDS;
7422 }
7423 }
7424#endif
7425}
7426
7427# ifndef __EMSCRIPTEN__
7428static int
7429popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7430{
7431 struct popen_arg *p = (struct popen_arg*)pp;
7432
7433 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7434}
7435# endif
7436#endif
7437
7438#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7439static VALUE
7440rb_execarg_fixup_v(VALUE execarg_obj)
7441{
7442 rb_execarg_parent_start(execarg_obj);
7443 return Qnil;
7444}
7445#else
7446char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7447#endif
7448
7449#ifndef __EMSCRIPTEN__
7450static VALUE
7451pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7452 const convconfig_t *convconfig)
7453{
7454 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7455 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7456 rb_pid_t pid = 0;
7457 rb_io_t *fptr;
7458 VALUE port;
7459 rb_io_t *write_fptr;
7460 VALUE write_port;
7461#if defined(HAVE_WORKING_FORK)
7462 int status;
7463 char errmsg[80] = { '\0' };
7464#endif
7465#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7466 int state;
7467 struct popen_arg arg;
7468#endif
7469 int e = 0;
7470#if defined(HAVE_SPAWNV)
7471# if defined(HAVE_SPAWNVE)
7472# define DO_SPAWN(cmd, args, envp) ((args) ? \
7473 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7474 spawne(P_NOWAIT, (cmd), (envp)))
7475# else
7476# define DO_SPAWN(cmd, args, envp) ((args) ? \
7477 spawnv(P_NOWAIT, (cmd), (args)) : \
7478 spawn(P_NOWAIT, (cmd)))
7479# endif
7480# if !defined(HAVE_WORKING_FORK)
7481 char **args = NULL;
7482# if defined(HAVE_SPAWNVE)
7483 char **envp = NULL;
7484# endif
7485# endif
7486#endif
7487#if !defined(HAVE_WORKING_FORK)
7488 struct rb_execarg sarg, *sargp = &sarg;
7489#endif
7490 FILE *fp = 0;
7491 int fd = -1;
7492 int write_fd = -1;
7493#if !defined(HAVE_WORKING_FORK)
7494 const char *cmd = 0;
7495
7496 if (prog)
7497 cmd = StringValueCStr(prog);
7498#endif
7499
7500#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7501 arg.execarg_obj = execarg_obj;
7502 arg.eargp = eargp;
7503 arg.modef = fmode;
7504 arg.pair[0] = arg.pair[1] = -1;
7505 arg.write_pair[0] = arg.write_pair[1] = -1;
7506# if !defined(HAVE_WORKING_FORK)
7507 if (eargp && !eargp->use_shell) {
7508 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7509 }
7510# endif
7511 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7513 if (rb_pipe(arg.write_pair) < 0)
7514 rb_sys_fail_str(prog);
7515 if (rb_pipe(arg.pair) < 0) {
7516 e = errno;
7517 close(arg.write_pair[0]);
7518 close(arg.write_pair[1]);
7519 rb_syserr_fail_str(e, prog);
7520 }
7521 if (eargp) {
7522 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7523 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7524 }
7525 break;
7526 case FMODE_READABLE:
7527 if (rb_pipe(arg.pair) < 0)
7528 rb_sys_fail_str(prog);
7529 if (eargp)
7530 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7531 break;
7532 case FMODE_WRITABLE:
7533 if (rb_pipe(arg.pair) < 0)
7534 rb_sys_fail_str(prog);
7535 if (eargp)
7536 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7537 break;
7538 default:
7539 rb_sys_fail_str(prog);
7540 }
7541 if (!NIL_P(execarg_obj)) {
7542 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7543 if (state) {
7544 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7545 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7546 if (0 <= arg.pair[0]) close(arg.pair[0]);
7547 if (0 <= arg.pair[1]) close(arg.pair[1]);
7548 rb_execarg_parent_end(execarg_obj);
7549 rb_jump_tag(state);
7550 }
7551
7552# if defined(HAVE_WORKING_FORK)
7553 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7554# else
7555 rb_execarg_run_options(eargp, sargp, NULL, 0);
7556# if defined(HAVE_SPAWNVE)
7557 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7558# endif
7559 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7560 /* exec failed */
7561 switch (e = errno) {
7562 case EAGAIN:
7563# if EWOULDBLOCK != EAGAIN
7564 case EWOULDBLOCK:
7565# endif
7566 rb_thread_sleep(1);
7567 continue;
7568 }
7569 break;
7570 }
7571 if (eargp)
7572 rb_execarg_run_options(sargp, NULL, NULL, 0);
7573# endif
7574 rb_execarg_parent_end(execarg_obj);
7575 }
7576 else {
7577# if defined(HAVE_WORKING_FORK)
7578 pid = rb_call_proc__fork();
7579 if (pid == 0) { /* child */
7580 popen_redirect(&arg);
7581 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7582 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7583 return Qnil;
7584 }
7585# else
7587# endif
7588 }
7589
7590 /* parent */
7591 if (pid < 0) {
7592# if defined(HAVE_WORKING_FORK)
7593 e = errno;
7594# endif
7595 close(arg.pair[0]);
7596 close(arg.pair[1]);
7598 close(arg.write_pair[0]);
7599 close(arg.write_pair[1]);
7600 }
7601# if defined(HAVE_WORKING_FORK)
7602 if (errmsg[0])
7603 rb_syserr_fail(e, errmsg);
7604# endif
7605 rb_syserr_fail_str(e, prog);
7606 }
7607 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7608 close(arg.pair[1]);
7609 fd = arg.pair[0];
7610 close(arg.write_pair[0]);
7611 write_fd = arg.write_pair[1];
7612 }
7613 else if (fmode & FMODE_READABLE) {
7614 close(arg.pair[1]);
7615 fd = arg.pair[0];
7616 }
7617 else {
7618 close(arg.pair[0]);
7619 fd = arg.pair[1];
7620 }
7621#else
7622 cmd = rb_execarg_commandline(eargp, &prog);
7623 if (!NIL_P(execarg_obj)) {
7624 rb_execarg_parent_start(execarg_obj);
7625 rb_execarg_run_options(eargp, sargp, NULL, 0);
7626 }
7627 fp = popen(cmd, modestr);
7628 e = errno;
7629 if (eargp) {
7630 rb_execarg_parent_end(execarg_obj);
7631 rb_execarg_run_options(sargp, NULL, NULL, 0);
7632 }
7633 if (!fp) rb_syserr_fail_path(e, prog);
7634 fd = fileno(fp);
7635#endif
7636
7637 port = io_alloc(rb_cIO);
7638 MakeOpenFile(port, fptr);
7639 fptr->fd = fd;
7640 fptr->stdio_file = fp;
7641 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7642 if (convconfig) {
7643 fptr->encs = *convconfig;
7644#if RUBY_CRLF_ENVIRONMENT
7647 }
7648#endif
7649 }
7650 else {
7651 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7653 }
7654#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7655 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7656 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7657 }
7658#endif
7659 }
7660 fptr->pid = pid;
7661
7662 if (0 <= write_fd) {
7663 write_port = io_alloc(rb_cIO);
7664 MakeOpenFile(write_port, write_fptr);
7665 write_fptr->fd = write_fd;
7666 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7667 fptr->mode &= ~FMODE_WRITABLE;
7668 fptr->tied_io_for_writing = write_port;
7669 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7670 }
7671
7672#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7673 fptr->finalize = pipe_finalize;
7674 pipe_add_fptr(fptr);
7675#endif
7676 return port;
7677}
7678#else
7679static VALUE
7680pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7681 const convconfig_t *convconfig)
7682{
7683 rb_raise(rb_eNotImpError, "popen() is not available");
7684}
7685#endif
7686
7687static int
7688is_popen_fork(VALUE prog)
7689{
7690 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7691#if !defined(HAVE_WORKING_FORK)
7693 "fork() function is unimplemented on this machine");
7694#else
7695 return TRUE;
7696#endif
7697 }
7698 return FALSE;
7699}
7700
7701static VALUE
7702pipe_open_s(VALUE prog, const char *modestr, int fmode,
7703 const convconfig_t *convconfig)
7704{
7705 int argc = 1;
7706 VALUE *argv = &prog;
7707 VALUE execarg_obj = Qnil;
7708
7709 if (!is_popen_fork(prog))
7710 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7711 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7712}
7713
7714static VALUE
7715pipe_close(VALUE io)
7716{
7717 rb_io_t *fptr = io_close_fptr(io);
7718 if (fptr) {
7719 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7720 }
7721 return Qnil;
7722}
7723
7724static VALUE popen_finish(VALUE port, VALUE klass);
7725
7726/*
7727 * call-seq:
7728 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7729 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7730 *
7731 * Executes the given command +cmd+ as a subprocess
7732 * whose $stdin and $stdout are connected to a new stream +io+.
7733 *
7734 * This method has potential security vulnerabilities if called with untrusted input;
7735 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7736 *
7737 * If no block is given, returns the new stream,
7738 * which depending on given +mode+ may be open for reading, writing, or both.
7739 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7740 *
7741 * If a block is given, the stream is passed to the block
7742 * (again, open for reading, writing, or both);
7743 * when the block exits, the stream is closed,
7744 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7745 *
7746 * Optional argument +mode+ may be any valid \IO mode.
7747 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7748 *
7749 * Required argument +cmd+ determines which of the following occurs:
7750 *
7751 * - The process forks.
7752 * - A specified program runs in a shell.
7753 * - A specified program runs with specified arguments.
7754 * - A specified program runs with specified arguments and a specified +argv0+.
7755 *
7756 * Each of these is detailed below.
7757 *
7758 * The optional hash argument +env+ specifies name/value pairs that are to be added
7759 * to the environment variables for the subprocess:
7760 *
7761 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7762 * pipe.puts 'puts ENV["FOO"]'
7763 * pipe.close_write
7764 * pipe.gets
7765 * end => "bar\n"
7766 *
7767 * Optional keyword arguments +opts+ specify:
7768 *
7769 * - {Open options}[rdoc-ref:IO@Open+Options].
7770 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7771 * - Options for Kernel#spawn.
7772 *
7773 * <b>Forked \Process</b>
7774 *
7775 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7776 * IO.popen('-') do |pipe|
7777 * if pipe
7778 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7779 * else
7780 * $stderr.puts "In child, pid is #{$$}\n"
7781 * end
7782 * end
7783 *
7784 * Output:
7785 *
7786 * In parent, child pid is 26253
7787 * In child, pid is 26253
7788 *
7789 * Note that this is not supported on all platforms.
7790 *
7791 * <b>Shell Subprocess</b>
7792 *
7793 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7794 * the program named +cmd+ is run as a shell command:
7795 *
7796 * IO.popen('uname') do |pipe|
7797 * pipe.readlines
7798 * end
7799 *
7800 * Output:
7801 *
7802 * ["Linux\n"]
7803 *
7804 * Another example:
7805 *
7806 * IO.popen('/bin/sh', 'r+') do |pipe|
7807 * pipe.puts('ls')
7808 * pipe.close_write
7809 * $stderr.puts pipe.readlines.size
7810 * end
7811 *
7812 * Output:
7813 *
7814 * 213
7815 *
7816 * <b>Program Subprocess</b>
7817 *
7818 * When argument +cmd+ is an array of strings,
7819 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7820 *
7821 * IO.popen(['du', '..', '.']) do |pipe|
7822 * $stderr.puts pipe.readlines.size
7823 * end
7824 *
7825 * Output:
7826 *
7827 * 1111
7828 *
7829 * <b>Program Subprocess with <tt>argv0</tt></b>
7830 *
7831 * When argument +cmd+ is an array whose first element is a 2-element string array
7832 * and whose remaining elements (if any) are strings:
7833 *
7834 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7835 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7836 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7837 *
7838 * Example (sets <tt>$0</tt> to 'foo'):
7839 *
7840 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7841 *
7842 * <b>Some Special Examples</b>
7843 *
7844 * # Set IO encoding.
7845 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7846 * euc_jp_string = nkf_io.read
7847 * }
7848 *
7849 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7850 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7851 * ls_result_with_error = io.read
7852 * end
7853 *
7854 * # Use mixture of spawn options and IO options.
7855 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7856 * ls_result_with_error = io.read
7857 * end
7858 *
7859 * f = IO.popen("uname")
7860 * p f.readlines
7861 * f.close
7862 * puts "Parent is #{Process.pid}"
7863 * IO.popen("date") {|f| puts f.gets }
7864 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7865 * p $?
7866 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7867 * f.puts "bar"; f.close_write; puts f.gets
7868 * }
7869 *
7870 * Output (from last section):
7871 *
7872 * ["Linux\n"]
7873 * Parent is 21346
7874 * Thu Jan 15 22:41:19 JST 2009
7875 * 21346 is here, f is #<IO:fd 3>
7876 * 21352 is here, f is nil
7877 * #<Process::Status: pid 21352 exit 0>
7878 * <foo>bar;zot;
7879 *
7880 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7881 *
7882 */
7883
7884static VALUE
7885rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7886{
7887 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7888
7889 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7890 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7891 switch (argc) {
7892 case 2:
7893 pmode = argv[1];
7894 case 1:
7895 pname = argv[0];
7896 break;
7897 default:
7898 {
7899 int ex = !NIL_P(opt);
7900 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7901 }
7902 }
7903 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7904}
7905
7906VALUE
7907rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7908{
7909 const char *modestr;
7910 VALUE tmp, execarg_obj = Qnil;
7911 int oflags, fmode;
7912 convconfig_t convconfig;
7913
7914 tmp = rb_check_array_type(pname);
7915 if (!NIL_P(tmp)) {
7916 long len = RARRAY_LEN(tmp);
7917#if SIZEOF_LONG > SIZEOF_INT
7918 if (len > INT_MAX) {
7919 rb_raise(rb_eArgError, "too many arguments");
7920 }
7921#endif
7922 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7923 RB_GC_GUARD(tmp);
7924 }
7925 else {
7926 SafeStringValue(pname);
7927 execarg_obj = Qnil;
7928 if (!is_popen_fork(pname))
7929 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7930 }
7931 if (!NIL_P(execarg_obj)) {
7932 if (!NIL_P(opt))
7933 opt = rb_execarg_extract_options(execarg_obj, opt);
7934 if (!NIL_P(env))
7935 rb_execarg_setenv(execarg_obj, env);
7936 }
7937 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
7938 modestr = rb_io_oflags_modestr(oflags);
7939
7940 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7941}
7942
7943static VALUE
7944popen_finish(VALUE port, VALUE klass)
7945{
7946 if (NIL_P(port)) {
7947 /* child */
7948 if (rb_block_given_p()) {
7949 rb_yield(Qnil);
7952 _exit(0);
7953 }
7954 return Qnil;
7955 }
7956 RBASIC_SET_CLASS(port, klass);
7957 if (rb_block_given_p()) {
7958 return rb_ensure(rb_yield, port, pipe_close, port);
7959 }
7960 return port;
7961}
7962
7963static void
7964rb_scan_open_args(int argc, const VALUE *argv,
7965 VALUE *fname_p, int *oflags_p, int *fmode_p,
7966 convconfig_t *convconfig_p, mode_t *perm_p)
7967{
7968 VALUE opt, fname, vmode, vperm;
7969 int oflags, fmode;
7970 mode_t perm;
7971
7972 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
7973 FilePathValue(fname);
7974
7975 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
7976
7977 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
7978
7979 *fname_p = fname;
7980 *oflags_p = oflags;
7981 *fmode_p = fmode;
7982 *perm_p = perm;
7983}
7984
7985static VALUE
7986rb_open_file(int argc, const VALUE *argv, VALUE io)
7987{
7988 VALUE fname;
7989 int oflags, fmode;
7990 convconfig_t convconfig;
7991 mode_t perm;
7992
7993 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
7994 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
7995
7996 return io;
7997}
7998
7999/*
8000 * Document-method: File::open
8001 *
8002 * call-seq:
8003 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8004 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8005 *
8006 * Creates a new \File object, via File.new with the given arguments.
8007 *
8008 * With no block given, returns the \File object.
8009 *
8010 * With a block given, calls the block with the \File object
8011 * and returns the block's value.
8012 *
8013 */
8014
8015/*
8016 * Document-method: IO::open
8017 *
8018 * call-seq:
8019 * IO.open(fd, mode = 'r', **opts) -> io
8020 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8021 *
8022 * Creates a new \IO object, via IO.new with the given arguments.
8023 *
8024 * With no block given, returns the \IO object.
8025 *
8026 * With a block given, calls the block with the \IO object
8027 * and returns the block's value.
8028 *
8029 */
8030
8031static VALUE
8032rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8033{
8035
8036 if (rb_block_given_p()) {
8037 return rb_ensure(rb_yield, io, io_close, io);
8038 }
8039
8040 return io;
8041}
8042
8043/*
8044 * call-seq:
8045 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8046 *
8047 * Opens the file at the given path with the given mode and permissions;
8048 * returns the integer file descriptor.
8049 *
8050 * If the file is to be readable, it must exist;
8051 * if the file is to be writable and does not exist,
8052 * it is created with the given permissions:
8053 *
8054 * File.write('t.tmp', '') # => 0
8055 * IO.sysopen('t.tmp') # => 8
8056 * IO.sysopen('t.tmp', 'w') # => 9
8057 *
8058 *
8059 */
8060
8061static VALUE
8062rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8063{
8064 VALUE fname, vmode, vperm;
8065 VALUE intmode;
8066 int oflags, fd;
8067 mode_t perm;
8068
8069 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8070 FilePathValue(fname);
8071
8072 if (NIL_P(vmode))
8073 oflags = O_RDONLY;
8074 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8075 oflags = NUM2INT(intmode);
8076 else {
8077 SafeStringValue(vmode);
8078 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8079 }
8080 if (NIL_P(vperm)) perm = 0666;
8081 else perm = NUM2MODET(vperm);
8082
8083 RB_GC_GUARD(fname) = rb_str_new4(fname);
8084 fd = rb_sysopen(fname, oflags, perm);
8085 return INT2NUM(fd);
8086}
8087
8088static VALUE
8089check_pipe_command(VALUE filename_or_command)
8090{
8091 char *s = RSTRING_PTR(filename_or_command);
8092 long l = RSTRING_LEN(filename_or_command);
8093 char *e = s + l;
8094 int chlen;
8095
8096 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8097 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8098 return cmd;
8099 }
8100 return Qnil;
8101}
8102
8103/*
8104 * call-seq:
8105 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8106 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8107 *
8108 * Creates an IO object connected to the given stream, file, or subprocess.
8109 *
8110 * Required string argument +path+ determines which of the following occurs:
8111 *
8112 * - The file at the specified +path+ is opened.
8113 * - The process forks.
8114 * - A subprocess is created.
8115 *
8116 * Each of these is detailed below.
8117 *
8118 * <b>File Opened</b>
8119
8120 * If +path+ does _not_ start with a pipe character (<tt>'|'</tt>),
8121 * a file stream is opened with <tt>File.open(path, mode, perm, **opts)</tt>.
8122 *
8123 * With no block given, file stream is returned:
8124 *
8125 * open('t.txt') # => #<File:t.txt>
8126 *
8127 * With a block given, calls the block with the open file stream,
8128 * then closes the stream:
8129 *
8130 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8131 *
8132 * Output:
8133 *
8134 * #<File:t.txt>
8135 *
8136 * See File.open for details.
8137 *
8138 * <b>Process Forked</b>
8139 *
8140 * If +path+ is the 2-character string <tt>'|-'</tt>, the process forks
8141 * and the child process is connected to the parent.
8142 *
8143 * With no block given:
8144 *
8145 * io = open('|-')
8146 * if io
8147 * $stderr.puts "In parent, child pid is #{io.pid}."
8148 * else
8149 * $stderr.puts "In child, pid is #{$$}."
8150 * end
8151 *
8152 * Output:
8153 *
8154 * In parent, child pid is 27903.
8155 * In child, pid is 27903.
8156 *
8157 * With a block given:
8158 *
8159 * open('|-') do |io|
8160 * if io
8161 * $stderr.puts "In parent, child pid is #{io.pid}."
8162 * else
8163 * $stderr.puts "In child, pid is #{$$}."
8164 * end
8165 * end
8166 *
8167 * Output:
8168 *
8169 * In parent, child pid is 28427.
8170 * In child, pid is 28427.
8171 *
8172 * <b>Subprocess Created</b>
8173 *
8174 * If +path+ is <tt>'|command'</tt> (<tt>'command' != '-'</tt>),
8175 * a new subprocess runs the command; its open stream is returned.
8176 * Note that the command may be processed by shell if it contains
8177 * shell metacharacters.
8178 *
8179 * With no block given:
8180 *
8181 * io = open('|echo "Hi!"') # => #<IO:fd 12>
8182 * print io.gets
8183 * io.close
8184 *
8185 * Output:
8186 *
8187 * "Hi!"
8188 *
8189 * With a block given, calls the block with the stream, then closes the stream:
8190 *
8191 * open('|echo "Hi!"') do |io|
8192 * print io.gets
8193 * end
8194 *
8195 * Output:
8196 *
8197 * "Hi!"
8198 *
8199 */
8200
8201static VALUE
8202rb_f_open(int argc, VALUE *argv, VALUE _)
8203{
8204 ID to_open = 0;
8205 int redirect = FALSE;
8206
8207 if (argc >= 1) {
8208 CONST_ID(to_open, "to_open");
8209 if (rb_respond_to(argv[0], to_open)) {
8210 redirect = TRUE;
8211 }
8212 else {
8213 VALUE tmp = argv[0];
8214 FilePathValue(tmp);
8215 if (NIL_P(tmp)) {
8216 redirect = TRUE;
8217 }
8218 else {
8219 VALUE cmd = check_pipe_command(tmp);
8220 if (!NIL_P(cmd)) {
8221 argv[0] = cmd;
8222 return rb_io_s_popen(argc, argv, rb_cIO);
8223 }
8224 }
8225 }
8226 }
8227 if (redirect) {
8228 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8229
8230 if (rb_block_given_p()) {
8231 return rb_ensure(rb_yield, io, io_close, io);
8232 }
8233 return io;
8234 }
8235 return rb_io_s_open(argc, argv, rb_cFile);
8236}
8237
8238static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const convconfig_t *, mode_t);
8239
8240static VALUE
8241rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8242{
8243 int oflags, fmode;
8244 convconfig_t convconfig;
8245 mode_t perm;
8246
8247 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8248 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8249 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8250}
8251
8252static VALUE
8253rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8254 const convconfig_t *convconfig, mode_t perm)
8255{
8256 VALUE cmd;
8257 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8258 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8259 }
8260 else {
8261 return rb_file_open_generic(io_alloc(klass), filename,
8262 oflags, fmode, convconfig, perm);
8263 }
8264}
8265
8266static VALUE
8267io_reopen(VALUE io, VALUE nfile)
8268{
8269 rb_io_t *fptr, *orig;
8270 int fd, fd2;
8271 rb_off_t pos = 0;
8272
8273 nfile = rb_io_get_io(nfile);
8274 GetOpenFile(io, fptr);
8275 GetOpenFile(nfile, orig);
8276
8277 if (fptr == orig) return io;
8278 if (IS_PREP_STDIO(fptr)) {
8279 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8280 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8281 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8283 "%s can't change access mode from \"%s\" to \"%s\"",
8284 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8285 rb_io_fmode_modestr(orig->mode));
8286 }
8287 }
8288 if (fptr->mode & FMODE_WRITABLE) {
8289 if (io_fflush(fptr) < 0)
8290 rb_sys_fail_on_write(fptr);
8291 }
8292 else {
8293 flush_before_seek(fptr);
8294 }
8295 if (orig->mode & FMODE_READABLE) {
8296 pos = io_tell(orig);
8297 }
8298 if (orig->mode & FMODE_WRITABLE) {
8299 if (io_fflush(orig) < 0)
8300 rb_sys_fail_on_write(fptr);
8301 }
8302
8303 /* copy rb_io_t structure */
8304 fptr->mode = orig->mode | (fptr->mode & FMODE_PREP);
8305 fptr->pid = orig->pid;
8306 fptr->lineno = orig->lineno;
8307 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8308 else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
8309 fptr_copy_finalizer(fptr, orig);
8310
8311 fd = fptr->fd;
8312 fd2 = orig->fd;
8313 if (fd != fd2) {
8314 if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->stdio_file) {
8315 /* need to keep FILE objects of stdin, stdout and stderr */
8316 if (rb_cloexec_dup2(fd2, fd) < 0)
8317 rb_sys_fail_path(orig->pathv);
8318 rb_update_max_fd(fd);
8319 }
8320 else {
8321 fclose(fptr->stdio_file);
8322 fptr->stdio_file = 0;
8323 fptr->fd = -1;
8324 if (rb_cloexec_dup2(fd2, fd) < 0)
8325 rb_sys_fail_path(orig->pathv);
8326 rb_update_max_fd(fd);
8327 fptr->fd = fd;
8328 }
8330 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8331 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8332 rb_sys_fail_path(fptr->pathv);
8333 }
8334 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8335 rb_sys_fail_path(orig->pathv);
8336 }
8337 }
8338 }
8339
8340 if (fptr->mode & FMODE_BINMODE) {
8341 rb_io_binmode(io);
8342 }
8343
8344 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8345 return io;
8346}
8347
8348#ifdef _WIN32
8349int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8350#else
8351static int
8352rb_freopen(VALUE fname, const char *mode, FILE *fp)
8353{
8354 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8355 RB_GC_GUARD(fname);
8356 return errno;
8357 }
8358 return 0;
8359}
8360#endif
8361
8362/*
8363 * call-seq:
8364 * reopen(other_io) -> self
8365 * reopen(path, mode = 'r', **opts) -> self
8366 *
8367 * Reassociates the stream with another stream,
8368 * which may be of a different class.
8369 * This method may be used to redirect an existing stream
8370 * to a new destination.
8371 *
8372 * With argument +other_io+ given, reassociates with that stream:
8373 *
8374 * # Redirect $stdin from a file.
8375 * f = File.open('t.txt')
8376 * $stdin.reopen(f)
8377 * f.close
8378 *
8379 * # Redirect $stdout to a file.
8380 * f = File.open('t.tmp', 'w')
8381 * $stdout.reopen(f)
8382 * f.close
8383 *
8384 * With argument +path+ given, reassociates with a new stream to that file path:
8385 *
8386 * $stdin.reopen('t.txt')
8387 * $stdout.reopen('t.tmp', 'w')
8388 *
8389 * Optional keyword arguments +opts+ specify:
8390 *
8391 * - {Open Options}[rdoc-ref:IO@Open+Options].
8392 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8393 *
8394 */
8395
8396static VALUE
8397rb_io_reopen(int argc, VALUE *argv, VALUE file)
8398{
8399 VALUE fname, nmode, opt;
8400 int oflags;
8401 rb_io_t *fptr;
8402
8403 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8404 VALUE tmp = rb_io_check_io(fname);
8405 if (!NIL_P(tmp)) {
8406 return io_reopen(file, tmp);
8407 }
8408 }
8409
8410 FilePathValue(fname);
8411 rb_io_taint_check(file);
8412 fptr = RFILE(file)->fptr;
8413 if (!fptr) {
8414 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8415 }
8416
8417 if (!NIL_P(nmode) || !NIL_P(opt)) {
8418 int fmode;
8419 convconfig_t convconfig;
8420
8421 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8422 if (IS_PREP_STDIO(fptr) &&
8423 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8424 (fptr->mode & FMODE_READWRITE)) {
8426 "%s can't change access mode from \"%s\" to \"%s\"",
8427 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8428 rb_io_fmode_modestr(fmode));
8429 }
8430 fptr->mode = fmode;
8431 fptr->encs = convconfig;
8432 }
8433 else {
8434 oflags = rb_io_fmode_oflags(fptr->mode);
8435 }
8436
8437 fptr->pathv = fname;
8438 if (fptr->fd < 0) {
8439 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8440 fptr->stdio_file = 0;
8441 return file;
8442 }
8443
8444 if (fptr->mode & FMODE_WRITABLE) {
8445 if (io_fflush(fptr) < 0)
8446 rb_sys_fail_on_write(fptr);
8447 }
8448 fptr->rbuf.off = fptr->rbuf.len = 0;
8449
8450 if (fptr->stdio_file) {
8451 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8452 rb_io_oflags_modestr(oflags),
8453 fptr->stdio_file);
8454 if (e) rb_syserr_fail_path(e, fptr->pathv);
8455 fptr->fd = fileno(fptr->stdio_file);
8456 rb_fd_fix_cloexec(fptr->fd);
8457#ifdef USE_SETVBUF
8458 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8459 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8460#endif
8461 if (fptr->stdio_file == stderr) {
8462 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8463 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8464 }
8465 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8466 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8467 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8468 }
8469 }
8470 else {
8471 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8472 int err = 0;
8473 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8474 err = errno;
8475 (void)close(tmpfd);
8476 if (err) {
8477 rb_syserr_fail_path(err, fptr->pathv);
8478 }
8479 }
8480
8481 return file;
8482}
8483
8484/* :nodoc: */
8485static VALUE
8486rb_io_init_copy(VALUE dest, VALUE io)
8487{
8488 rb_io_t *fptr, *orig;
8489 int fd;
8490 VALUE write_io;
8491 rb_off_t pos;
8492
8493 io = rb_io_get_io(io);
8494 if (!OBJ_INIT_COPY(dest, io)) return dest;
8495 GetOpenFile(io, orig);
8496 MakeOpenFile(dest, fptr);
8497
8498 rb_io_flush(io);
8499
8500 /* copy rb_io_t structure */
8501 fptr->mode = orig->mode & ~FMODE_PREP;
8502 fptr->encs = orig->encs;
8503 fptr->pid = orig->pid;
8504 fptr->lineno = orig->lineno;
8505 fptr->timeout = orig->timeout;
8506 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8507 fptr_copy_finalizer(fptr, orig);
8508
8509 fd = ruby_dup(orig->fd);
8510 fptr->fd = fd;
8511 pos = io_tell(orig);
8512 if (0 <= pos)
8513 io_seek(fptr, pos, SEEK_SET);
8514 if (fptr->mode & FMODE_BINMODE) {
8515 rb_io_binmode(dest);
8516 }
8517
8518 write_io = GetWriteIO(io);
8519 if (io != write_io) {
8520 write_io = rb_obj_dup(write_io);
8521 fptr->tied_io_for_writing = write_io;
8522 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8523 }
8524
8525 return dest;
8526}
8527
8528/*
8529 * call-seq:
8530 * printf(format_string, *objects) -> nil
8531 *
8532 * Formats and writes +objects+ to the stream.
8533 *
8534 * For details on +format_string+, see
8535 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8536 *
8537 */
8538
8539VALUE
8540rb_io_printf(int argc, const VALUE *argv, VALUE out)
8541{
8542 rb_io_write(out, rb_f_sprintf(argc, argv));
8543 return Qnil;
8544}
8545
8546/*
8547 * call-seq:
8548 * printf(format_string, *objects) -> nil
8549 * printf(io, format_string, *objects) -> nil
8550 *
8551 * Equivalent to:
8552 *
8553 * io.write(sprintf(format_string, *objects))
8554 *
8555 * For details on +format_string+, see
8556 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8557 *
8558 * With the single argument +format_string+, formats +objects+ into the string,
8559 * then writes the formatted string to $stdout:
8560 *
8561 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8562 *
8563 * Output (on $stdout):
8564 *
8565 * 0024 24 24.00#
8566 *
8567 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8568 * then writes the formatted string to +io+:
8569 *
8570 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8571 *
8572 * Output (on $stderr):
8573 *
8574 * 0024 24 24.00# => nil
8575 *
8576 * With no arguments, does nothing.
8577 *
8578 */
8579
8580static VALUE
8581rb_f_printf(int argc, VALUE *argv, VALUE _)
8582{
8583 VALUE out;
8584
8585 if (argc == 0) return Qnil;
8586 if (RB_TYPE_P(argv[0], T_STRING)) {
8587 out = rb_ractor_stdout();
8588 }
8589 else {
8590 out = argv[0];
8591 argv++;
8592 argc--;
8593 }
8594 rb_io_write(out, rb_f_sprintf(argc, argv));
8595
8596 return Qnil;
8597}
8598
8599static void
8600deprecated_str_setter(VALUE val, ID id, VALUE *var)
8601{
8602 rb_str_setter(val, id, &val);
8603 if (!NIL_P(val)) {
8604 rb_warn_deprecated("`%s'", NULL, rb_id2name(id));
8605 }
8606 *var = val;
8607}
8608
8609/*
8610 * call-seq:
8611 * print(*objects) -> nil
8612 *
8613 * Writes the given objects to the stream; returns +nil+.
8614 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8615 * (<tt>$\</tt>), if it is not +nil+.
8616 * See {Line IO}[rdoc-ref:IO@Line+IO].
8617 *
8618 * With argument +objects+ given, for each object:
8619 *
8620 * - Converts via its method +to_s+ if not a string.
8621 * - Writes to the stream.
8622 * - If not the last object, writes the output field separator
8623 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8624 *
8625 * With default separators:
8626 *
8627 * f = File.open('t.tmp', 'w+')
8628 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8629 * p $OUTPUT_RECORD_SEPARATOR
8630 * p $OUTPUT_FIELD_SEPARATOR
8631 * f.print(*objects)
8632 * f.rewind
8633 * p f.read
8634 * f.close
8635 *
8636 * Output:
8637 *
8638 * nil
8639 * nil
8640 * "00.00/10+0izerozero"
8641 *
8642 * With specified separators:
8643 *
8644 * $\ = "\n"
8645 * $, = ','
8646 * f.rewind
8647 * f.print(*objects)
8648 * f.rewind
8649 * p f.read
8650 *
8651 * Output:
8652 *
8653 * "0,0.0,0/1,0+0i,zero,zero\n"
8654 *
8655 * With no argument given, writes the content of <tt>$_</tt>
8656 * (which is usually the most recent user input):
8657 *
8658 * f = File.open('t.tmp', 'w+')
8659 * gets # Sets $_ to the most recent user input.
8660 * f.print
8661 * f.close
8662 *
8663 */
8664
8665VALUE
8666rb_io_print(int argc, const VALUE *argv, VALUE out)
8667{
8668 int i;
8669 VALUE line;
8670
8671 /* if no argument given, print `$_' */
8672 if (argc == 0) {
8673 argc = 1;
8674 line = rb_lastline_get();
8675 argv = &line;
8676 }
8677 if (argc > 1 && !NIL_P(rb_output_fs)) {
8678 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8679 }
8680 for (i=0; i<argc; i++) {
8681 if (!NIL_P(rb_output_fs) && i>0) {
8682 rb_io_write(out, rb_output_fs);
8683 }
8684 rb_io_write(out, argv[i]);
8685 }
8686 if (argc > 0 && !NIL_P(rb_output_rs)) {
8688 }
8689
8690 return Qnil;
8691}
8692
8693/*
8694 * call-seq:
8695 * print(*objects) -> nil
8696 *
8697 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8698 * this method is the straightforward way to write to <tt>$stdout</tt>.
8699 *
8700 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8701 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8702 * <tt>$\</tt>), if it is not +nil+.
8703 *
8704 * With argument +objects+ given, for each object:
8705 *
8706 * - Converts via its method +to_s+ if not a string.
8707 * - Writes to <tt>stdout</tt>.
8708 * - If not the last object, writes the output field separator
8709 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8710 *
8711 * With default separators:
8712 *
8713 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8714 * $OUTPUT_RECORD_SEPARATOR
8715 * $OUTPUT_FIELD_SEPARATOR
8716 * print(*objects)
8717 *
8718 * Output:
8719 *
8720 * nil
8721 * nil
8722 * 00.00/10+0izerozero
8723 *
8724 * With specified separators:
8725 *
8726 * $OUTPUT_RECORD_SEPARATOR = "\n"
8727 * $OUTPUT_FIELD_SEPARATOR = ','
8728 * print(*objects)
8729 *
8730 * Output:
8731 *
8732 * 0,0.0,0/1,0+0i,zero,zero
8733 *
8734 * With no argument given, writes the content of <tt>$_</tt>
8735 * (which is usually the most recent user input):
8736 *
8737 * gets # Sets $_ to the most recent user input.
8738 * print # Prints $_.
8739 *
8740 */
8741
8742static VALUE
8743rb_f_print(int argc, const VALUE *argv, VALUE _)
8744{
8745 rb_io_print(argc, argv, rb_ractor_stdout());
8746 return Qnil;
8747}
8748
8749/*
8750 * call-seq:
8751 * putc(object) -> object
8752 *
8753 * Writes a character to the stream.
8754 * See {Character IO}[rdoc-ref:IO@Character+IO].
8755 *
8756 * If +object+ is numeric, converts to integer if necessary,
8757 * then writes the character whose code is the
8758 * least significant byte;
8759 * if +object+ is a string, writes the first character:
8760 *
8761 * $stdout.putc "A"
8762 * $stdout.putc 65
8763 *
8764 * Output:
8765 *
8766 * AA
8767 *
8768 */
8769
8770static VALUE
8771rb_io_putc(VALUE io, VALUE ch)
8772{
8773 VALUE str;
8774 if (RB_TYPE_P(ch, T_STRING)) {
8775 str = rb_str_substr(ch, 0, 1);
8776 }
8777 else {
8778 char c = NUM2CHR(ch);
8779 str = rb_str_new(&c, 1);
8780 }
8781 rb_io_write(io, str);
8782 return ch;
8783}
8784
8785#define forward(obj, id, argc, argv) \
8786 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8787#define forward_public(obj, id, argc, argv) \
8788 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8789#define forward_current(id, argc, argv) \
8790 forward_public(ARGF.current_file, id, argc, argv)
8791
8792/*
8793 * call-seq:
8794 * putc(int) -> int
8795 *
8796 * Equivalent to:
8797 *
8798 * $stdout.putc(int)
8799 *
8800 * See IO#putc for important information regarding multi-byte characters.
8801 *
8802 */
8803
8804static VALUE
8805rb_f_putc(VALUE recv, VALUE ch)
8806{
8807 VALUE r_stdout = rb_ractor_stdout();
8808 if (recv == r_stdout) {
8809 return rb_io_putc(recv, ch);
8810 }
8811 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8812}
8813
8814
8815int
8816rb_str_end_with_asciichar(VALUE str, int c)
8817{
8818 long len = RSTRING_LEN(str);
8819 const char *ptr = RSTRING_PTR(str);
8820 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8821 int n;
8822
8823 if (len == 0) return 0;
8824 if ((n = rb_enc_mbminlen(enc)) == 1) {
8825 return ptr[len - 1] == c;
8826 }
8827 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8828}
8829
8830static VALUE
8831io_puts_ary(VALUE ary, VALUE out, int recur)
8832{
8833 VALUE tmp;
8834 long i;
8835
8836 if (recur) {
8837 tmp = rb_str_new2("[...]");
8838 rb_io_puts(1, &tmp, out);
8839 return Qtrue;
8840 }
8841 ary = rb_check_array_type(ary);
8842 if (NIL_P(ary)) return Qfalse;
8843 for (i=0; i<RARRAY_LEN(ary); i++) {
8844 tmp = RARRAY_AREF(ary, i);
8845 rb_io_puts(1, &tmp, out);
8846 }
8847 return Qtrue;
8848}
8849
8850/*
8851 * call-seq:
8852 * puts(*objects) -> nil
8853 *
8854 * Writes the given +objects+ to the stream, which must be open for writing;
8855 * returns +nil+.\
8856 * Writes a newline after each that does not already end with a newline sequence.
8857 * If called without arguments, writes a newline.
8858 * See {Line IO}[rdoc-ref:IO@Line+IO].
8859 *
8860 * Note that each added newline is the character <tt>"\n"<//tt>,
8861 * not the output record separator (<tt>$\</tt>).
8862 *
8863 * Treatment for each object:
8864 *
8865 * - \String: writes the string.
8866 * - Neither string nor array: writes <tt>object.to_s</tt>.
8867 * - \Array: writes each element of the array; arrays may be nested.
8868 *
8869 * To keep these examples brief, we define this helper method:
8870 *
8871 * def show(*objects)
8872 * # Puts objects to file.
8873 * f = File.new('t.tmp', 'w+')
8874 * f.puts(objects)
8875 * # Return file content.
8876 * f.rewind
8877 * p f.read
8878 * f.close
8879 * end
8880 *
8881 * # Strings without newlines.
8882 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8883 * # Strings, some with newlines.
8884 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8885 *
8886 * # Neither strings nor arrays:
8887 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8888 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8889 *
8890 * # Array of strings.
8891 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8892 * # Nested arrays.
8893 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8894 *
8895 */
8896
8897VALUE
8898rb_io_puts(int argc, const VALUE *argv, VALUE out)
8899{
8900 VALUE line, args[2];
8901
8902 /* if no argument given, print newline. */
8903 if (argc == 0) {
8905 return Qnil;
8906 }
8907 for (int i = 0; i < argc; i++) {
8908 // Convert the argument to a string:
8909 if (RB_TYPE_P(argv[i], T_STRING)) {
8910 line = argv[i];
8911 }
8912 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8913 continue;
8914 }
8915 else {
8916 line = rb_obj_as_string(argv[i]);
8917 }
8918
8919 // Write the line:
8920 int n = 0;
8921 if (RSTRING_LEN(line) == 0) {
8922 args[n++] = rb_default_rs;
8923 }
8924 else {
8925 args[n++] = line;
8926 if (!rb_str_end_with_asciichar(line, '\n')) {
8927 args[n++] = rb_default_rs;
8928 }
8929 }
8930
8931 rb_io_writev(out, n, args);
8932 }
8933
8934 return Qnil;
8935}
8936
8937/*
8938 * call-seq:
8939 * puts(*objects) -> nil
8940 *
8941 * Equivalent to
8942 *
8943 * $stdout.puts(objects)
8944 */
8945
8946static VALUE
8947rb_f_puts(int argc, VALUE *argv, VALUE recv)
8948{
8949 VALUE r_stdout = rb_ractor_stdout();
8950 if (recv == r_stdout) {
8951 return rb_io_puts(argc, argv, recv);
8952 }
8953 return forward(r_stdout, rb_intern("puts"), argc, argv);
8954}
8955
8956static VALUE
8957rb_p_write(VALUE str)
8958{
8959 VALUE args[2];
8960 args[0] = str;
8961 args[1] = rb_default_rs;
8962 VALUE r_stdout = rb_ractor_stdout();
8963 if (RB_TYPE_P(r_stdout, T_FILE) &&
8964 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
8965 io_writev(2, args, r_stdout);
8966 }
8967 else {
8968 rb_io_writev(r_stdout, 2, args);
8969 }
8970 return Qnil;
8971}
8972
8973void
8974rb_p(VALUE obj) /* for debug print within C code */
8975{
8976 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
8977}
8978
8979static VALUE
8980rb_p_result(int argc, const VALUE *argv)
8981{
8982 VALUE ret = Qnil;
8983
8984 if (argc == 1) {
8985 ret = argv[0];
8986 }
8987 else if (argc > 1) {
8988 ret = rb_ary_new4(argc, argv);
8989 }
8990 VALUE r_stdout = rb_ractor_stdout();
8991 if (RB_TYPE_P(r_stdout, T_FILE)) {
8992 rb_uninterruptible(rb_io_flush, r_stdout);
8993 }
8994 return ret;
8995}
8996
8997/*
8998 * call-seq:
8999 * p(object) -> obj
9000 * p(*objects) -> array of objects
9001 * p -> nil
9002 *
9003 * For each object +obj+, executes:
9004 *
9005 * $stdout.write(obj.inspect, "\n")
9006 *
9007 * With one object given, returns the object;
9008 * with multiple objects given, returns an array containing the objects;
9009 * with no object given, returns +nil+.
9010 *
9011 * Examples:
9012 *
9013 * r = Range.new(0, 4)
9014 * p r # => 0..4
9015 * p [r, r, r] # => [0..4, 0..4, 0..4]
9016 * p # => nil
9017 *
9018 * Output:
9019 *
9020 * 0..4
9021 * [0..4, 0..4, 0..4]
9022 *
9023 */
9024
9025static VALUE
9026rb_f_p(int argc, VALUE *argv, VALUE self)
9027{
9028 int i;
9029 for (i=0; i<argc; i++) {
9030 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9031 rb_uninterruptible(rb_p_write, inspected);
9032 }
9033 return rb_p_result(argc, argv);
9034}
9035
9036/*
9037 * call-seq:
9038 * display(port = $>) -> nil
9039 *
9040 * Writes +self+ on the given port:
9041 *
9042 * 1.display
9043 * "cat".display
9044 * [ 4, 5, 6 ].display
9045 * puts
9046 *
9047 * Output:
9048 *
9049 * 1cat[4, 5, 6]
9050 *
9051 */
9052
9053static VALUE
9054rb_obj_display(int argc, VALUE *argv, VALUE self)
9055{
9056 VALUE out;
9057
9058 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9059 rb_io_write(out, self);
9060
9061 return Qnil;
9062}
9063
9064static int
9065rb_stderr_to_original_p(VALUE err)
9066{
9067 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9068}
9069
9070void
9071rb_write_error2(const char *mesg, long len)
9072{
9073 VALUE out = rb_ractor_stderr();
9074 if (rb_stderr_to_original_p(out)) {
9075#ifdef _WIN32
9076 if (isatty(fileno(stderr))) {
9077 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9078 }
9079#endif
9080 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9081 /* failed to write to stderr, what can we do? */
9082 return;
9083 }
9084 }
9085 else {
9086 rb_io_write(out, rb_str_new(mesg, len));
9087 }
9088}
9089
9090void
9091rb_write_error(const char *mesg)
9092{
9093 rb_write_error2(mesg, strlen(mesg));
9094}
9095
9096void
9097rb_write_error_str(VALUE mesg)
9098{
9099 VALUE out = rb_ractor_stderr();
9100 /* a stopgap measure for the time being */
9101 if (rb_stderr_to_original_p(out)) {
9102 size_t len = (size_t)RSTRING_LEN(mesg);
9103#ifdef _WIN32
9104 if (isatty(fileno(stderr))) {
9105 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9106 }
9107#endif
9108 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9109 RB_GC_GUARD(mesg);
9110 return;
9111 }
9112 }
9113 else {
9114 /* may unlock GVL, and */
9115 rb_io_write(out, mesg);
9116 }
9117}
9118
9119int
9120rb_stderr_tty_p(void)
9121{
9122 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9123 return isatty(fileno(stderr));
9124 return 0;
9125}
9126
9127static void
9128must_respond_to(ID mid, VALUE val, ID id)
9129{
9130 if (!rb_respond_to(val, mid)) {
9131 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9132 rb_id2str(id), rb_id2str(mid),
9133 rb_obj_class(val));
9134 }
9135}
9136
9137static void
9138stdin_setter(VALUE val, ID id, VALUE *ptr)
9139{
9141}
9142
9143static VALUE
9144stdin_getter(ID id, VALUE *ptr)
9145{
9146 return rb_ractor_stdin();
9147}
9148
9149static void
9150stdout_setter(VALUE val, ID id, VALUE *ptr)
9151{
9152 must_respond_to(id_write, val, id);
9154}
9155
9156static VALUE
9157stdout_getter(ID id, VALUE *ptr)
9158{
9159 return rb_ractor_stdout();
9160}
9161
9162static void
9163stderr_setter(VALUE val, ID id, VALUE *ptr)
9164{
9165 must_respond_to(id_write, val, id);
9167}
9168
9169static VALUE
9170stderr_getter(ID id, VALUE *ptr)
9171{
9172 return rb_ractor_stderr();
9173}
9174
9175static VALUE
9176prep_io(int fd, int fmode, VALUE klass, const char *path)
9177{
9178 rb_io_t *fp;
9179 VALUE io = io_alloc(klass);
9180
9181 MakeOpenFile(io, fp);
9182 fp->self = io;
9183 fp->fd = fd;
9184 fp->mode = fmode;
9185 fp->timeout = Qnil;
9186 if (!io_check_tty(fp)) {
9187#ifdef __CYGWIN__
9188 fp->mode |= FMODE_BINMODE;
9189 setmode(fd, O_BINARY);
9190#endif
9191 }
9192 if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
9193 rb_update_max_fd(fd);
9194
9195 return io;
9196}
9197
9198VALUE
9199rb_io_fdopen(int fd, int oflags, const char *path)
9200{
9201 VALUE klass = rb_cIO;
9202
9203 if (path && strcmp(path, "-")) klass = rb_cFile;
9204 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9205}
9206
9207static VALUE
9208prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9209{
9210 rb_io_t *fptr;
9211 VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
9212
9213 GetOpenFile(io, fptr);
9215#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9216 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9217 if (fmode & FMODE_READABLE) {
9219 }
9220#endif
9221 fptr->stdio_file = f;
9222
9223 return io;
9224}
9225
9226VALUE
9227rb_io_prep_stdin(void)
9228{
9229 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9230}
9231
9232VALUE
9233rb_io_prep_stdout(void)
9234{
9235 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9236}
9237
9238VALUE
9239rb_io_prep_stderr(void)
9240{
9241 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9242}
9243
9244FILE *
9246{
9247 if (!fptr->stdio_file) {
9248 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9249 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9250 }
9251 return fptr->stdio_file;
9252}
9253
9254static inline void
9255rb_io_buffer_init(rb_io_buffer_t *buf)
9256{
9257 buf->ptr = NULL;
9258 buf->off = 0;
9259 buf->len = 0;
9260 buf->capa = 0;
9261}
9262
9263static inline rb_io_t *
9264rb_io_fptr_new(void)
9265{
9266 rb_io_t *fp = ALLOC(rb_io_t);
9267 fp->self = Qnil;
9268 fp->fd = -1;
9269 fp->stdio_file = NULL;
9270 fp->mode = 0;
9271 fp->pid = 0;
9272 fp->lineno = 0;
9273 fp->pathv = Qnil;
9274 fp->finalize = 0;
9275 rb_io_buffer_init(&fp->wbuf);
9276 rb_io_buffer_init(&fp->rbuf);
9277 rb_io_buffer_init(&fp->cbuf);
9278 fp->readconv = NULL;
9279 fp->writeconv = NULL;
9281 fp->writeconv_pre_ecflags = 0;
9283 fp->writeconv_initialized = 0;
9284 fp->tied_io_for_writing = 0;
9285 fp->encs.enc = NULL;
9286 fp->encs.enc2 = NULL;
9287 fp->encs.ecflags = 0;
9288 fp->encs.ecopts = Qnil;
9289 fp->write_lock = Qnil;
9290 fp->timeout = Qnil;
9291 return fp;
9292}
9293
9294rb_io_t *
9295rb_io_make_open_file(VALUE obj)
9296{
9297 rb_io_t *fp = 0;
9298
9299 Check_Type(obj, T_FILE);
9300 if (RFILE(obj)->fptr) {
9301 rb_io_close(obj);
9302 rb_io_fptr_finalize(RFILE(obj)->fptr);
9303 RFILE(obj)->fptr = 0;
9304 }
9305 fp = rb_io_fptr_new();
9306 fp->self = obj;
9307 RFILE(obj)->fptr = fp;
9308 return fp;
9309}
9310
9311/*
9312 * call-seq:
9313 * IO.new(fd, mode = 'r', **opts) -> io
9314 *
9315 * Creates and returns a new \IO object (file stream) from a file descriptor.
9316 *
9317 * \IO.new may be useful for interaction with low-level libraries.
9318 * For higher-level interactions, it may be simpler to create
9319 * the file stream using File.open.
9320 *
9321 * Argument +fd+ must be a valid file descriptor (integer):
9322 *
9323 * path = 't.tmp'
9324 * fd = IO.sysopen(path) # => 3
9325 * IO.new(fd) # => #<IO:fd 3>
9326 *
9327 * The new \IO object does not inherit encoding
9328 * (because the integer file descriptor does not have an encoding):
9329 *
9330 * fd = IO.sysopen('t.rus', 'rb')
9331 * io = IO.new(fd)
9332 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9333 *
9334 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9335 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9336 *
9337 * IO.new(fd, 'w') # => #<IO:fd 3>
9338 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9339 *
9340 * Optional keyword arguments +opts+ specify:
9341 *
9342 * - {Open Options}[rdoc-ref:IO@Open+Options].
9343 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9344 *
9345 * Examples:
9346 *
9347 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9348 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9349 *
9350 */
9351
9352static VALUE
9353rb_io_initialize(int argc, VALUE *argv, VALUE io)
9354{
9355 VALUE fnum, vmode;
9356 rb_io_t *fp;
9357 int fd, fmode, oflags = O_RDONLY;
9358 convconfig_t convconfig;
9359 VALUE opt;
9360#if defined(HAVE_FCNTL) && defined(F_GETFL)
9361 int ofmode;
9362#else
9363 struct stat st;
9364#endif
9365
9366
9367 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9368 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9369
9370 fd = NUM2INT(fnum);
9371 if (rb_reserved_fd_p(fd)) {
9372 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9373 }
9374#if defined(HAVE_FCNTL) && defined(F_GETFL)
9375 oflags = fcntl(fd, F_GETFL);
9376 if (oflags == -1) rb_sys_fail(0);
9377#else
9378 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9379#endif
9380 rb_update_max_fd(fd);
9381#if defined(HAVE_FCNTL) && defined(F_GETFL)
9382 ofmode = rb_io_oflags_fmode(oflags);
9383 if (NIL_P(vmode)) {
9384 fmode = ofmode;
9385 }
9386 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9387 VALUE error = INT2FIX(EINVAL);
9389 }
9390#endif
9391 VALUE path = Qnil;
9392
9393 if (!NIL_P(opt)) {
9394 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9395 fmode |= FMODE_PREP;
9396 }
9397
9398 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9399 if (!NIL_P(path)) {
9400 StringValue(path);
9401 path = rb_str_new_frozen(path);
9402 }
9403 }
9404
9405 MakeOpenFile(io, fp);
9406 fp->self = io;
9407 fp->fd = fd;
9408 fp->mode = fmode;
9409 fp->encs = convconfig;
9410 fp->pathv = path;
9411 fp->timeout = Qnil;
9412 clear_codeconv(fp);
9413 io_check_tty(fp);
9414 if (fileno(stdin) == fd)
9415 fp->stdio_file = stdin;
9416 else if (fileno(stdout) == fd)
9417 fp->stdio_file = stdout;
9418 else if (fileno(stderr) == fd)
9419 fp->stdio_file = stderr;
9420
9421 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9422 return io;
9423}
9424
9425/*
9426 * call-seq:
9427 * set_encoding_by_bom -> encoding or nil
9428 *
9429 * If the stream begins with a BOM
9430 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9431 * consumes the BOM and sets the external encoding accordingly;
9432 * returns the result encoding if found, or +nil+ otherwise:
9433 *
9434 * File.write('t.tmp', "\u{FEFF}abc")
9435 * io = File.open('t.tmp', 'rb')
9436 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9437 * io.close
9438 *
9439 * File.write('t.tmp', 'abc')
9440 * io = File.open('t.tmp', 'rb')
9441 * io.set_encoding_by_bom # => nil
9442 * io.close
9443 *
9444 * Raises an exception if the stream is not binmode
9445 * or its encoding has already been set.
9446 *
9447 */
9448
9449static VALUE
9450rb_io_set_encoding_by_bom(VALUE io)
9451{
9452 rb_io_t *fptr;
9453
9454 GetOpenFile(io, fptr);
9455 if (!(fptr->mode & FMODE_BINMODE)) {
9456 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9457 }
9458 if (fptr->encs.enc2) {
9459 rb_raise(rb_eArgError, "encoding conversion is set");
9460 }
9461 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9462 rb_raise(rb_eArgError, "encoding is set to %s already",
9463 rb_enc_name(fptr->encs.enc));
9464 }
9465 if (!io_set_encoding_by_bom(io)) return Qnil;
9466 return rb_enc_from_encoding(fptr->encs.enc);
9467}
9468
9469/*
9470 * call-seq:
9471 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9472 *
9473 * Opens the file at the given +path+ according to the given +mode+;
9474 * creates and returns a new \File object for that file.
9475 *
9476 * The new \File object is buffered mode (or non-sync mode), unless
9477 * +filename+ is a tty.
9478 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9479 *
9480 * Argument +path+ must be a valid file path:
9481 *
9482 * f = File.new('/etc/fstab')
9483 * f.close
9484 * f = File.new('t.txt')
9485 * f.close
9486 *
9487 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9488 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9489 *
9490 * f = File.new('t.tmp', 'w')
9491 * f.close
9492 * f = File.new('t.tmp', File::RDONLY)
9493 * f.close
9494 *
9495 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9496 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9497 *
9498 * f = File.new('t.tmp', File::CREAT, 0644)
9499 * f.close
9500 * f = File.new('t.tmp', File::CREAT, 0444)
9501 * f.close
9502 *
9503 * Optional keyword arguments +opts+ specify:
9504 *
9505 * - {Open Options}[rdoc-ref:IO@Open+Options].
9506 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9507 *
9508 */
9509
9510static VALUE
9511rb_file_initialize(int argc, VALUE *argv, VALUE io)
9512{
9513 if (RFILE(io)->fptr) {
9514 rb_raise(rb_eRuntimeError, "reinitializing File");
9515 }
9516 if (0 < argc && argc < 3) {
9517 VALUE fd = rb_check_to_int(argv[0]);
9518
9519 if (!NIL_P(fd)) {
9520 argv[0] = fd;
9521 return rb_io_initialize(argc, argv, io);
9522 }
9523 }
9524 rb_open_file(argc, argv, io);
9525
9526 return io;
9527}
9528
9529/* :nodoc: */
9530static VALUE
9531rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9532{
9533 if (rb_block_given_p()) {
9534 VALUE cname = rb_obj_as_string(klass);
9535
9536 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9537 cname, cname);
9538 }
9539 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9540}
9541
9542
9543/*
9544 * call-seq:
9545 * IO.for_fd(fd, mode = 'r', **opts) -> io
9546 *
9547 * Synonym for IO.new.
9548 *
9549 */
9550
9551static VALUE
9552rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9553{
9554 VALUE io = rb_obj_alloc(klass);
9555 rb_io_initialize(argc, argv, io);
9556 return io;
9557}
9558
9559/*
9560 * call-seq:
9561 * ios.autoclose? -> true or false
9562 *
9563 * Returns +true+ if the underlying file descriptor of _ios_ will be
9564 * closed automatically at its finalization, otherwise +false+.
9565 */
9566
9567static VALUE
9568rb_io_autoclose_p(VALUE io)
9569{
9570 rb_io_t *fptr = RFILE(io)->fptr;
9571 rb_io_check_closed(fptr);
9572 return RBOOL(!(fptr->mode & FMODE_PREP));
9573}
9574
9575/*
9576 * call-seq:
9577 * io.autoclose = bool -> true or false
9578 *
9579 * Sets auto-close flag.
9580 *
9581 * f = open("/dev/null")
9582 * IO.for_fd(f.fileno)
9583 * # ...
9584 * f.gets # may cause Errno::EBADF
9585 *
9586 * f = open("/dev/null")
9587 * IO.for_fd(f.fileno).autoclose = false
9588 * # ...
9589 * f.gets # won't cause Errno::EBADF
9590 */
9591
9592static VALUE
9593rb_io_set_autoclose(VALUE io, VALUE autoclose)
9594{
9595 rb_io_t *fptr;
9596 GetOpenFile(io, fptr);
9597 if (!RTEST(autoclose))
9598 fptr->mode |= FMODE_PREP;
9599 else
9600 fptr->mode &= ~FMODE_PREP;
9601 return autoclose;
9602}
9603
9604static VALUE
9605io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9606{
9607 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9608
9609 if (!RB_TEST(result)) {
9610 return Qnil;
9611 }
9612
9613 int mask = RB_NUM2INT(result);
9614
9615 if (mask & event) {
9616 if (return_io)
9617 return io;
9618 else
9619 return result;
9620 }
9621 else {
9622 return Qfalse;
9623 }
9624}
9625
9626/*
9627 * call-seq:
9628 * io.wait_readable -> truthy or falsy
9629 * io.wait_readable(timeout) -> truthy or falsy
9630 *
9631 * Waits until IO is readable and returns a truthy value, or a falsy
9632 * value when times out. Returns a truthy value immediately when
9633 * buffered data is available.
9634 */
9635
9636static VALUE
9637io_wait_readable(int argc, VALUE *argv, VALUE io)
9638{
9639 rb_io_t *fptr;
9640
9641 RB_IO_POINTER(io, fptr);
9643
9644 if (rb_io_read_pending(fptr)) return Qtrue;
9645
9646 rb_check_arity(argc, 0, 1);
9647 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9648
9649 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9650}
9651
9652/*
9653 * call-seq:
9654 * io.wait_writable -> truthy or falsy
9655 * io.wait_writable(timeout) -> truthy or falsy
9656 *
9657 * Waits until IO is writable and returns a truthy value or a falsy
9658 * value when times out.
9659 */
9660static VALUE
9661io_wait_writable(int argc, VALUE *argv, VALUE io)
9662{
9663 rb_io_t *fptr;
9664
9665 RB_IO_POINTER(io, fptr);
9667
9668 rb_check_arity(argc, 0, 1);
9669 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9670
9671 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9672}
9673
9674/*
9675 * call-seq:
9676 * io.wait_priority -> truthy or falsy
9677 * io.wait_priority(timeout) -> truthy or falsy
9678 *
9679 * Waits until IO is priority and returns a truthy value or a falsy
9680 * value when times out. Priority data is sent and received using
9681 * the Socket::MSG_OOB flag and is typically limited to streams.
9682 */
9683static VALUE
9684io_wait_priority(int argc, VALUE *argv, VALUE io)
9685{
9686 rb_io_t *fptr = NULL;
9687
9688 RB_IO_POINTER(io, fptr);
9690
9691 if (rb_io_read_pending(fptr)) return Qtrue;
9692
9693 rb_check_arity(argc, 0, 1);
9694 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9695
9696 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9697}
9698
9699static int
9700wait_mode_sym(VALUE mode)
9701{
9702 if (mode == ID2SYM(rb_intern("r"))) {
9703 return RB_WAITFD_IN;
9704 }
9705 if (mode == ID2SYM(rb_intern("read"))) {
9706 return RB_WAITFD_IN;
9707 }
9708 if (mode == ID2SYM(rb_intern("readable"))) {
9709 return RB_WAITFD_IN;
9710 }
9711 if (mode == ID2SYM(rb_intern("w"))) {
9712 return RB_WAITFD_OUT;
9713 }
9714 if (mode == ID2SYM(rb_intern("write"))) {
9715 return RB_WAITFD_OUT;
9716 }
9717 if (mode == ID2SYM(rb_intern("writable"))) {
9718 return RB_WAITFD_OUT;
9719 }
9720 if (mode == ID2SYM(rb_intern("rw"))) {
9721 return RB_WAITFD_IN|RB_WAITFD_OUT;
9722 }
9723 if (mode == ID2SYM(rb_intern("read_write"))) {
9724 return RB_WAITFD_IN|RB_WAITFD_OUT;
9725 }
9726 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9727 return RB_WAITFD_IN|RB_WAITFD_OUT;
9728 }
9729
9730 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9731}
9732
9733static inline rb_io_event_t
9734io_event_from_value(VALUE value)
9735{
9736 int events = RB_NUM2INT(value);
9737
9738 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9739
9740 return events;
9741}
9742
9743/*
9744 * call-seq:
9745 * io.wait(events, timeout) -> event mask, false or nil
9746 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9747 *
9748 * Waits until the IO becomes ready for the specified events and returns the
9749 * subset of events that become ready, or a falsy value when times out.
9750 *
9751 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9752 * +IO::PRIORITY+.
9753 *
9754 * Returns an event mask (truthy value) immediately when buffered data is available.
9755 *
9756 * Optional parameter +mode+ is one of +:read+, +:write+, or
9757 * +:read_write+.
9758 */
9759
9760static VALUE
9761io_wait(int argc, VALUE *argv, VALUE io)
9762{
9763 VALUE timeout = Qundef;
9764 rb_io_event_t events = 0;
9765 int return_io = 0;
9766
9767 // The documented signature for this method is actually incorrect.
9768 // A single timeout is allowed in any position, and multiple symbols can be given.
9769 // Whether this is intentional or not, I don't know, and as such I consider this to
9770 // be a legacy/slow path.
9771 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9772 // We'd prefer to return the actual mask, but this form would return the io itself:
9773 return_io = 1;
9774
9775 // Slow/messy path:
9776 for (int i = 0; i < argc; i += 1) {
9777 if (RB_SYMBOL_P(argv[i])) {
9778 events |= wait_mode_sym(argv[i]);
9779 }
9780 else if (UNDEF_P(timeout)) {
9781 rb_time_interval(timeout = argv[i]);
9782 }
9783 else {
9784 rb_raise(rb_eArgError, "timeout given more than once");
9785 }
9786 }
9787
9788 if (UNDEF_P(timeout)) timeout = Qnil;
9789
9790 if (events == 0) {
9791 events = RUBY_IO_READABLE;
9792 }
9793 }
9794 else /* argc == 2 and neither are symbols */ {
9795 // This is the fast path:
9796 events = io_event_from_value(argv[0]);
9797 timeout = argv[1];
9798 }
9799
9800 if (events & RUBY_IO_READABLE) {
9801 rb_io_t *fptr = NULL;
9802 RB_IO_POINTER(io, fptr);
9803
9804 if (rb_io_read_pending(fptr)) {
9805 // This was the original behaviour:
9806 if (return_io) return Qtrue;
9807 // New behaviour always returns an event mask:
9808 else return RB_INT2NUM(RUBY_IO_READABLE);
9809 }
9810 }
9811
9812 return io_wait_event(io, events, timeout, return_io);
9813}
9814
9815static void
9816argf_mark(void *ptr)
9817{
9818 struct argf *p = ptr;
9819 rb_gc_mark(p->filename);
9820 rb_gc_mark(p->current_file);
9821 rb_gc_mark(p->argv);
9822 rb_gc_mark(p->inplace);
9823 rb_gc_mark(p->encs.ecopts);
9824}
9825
9826static size_t
9827argf_memsize(const void *ptr)
9828{
9829 const struct argf *p = ptr;
9830 size_t size = sizeof(*p);
9831 return size;
9832}
9833
9834static const rb_data_type_t argf_type = {
9835 "ARGF",
9836 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9837 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9838};
9839
9840static inline void
9841argf_init(struct argf *p, VALUE v)
9842{
9843 p->filename = Qnil;
9844 p->current_file = Qnil;
9845 p->lineno = 0;
9846 p->argv = v;
9847}
9848
9849static VALUE
9850argf_alloc(VALUE klass)
9851{
9852 struct argf *p;
9853 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9854
9855 argf_init(p, Qnil);
9856 return argf;
9857}
9858
9859#undef rb_argv
9860
9861/* :nodoc: */
9862static VALUE
9863argf_initialize(VALUE argf, VALUE argv)
9864{
9865 memset(&ARGF, 0, sizeof(ARGF));
9866 argf_init(&ARGF, argv);
9867
9868 return argf;
9869}
9870
9871/* :nodoc: */
9872static VALUE
9873argf_initialize_copy(VALUE argf, VALUE orig)
9874{
9875 if (!OBJ_INIT_COPY(argf, orig)) return argf;
9876 ARGF = argf_of(orig);
9877 ARGF.argv = rb_obj_dup(ARGF.argv);
9878 return argf;
9879}
9880
9881/*
9882 * call-seq:
9883 * ARGF.lineno = integer -> integer
9884 *
9885 * Sets the line number of ARGF as a whole to the given Integer.
9886 *
9887 * ARGF sets the line number automatically as you read data, so normally
9888 * you will not need to set it explicitly. To access the current line number
9889 * use ARGF.lineno.
9890 *
9891 * For example:
9892 *
9893 * ARGF.lineno #=> 0
9894 * ARGF.readline #=> "This is line 1\n"
9895 * ARGF.lineno #=> 1
9896 * ARGF.lineno = 0 #=> 0
9897 * ARGF.lineno #=> 0
9898 */
9899static VALUE
9900argf_set_lineno(VALUE argf, VALUE val)
9901{
9902 ARGF.lineno = NUM2INT(val);
9903 ARGF.last_lineno = ARGF.lineno;
9904 return val;
9905}
9906
9907/*
9908 * call-seq:
9909 * ARGF.lineno -> integer
9910 *
9911 * Returns the current line number of ARGF as a whole. This value
9912 * can be set manually with ARGF.lineno=.
9913 *
9914 * For example:
9915 *
9916 * ARGF.lineno #=> 0
9917 * ARGF.readline #=> "This is line 1\n"
9918 * ARGF.lineno #=> 1
9919 */
9920static VALUE
9921argf_lineno(VALUE argf)
9922{
9923 return INT2FIX(ARGF.lineno);
9924}
9925
9926static VALUE
9927argf_forward(int argc, VALUE *argv, VALUE argf)
9928{
9929 return forward_current(rb_frame_this_func(), argc, argv);
9930}
9931
9932#define next_argv() argf_next_argv(argf)
9933#define ARGF_GENERIC_INPUT_P() \
9934 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
9935#define ARGF_FORWARD(argc, argv) do {\
9936 if (ARGF_GENERIC_INPUT_P())\
9937 return argf_forward((argc), (argv), argf);\
9938} while (0)
9939#define NEXT_ARGF_FORWARD(argc, argv) do {\
9940 if (!next_argv()) return Qnil;\
9941 ARGF_FORWARD((argc), (argv));\
9942} while (0)
9943
9944static void
9945argf_close(VALUE argf)
9946{
9947 VALUE file = ARGF.current_file;
9948 if (file == rb_stdin) return;
9949 if (RB_TYPE_P(file, T_FILE)) {
9950 rb_io_set_write_io(file, Qnil);
9951 }
9952 io_close(file);
9953 ARGF.init_p = -1;
9954}
9955
9956static int
9957argf_next_argv(VALUE argf)
9958{
9959 char *fn;
9960 rb_io_t *fptr;
9961 int stdout_binmode = 0;
9962 int fmode;
9963
9964 VALUE r_stdout = rb_ractor_stdout();
9965
9966 if (RB_TYPE_P(r_stdout, T_FILE)) {
9967 GetOpenFile(r_stdout, fptr);
9968 if (fptr->mode & FMODE_BINMODE)
9969 stdout_binmode = 1;
9970 }
9971
9972 if (ARGF.init_p == 0) {
9973 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
9974 ARGF.next_p = 1;
9975 }
9976 else {
9977 ARGF.next_p = -1;
9978 }
9979 ARGF.init_p = 1;
9980 }
9981 else {
9982 if (NIL_P(ARGF.argv)) {
9983 ARGF.next_p = -1;
9984 }
9985 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
9986 ARGF.next_p = 1;
9987 }
9988 }
9989
9990 if (ARGF.next_p == 1) {
9991 if (ARGF.init_p == 1) argf_close(argf);
9992 retry:
9993 if (RARRAY_LEN(ARGF.argv) > 0) {
9994 VALUE filename = rb_ary_shift(ARGF.argv);
9995 FilePathValue(filename);
9996 ARGF.filename = filename;
9997 filename = rb_str_encode_ospath(filename);
9998 fn = StringValueCStr(filename);
9999 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10000 ARGF.current_file = rb_stdin;
10001 if (ARGF.inplace) {
10002 rb_warn("Can't do inplace edit for stdio; skipping");
10003 goto retry;
10004 }
10005 }
10006 else {
10007 VALUE write_io = Qnil;
10008 int fr = rb_sysopen(filename, O_RDONLY, 0);
10009
10010 if (ARGF.inplace) {
10011 struct stat st;
10012#ifndef NO_SAFE_RENAME
10013 struct stat st2;
10014#endif
10015 VALUE str;
10016 int fw;
10017
10018 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10019 rb_io_close(r_stdout);
10020 }
10021 fstat(fr, &st);
10022 str = filename;
10023 if (!NIL_P(ARGF.inplace)) {
10024 VALUE suffix = ARGF.inplace;
10025 str = rb_str_dup(str);
10026 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10027 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10028 rb_enc_get(suffix), 0, Qnil))) {
10029 rb_str_append(str, suffix);
10030 }
10031#ifdef NO_SAFE_RENAME
10032 (void)close(fr);
10033 (void)unlink(RSTRING_PTR(str));
10034 if (rename(fn, RSTRING_PTR(str)) < 0) {
10035 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10036 filename, str, strerror(errno));
10037 goto retry;
10038 }
10039 fr = rb_sysopen(str, O_RDONLY, 0);
10040#else
10041 if (rename(fn, RSTRING_PTR(str)) < 0) {
10042 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10043 filename, str, strerror(errno));
10044 close(fr);
10045 goto retry;
10046 }
10047#endif
10048 }
10049 else {
10050#ifdef NO_SAFE_RENAME
10051 rb_fatal("Can't do inplace edit without backup");
10052#else
10053 if (unlink(fn) < 0) {
10054 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10055 filename, strerror(errno));
10056 close(fr);
10057 goto retry;
10058 }
10059#endif
10060 }
10061 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10062#ifndef NO_SAFE_RENAME
10063 fstat(fw, &st2);
10064#ifdef HAVE_FCHMOD
10065 fchmod(fw, st.st_mode);
10066#else
10067 chmod(fn, st.st_mode);
10068#endif
10069 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10070 int err;
10071#ifdef HAVE_FCHOWN
10072 err = fchown(fw, st.st_uid, st.st_gid);
10073#else
10074 err = chown(fn, st.st_uid, st.st_gid);
10075#endif
10076 if (err && getuid() == 0 && st2.st_uid == 0) {
10077 const char *wkfn = RSTRING_PTR(filename);
10078 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10079 filename, str, strerror(errno));
10080 (void)close(fr);
10081 (void)close(fw);
10082 (void)unlink(wkfn);
10083 goto retry;
10084 }
10085 }
10086#endif
10087 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10088 rb_ractor_stdout_set(write_io);
10089 if (stdout_binmode) rb_io_binmode(rb_stdout);
10090 }
10091 fmode = FMODE_READABLE;
10092 if (!ARGF.binmode) {
10093 fmode |= DEFAULT_TEXTMODE;
10094 }
10095 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10096 if (!NIL_P(write_io)) {
10097 rb_io_set_write_io(ARGF.current_file, write_io);
10098 }
10099 RB_GC_GUARD(filename);
10100 }
10101 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10102 GetOpenFile(ARGF.current_file, fptr);
10103 if (ARGF.encs.enc) {
10104 fptr->encs = ARGF.encs;
10105 clear_codeconv(fptr);
10106 }
10107 else {
10108 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10109 if (!ARGF.binmode) {
10111#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10112 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10113#endif
10114 }
10115 }
10116 ARGF.next_p = 0;
10117 }
10118 else {
10119 ARGF.next_p = 1;
10120 return FALSE;
10121 }
10122 }
10123 else if (ARGF.next_p == -1) {
10124 ARGF.current_file = rb_stdin;
10125 ARGF.filename = rb_str_new2("-");
10126 if (ARGF.inplace) {
10127 rb_warn("Can't do inplace edit for stdio");
10128 rb_ractor_stdout_set(orig_stdout);
10129 }
10130 }
10131 if (ARGF.init_p == -1) ARGF.init_p = 1;
10132 return TRUE;
10133}
10134
10135static VALUE
10136argf_getline(int argc, VALUE *argv, VALUE argf)
10137{
10138 VALUE line;
10139 long lineno = ARGF.lineno;
10140
10141 retry:
10142 if (!next_argv()) return Qnil;
10143 if (ARGF_GENERIC_INPUT_P()) {
10144 line = forward_current(idGets, argc, argv);
10145 }
10146 else {
10147 if (argc == 0 && rb_rs == rb_default_rs) {
10148 line = rb_io_gets(ARGF.current_file);
10149 }
10150 else {
10151 line = rb_io_getline(argc, argv, ARGF.current_file);
10152 }
10153 if (NIL_P(line) && ARGF.next_p != -1) {
10154 argf_close(argf);
10155 ARGF.next_p = 1;
10156 goto retry;
10157 }
10158 }
10159 if (!NIL_P(line)) {
10160 ARGF.lineno = ++lineno;
10161 ARGF.last_lineno = ARGF.lineno;
10162 }
10163 return line;
10164}
10165
10166static VALUE
10167argf_lineno_getter(ID id, VALUE *var)
10168{
10169 VALUE argf = *var;
10170 return INT2FIX(ARGF.last_lineno);
10171}
10172
10173static void
10174argf_lineno_setter(VALUE val, ID id, VALUE *var)
10175{
10176 VALUE argf = *var;
10177 int n = NUM2INT(val);
10178 ARGF.last_lineno = ARGF.lineno = n;
10179}
10180
10181void
10182rb_reset_argf_lineno(long n)
10183{
10184 ARGF.last_lineno = ARGF.lineno = n;
10185}
10186
10187static VALUE argf_gets(int, VALUE *, VALUE);
10188
10189/*
10190 * call-seq:
10191 * gets(sep=$/ [, getline_args]) -> string or nil
10192 * gets(limit [, getline_args]) -> string or nil
10193 * gets(sep, limit [, getline_args]) -> string or nil
10194 *
10195 * Returns (and assigns to <code>$_</code>) the next line from the list
10196 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10197 * no files are present on the command line. Returns +nil+ at end of
10198 * file. The optional argument specifies the record separator. The
10199 * separator is included with the contents of each record. A separator
10200 * of +nil+ reads the entire contents, and a zero-length separator
10201 * reads the input one paragraph at a time, where paragraphs are
10202 * divided by two consecutive newlines. If the first argument is an
10203 * integer, or optional second argument is given, the returning string
10204 * would not be longer than the given value in bytes. If multiple
10205 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10206 * the contents one file at a time.
10207 *
10208 * ARGV << "testfile"
10209 * print while gets
10210 *
10211 * <em>produces:</em>
10212 *
10213 * This is line one
10214 * This is line two
10215 * This is line three
10216 * And so on...
10217 *
10218 * The style of programming using <code>$_</code> as an implicit
10219 * parameter is gradually losing favor in the Ruby community.
10220 */
10221
10222static VALUE
10223rb_f_gets(int argc, VALUE *argv, VALUE recv)
10224{
10225 if (recv == argf) {
10226 return argf_gets(argc, argv, argf);
10227 }
10228 return forward(argf, idGets, argc, argv);
10229}
10230
10231/*
10232 * call-seq:
10233 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10234 * ARGF.gets(limit [, getline_args]) -> string or nil
10235 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10236 *
10237 * Returns the next line from the current file in ARGF.
10238 *
10239 * By default lines are assumed to be separated by <code>$/</code>;
10240 * to use a different character as a separator, supply it as a String
10241 * for the _sep_ argument.
10242 *
10243 * The optional _limit_ argument specifies how many characters of each line
10244 * to return. By default all characters are returned.
10245 *
10246 * See IO.readlines for details about getline_args.
10247 *
10248 */
10249static VALUE
10250argf_gets(int argc, VALUE *argv, VALUE argf)
10251{
10252 VALUE line;
10253
10254 line = argf_getline(argc, argv, argf);
10255 rb_lastline_set(line);
10256
10257 return line;
10258}
10259
10260VALUE
10262{
10263 VALUE line;
10264
10265 if (rb_rs != rb_default_rs) {
10266 return rb_f_gets(0, 0, argf);
10267 }
10268
10269 retry:
10270 if (!next_argv()) return Qnil;
10271 line = rb_io_gets(ARGF.current_file);
10272 if (NIL_P(line) && ARGF.next_p != -1) {
10273 rb_io_close(ARGF.current_file);
10274 ARGF.next_p = 1;
10275 goto retry;
10276 }
10277 rb_lastline_set(line);
10278 if (!NIL_P(line)) {
10279 ARGF.lineno++;
10280 ARGF.last_lineno = ARGF.lineno;
10281 }
10282
10283 return line;
10284}
10285
10286static VALUE argf_readline(int, VALUE *, VALUE);
10287
10288/*
10289 * call-seq:
10290 * readline(sep = $/, chomp: false) -> string
10291 * readline(limit, chomp: false) -> string
10292 * readline(sep, limit, chomp: false) -> string
10293 *
10294 * Equivalent to method Kernel#gets, except that it raises an exception
10295 * if called at end-of-stream:
10296 *
10297 * $ cat t.txt | ruby -e "p readlines; readline"
10298 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10299 * in `readline': end of file reached (EOFError)
10300 *
10301 * Optional keyword argument +chomp+ specifies whether line separators
10302 * are to be omitted.
10303 */
10304
10305static VALUE
10306rb_f_readline(int argc, VALUE *argv, VALUE recv)
10307{
10308 if (recv == argf) {
10309 return argf_readline(argc, argv, argf);
10310 }
10311 return forward(argf, rb_intern("readline"), argc, argv);
10312}
10313
10314
10315/*
10316 * call-seq:
10317 * ARGF.readline(sep=$/) -> string
10318 * ARGF.readline(limit) -> string
10319 * ARGF.readline(sep, limit) -> string
10320 *
10321 * Returns the next line from the current file in ARGF.
10322 *
10323 * By default lines are assumed to be separated by <code>$/</code>;
10324 * to use a different character as a separator, supply it as a String
10325 * for the _sep_ argument.
10326 *
10327 * The optional _limit_ argument specifies how many characters of each line
10328 * to return. By default all characters are returned.
10329 *
10330 * An EOFError is raised at the end of the file.
10331 */
10332static VALUE
10333argf_readline(int argc, VALUE *argv, VALUE argf)
10334{
10335 VALUE line;
10336
10337 if (!next_argv()) rb_eof_error();
10338 ARGF_FORWARD(argc, argv);
10339 line = argf_gets(argc, argv, argf);
10340 if (NIL_P(line)) {
10341 rb_eof_error();
10342 }
10343
10344 return line;
10345}
10346
10347static VALUE argf_readlines(int, VALUE *, VALUE);
10348
10349/*
10350 * call-seq:
10351 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10352 * readlines(limit, chomp: false, **enc_opts) -> array
10353 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10354 *
10355 * Returns an array containing the lines returned by calling
10356 * Kernel#gets until the end-of-stream is reached;
10357 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10358 *
10359 * With only string argument +sep+ given,
10360 * returns the remaining lines as determined by line separator +sep+,
10361 * or +nil+ if none;
10362 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10363 *
10364 * # Default separator.
10365 * $ cat t.txt | ruby -e "p readlines"
10366 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10367 *
10368 * # Specified separator.
10369 * $ cat t.txt | ruby -e "p readlines 'li'"
10370 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10371 *
10372 * # Get-all separator.
10373 * $ cat t.txt | ruby -e "p readlines nil"
10374 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10375 *
10376 * # Get-paragraph separator.
10377 * $ cat t.txt | ruby -e "p readlines ''"
10378 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10379 *
10380 * With only integer argument +limit+ given,
10381 * limits the number of bytes in the line;
10382 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10383 *
10384 * $cat t.txt | ruby -e "p readlines 10"
10385 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10386 *
10387 * $cat t.txt | ruby -e "p readlines 11"
10388 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10389 *
10390 * $cat t.txt | ruby -e "p readlines 12"
10391 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10392 *
10393 * With arguments +sep+ and +limit+ given, combines the two behaviors;
10394 * see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit].
10395 *
10396 * Optional keyword argument +chomp+ specifies whether line separators
10397 * are to be omitted:
10398 *
10399 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10400 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10401 *
10402 * Optional keyword arguments +enc_opts+ specify encoding options;
10403 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10404 *
10405 */
10406
10407static VALUE
10408rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10409{
10410 if (recv == argf) {
10411 return argf_readlines(argc, argv, argf);
10412 }
10413 return forward(argf, rb_intern("readlines"), argc, argv);
10414}
10415
10416/*
10417 * call-seq:
10418 * ARGF.readlines(sep = $/) -> array
10419 * ARGF.readlines(limit) -> array
10420 * ARGF.readlines(sep, limit) -> array
10421 *
10422 * ARGF.to_a(sep = $/) -> array
10423 * ARGF.to_a(limit) -> array
10424 * ARGF.to_a(sep, limit) -> array
10425 *
10426 * Reads each file in ARGF in its entirety, returning an Array containing
10427 * lines from the files. Lines are assumed to be separated by _sep_.
10428 *
10429 * lines = ARGF.readlines
10430 * lines[0] #=> "This is line one\n"
10431 */
10432static VALUE
10433argf_readlines(int argc, VALUE *argv, VALUE argf)
10434{
10435 long lineno = ARGF.lineno;
10436 VALUE lines, ary;
10437
10438 ary = rb_ary_new();
10439 while (next_argv()) {
10440 if (ARGF_GENERIC_INPUT_P()) {
10441 lines = forward_current(rb_intern("readlines"), argc, argv);
10442 }
10443 else {
10444 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10445 argf_close(argf);
10446 }
10447 ARGF.next_p = 1;
10448 rb_ary_concat(ary, lines);
10449 ARGF.lineno = lineno + RARRAY_LEN(ary);
10450 ARGF.last_lineno = ARGF.lineno;
10451 }
10452 ARGF.init_p = 0;
10453 return ary;
10454}
10455
10456/*
10457 * call-seq:
10458 * `command` -> string
10459 *
10460 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10461 * sets global variable <tt>$?</tt> to the process status.
10462 *
10463 * This method has potential security vulnerabilities if called with untrusted input;
10464 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10465 *
10466 * Examples:
10467 *
10468 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10469 * $ `echo oops && exit 99` # => "oops\n"
10470 * $ $? # => #<Process::Status: pid 17088 exit 99>
10471 * $ $?.status # => 99>
10472 *
10473 * The built-in syntax <tt>%x{...}</tt> uses this method.
10474 *
10475 */
10476
10477static VALUE
10478rb_f_backquote(VALUE obj, VALUE str)
10479{
10480 VALUE port;
10481 VALUE result;
10482 rb_io_t *fptr;
10483
10484 SafeStringValue(str);
10485 rb_last_status_clear();
10486 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10487 if (NIL_P(port)) return rb_str_new(0,0);
10488
10489 GetOpenFile(port, fptr);
10490 result = read_all(fptr, remain_size(fptr), Qnil);
10491 rb_io_close(port);
10492 RFILE(port)->fptr = NULL;
10493 rb_io_fptr_finalize(fptr);
10494 RB_GC_GUARD(port);
10495
10496 return result;
10497}
10498
10499#ifdef HAVE_SYS_SELECT_H
10500#include <sys/select.h>
10501#endif
10502
10503static VALUE
10504select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10505{
10506 VALUE res, list;
10507 rb_fdset_t *rp, *wp, *ep;
10508 rb_io_t *fptr;
10509 long i;
10510 int max = 0, n;
10511 int pending = 0;
10512 struct timeval timerec;
10513
10514 if (!NIL_P(read)) {
10515 Check_Type(read, T_ARRAY);
10516 for (i=0; i<RARRAY_LEN(read); i++) {
10517 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10518 rb_fd_set(fptr->fd, &fds[0]);
10519 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10520 pending++;
10521 rb_fd_set(fptr->fd, &fds[3]);
10522 }
10523 if (max < fptr->fd) max = fptr->fd;
10524 }
10525 if (pending) { /* no blocking if there's buffered data */
10526 timerec.tv_sec = timerec.tv_usec = 0;
10527 tp = &timerec;
10528 }
10529 rp = &fds[0];
10530 }
10531 else
10532 rp = 0;
10533
10534 if (!NIL_P(write)) {
10535 Check_Type(write, T_ARRAY);
10536 for (i=0; i<RARRAY_LEN(write); i++) {
10537 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10538 GetOpenFile(write_io, fptr);
10539 rb_fd_set(fptr->fd, &fds[1]);
10540 if (max < fptr->fd) max = fptr->fd;
10541 }
10542 wp = &fds[1];
10543 }
10544 else
10545 wp = 0;
10546
10547 if (!NIL_P(except)) {
10548 Check_Type(except, T_ARRAY);
10549 for (i=0; i<RARRAY_LEN(except); i++) {
10550 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10551 VALUE write_io = GetWriteIO(io);
10552 GetOpenFile(io, fptr);
10553 rb_fd_set(fptr->fd, &fds[2]);
10554 if (max < fptr->fd) max = fptr->fd;
10555 if (io != write_io) {
10556 GetOpenFile(write_io, fptr);
10557 rb_fd_set(fptr->fd, &fds[2]);
10558 if (max < fptr->fd) max = fptr->fd;
10559 }
10560 }
10561 ep = &fds[2];
10562 }
10563 else {
10564 ep = 0;
10565 }
10566
10567 max++;
10568
10569 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10570 if (n < 0) {
10571 rb_sys_fail(0);
10572 }
10573 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10574
10575 res = rb_ary_new2(3);
10576 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10577 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10578 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10579
10580 if (rp) {
10581 list = RARRAY_AREF(res, 0);
10582 for (i=0; i< RARRAY_LEN(read); i++) {
10583 VALUE obj = rb_ary_entry(read, i);
10584 VALUE io = rb_io_get_io(obj);
10585 GetOpenFile(io, fptr);
10586 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10587 rb_fd_isset(fptr->fd, &fds[3])) {
10588 rb_ary_push(list, obj);
10589 }
10590 }
10591 }
10592
10593 if (wp) {
10594 list = RARRAY_AREF(res, 1);
10595 for (i=0; i< RARRAY_LEN(write); i++) {
10596 VALUE obj = rb_ary_entry(write, i);
10597 VALUE io = rb_io_get_io(obj);
10598 VALUE write_io = GetWriteIO(io);
10599 GetOpenFile(write_io, fptr);
10600 if (rb_fd_isset(fptr->fd, &fds[1])) {
10601 rb_ary_push(list, obj);
10602 }
10603 }
10604 }
10605
10606 if (ep) {
10607 list = RARRAY_AREF(res, 2);
10608 for (i=0; i< RARRAY_LEN(except); i++) {
10609 VALUE obj = rb_ary_entry(except, i);
10610 VALUE io = rb_io_get_io(obj);
10611 VALUE write_io = GetWriteIO(io);
10612 GetOpenFile(io, fptr);
10613 if (rb_fd_isset(fptr->fd, &fds[2])) {
10614 rb_ary_push(list, obj);
10615 }
10616 else if (io != write_io) {
10617 GetOpenFile(write_io, fptr);
10618 if (rb_fd_isset(fptr->fd, &fds[2])) {
10619 rb_ary_push(list, obj);
10620 }
10621 }
10622 }
10623 }
10624
10625 return res; /* returns an empty array on interrupt */
10626}
10627
10629 VALUE read, write, except;
10630 struct timeval *timeout;
10631 rb_fdset_t fdsets[4];
10632};
10633
10634static VALUE
10635select_call(VALUE arg)
10636{
10637 struct select_args *p = (struct select_args *)arg;
10638
10639 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10640}
10641
10642static VALUE
10643select_end(VALUE arg)
10644{
10645 struct select_args *p = (struct select_args *)arg;
10646 int i;
10647
10648 for (i = 0; i < numberof(p->fdsets); ++i)
10649 rb_fd_term(&p->fdsets[i]);
10650 return Qnil;
10651}
10652
10653static VALUE sym_normal, sym_sequential, sym_random,
10654 sym_willneed, sym_dontneed, sym_noreuse;
10655
10656#ifdef HAVE_POSIX_FADVISE
10657struct io_advise_struct {
10658 int fd;
10659 int advice;
10660 rb_off_t offset;
10661 rb_off_t len;
10662};
10663
10664static VALUE
10665io_advise_internal(void *arg)
10666{
10667 struct io_advise_struct *ptr = arg;
10668 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10669}
10670
10671static VALUE
10672io_advise_sym_to_const(VALUE sym)
10673{
10674#ifdef POSIX_FADV_NORMAL
10675 if (sym == sym_normal)
10676 return INT2NUM(POSIX_FADV_NORMAL);
10677#endif
10678
10679#ifdef POSIX_FADV_RANDOM
10680 if (sym == sym_random)
10681 return INT2NUM(POSIX_FADV_RANDOM);
10682#endif
10683
10684#ifdef POSIX_FADV_SEQUENTIAL
10685 if (sym == sym_sequential)
10686 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10687#endif
10688
10689#ifdef POSIX_FADV_WILLNEED
10690 if (sym == sym_willneed)
10691 return INT2NUM(POSIX_FADV_WILLNEED);
10692#endif
10693
10694#ifdef POSIX_FADV_DONTNEED
10695 if (sym == sym_dontneed)
10696 return INT2NUM(POSIX_FADV_DONTNEED);
10697#endif
10698
10699#ifdef POSIX_FADV_NOREUSE
10700 if (sym == sym_noreuse)
10701 return INT2NUM(POSIX_FADV_NOREUSE);
10702#endif
10703
10704 return Qnil;
10705}
10706
10707static VALUE
10708do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10709{
10710 int rv;
10711 struct io_advise_struct ias;
10712 VALUE num_adv;
10713
10714 num_adv = io_advise_sym_to_const(advice);
10715
10716 /*
10717 * The platform doesn't support this hint. We don't raise exception, instead
10718 * silently ignore it. Because IO::advise is only hint.
10719 */
10720 if (NIL_P(num_adv))
10721 return Qnil;
10722
10723 ias.fd = fptr->fd;
10724 ias.advice = NUM2INT(num_adv);
10725 ias.offset = offset;
10726 ias.len = len;
10727
10728 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
10729 if (rv && rv != ENOSYS) {
10730 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10731 it returns the error code. */
10732 VALUE message = rb_sprintf("%"PRIsVALUE" "
10733 "(%"PRI_OFFT_PREFIX"d, "
10734 "%"PRI_OFFT_PREFIX"d, "
10735 "%"PRIsVALUE")",
10736 fptr->pathv, offset, len, advice);
10737 rb_syserr_fail_str(rv, message);
10738 }
10739
10740 return Qnil;
10741}
10742
10743#endif /* HAVE_POSIX_FADVISE */
10744
10745static void
10746advice_arg_check(VALUE advice)
10747{
10748 if (!SYMBOL_P(advice))
10749 rb_raise(rb_eTypeError, "advice must be a Symbol");
10750
10751 if (advice != sym_normal &&
10752 advice != sym_sequential &&
10753 advice != sym_random &&
10754 advice != sym_willneed &&
10755 advice != sym_dontneed &&
10756 advice != sym_noreuse) {
10757 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10758 }
10759}
10760
10761/*
10762 * call-seq:
10763 * advise(advice, offset = 0, len = 0) -> nil
10764 *
10765 * Invokes Posix system call
10766 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10767 * which announces an intention to access data from the current file
10768 * in a particular manner.
10769 *
10770 * The arguments and results are platform-dependent.
10771 *
10772 * The relevant data is specified by:
10773 *
10774 * - +offset+: The offset of the first byte of data.
10775 * - +len+: The number of bytes to be accessed;
10776 * if +len+ is zero, or is larger than the number of bytes remaining,
10777 * all remaining bytes will be accessed.
10778 *
10779 * Argument +advice+ is one of the following symbols:
10780 *
10781 * - +:normal+: The application has no advice to give
10782 * about its access pattern for the specified data.
10783 * If no advice is given for an open file, this is the default assumption.
10784 * - +:sequential+: The application expects to access the specified data sequentially
10785 * (with lower offsets read before higher ones).
10786 * - +:random+: The specified data will be accessed in random order.
10787 * - +:noreuse+: The specified data will be accessed only once.
10788 * - +:willneed+: The specified data will be accessed in the near future.
10789 * - +:dontneed+: The specified data will not be accessed in the near future.
10790 *
10791 * Not implemented on all platforms.
10792 *
10793 */
10794static VALUE
10795rb_io_advise(int argc, VALUE *argv, VALUE io)
10796{
10797 VALUE advice, offset, len;
10798 rb_off_t off, l;
10799 rb_io_t *fptr;
10800
10801 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10802 advice_arg_check(advice);
10803
10804 io = GetWriteIO(io);
10805 GetOpenFile(io, fptr);
10806
10807 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10808 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10809
10810#ifdef HAVE_POSIX_FADVISE
10811 return do_io_advise(fptr, advice, off, l);
10812#else
10813 ((void)off, (void)l); /* Ignore all hint */
10814 return Qnil;
10815#endif
10816}
10817
10818/*
10819 * call-seq:
10820 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10821 *
10822 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10823 * which monitors multiple file descriptors,
10824 * waiting until one or more of the file descriptors
10825 * becomes ready for some class of I/O operation.
10826 *
10827 * Not implemented on all platforms.
10828 *
10829 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10830 * is an array of IO objects.
10831 *
10832 * Argument +timeout+ is an integer timeout interval in seconds.
10833 *
10834 * The method monitors the \IO objects given in all three arrays,
10835 * waiting for some to be ready;
10836 * returns a 3-element array whose elements are:
10837 *
10838 * - An array of the objects in +read_ios+ that are ready for reading.
10839 * - An array of the objects in +write_ios+ that are ready for writing.
10840 * - An array of the objects in +error_ios+ have pending exceptions.
10841 *
10842 * If no object becomes ready within the given +timeout+, +nil+ is returned.
10843 *
10844 * \IO.select peeks the buffer of \IO objects for testing readability.
10845 * If the \IO buffer is not empty, \IO.select immediately notifies
10846 * readability. This "peek" only happens for \IO objects. It does not
10847 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10848 *
10849 * The best way to use \IO.select is invoking it after non-blocking
10850 * methods such as #read_nonblock, #write_nonblock, etc. The methods
10851 * raise an exception which is extended by IO::WaitReadable or
10852 * IO::WaitWritable. The modules notify how the caller should wait
10853 * with \IO.select. If IO::WaitReadable is raised, the caller should
10854 * wait for reading. If IO::WaitWritable is raised, the caller should
10855 * wait for writing.
10856 *
10857 * So, blocking read (#readpartial) can be emulated using
10858 * #read_nonblock and \IO.select as follows:
10859 *
10860 * begin
10861 * result = io_like.read_nonblock(maxlen)
10862 * rescue IO::WaitReadable
10863 * IO.select([io_like])
10864 * retry
10865 * rescue IO::WaitWritable
10866 * IO.select(nil, [io_like])
10867 * retry
10868 * end
10869 *
10870 * Especially, the combination of non-blocking methods and \IO.select is
10871 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
10872 * has #to_io method to return underlying IO object. IO.select calls
10873 * #to_io to obtain the file descriptor to wait.
10874 *
10875 * This means that readability notified by \IO.select doesn't mean
10876 * readability from OpenSSL::SSL::SSLSocket object.
10877 *
10878 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
10879 * some data. \IO.select doesn't see the buffer. So \IO.select can
10880 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
10881 *
10882 * However, several more complicated situations exist.
10883 *
10884 * SSL is a protocol which is sequence of records.
10885 * The record consists of multiple bytes.
10886 * So, the remote side of SSL sends a partial record, IO.select
10887 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
10888 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
10889 *
10890 * Also, the remote side can request SSL renegotiation which forces
10891 * the local SSL engine to write some data.
10892 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
10893 * system call and it can block.
10894 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
10895 * IO::WaitWritable instead of blocking.
10896 * So, the caller should wait for ready for writability as above
10897 * example.
10898 *
10899 * The combination of non-blocking methods and \IO.select is also useful
10900 * for streams such as tty, pipe socket socket when multiple processes
10901 * read from a stream.
10902 *
10903 * Finally, Linux kernel developers don't guarantee that
10904 * readability of select(2) means readability of following read(2) even
10905 * for a single process;
10906 * see {select(2)}[https://linux.die.net/man/2/select]
10907 *
10908 * Invoking \IO.select before IO#readpartial works well as usual.
10909 * However it is not the best way to use \IO.select.
10910 *
10911 * The writability notified by select(2) doesn't show
10912 * how many bytes are writable.
10913 * IO#write method blocks until given whole string is written.
10914 * So, <tt>IO#write(two or more bytes)</tt> can block after
10915 * writability is notified by \IO.select. IO#write_nonblock is required
10916 * to avoid the blocking.
10917 *
10918 * Blocking write (#write) can be emulated using #write_nonblock and
10919 * IO.select as follows: IO::WaitReadable should also be rescued for
10920 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
10921 *
10922 * while 0 < string.bytesize
10923 * begin
10924 * written = io_like.write_nonblock(string)
10925 * rescue IO::WaitReadable
10926 * IO.select([io_like])
10927 * retry
10928 * rescue IO::WaitWritable
10929 * IO.select(nil, [io_like])
10930 * retry
10931 * end
10932 * string = string.byteslice(written..-1)
10933 * end
10934 *
10935 * Example:
10936 *
10937 * rp, wp = IO.pipe
10938 * mesg = "ping "
10939 * 100.times {
10940 * # IO.select follows IO#read. Not the best way to use IO.select.
10941 * rs, ws, = IO.select([rp], [wp])
10942 * if r = rs[0]
10943 * ret = r.read(5)
10944 * print ret
10945 * case ret
10946 * when /ping/
10947 * mesg = "pong\n"
10948 * when /pong/
10949 * mesg = "ping "
10950 * end
10951 * end
10952 * if w = ws[0]
10953 * w.write(mesg)
10954 * end
10955 * }
10956 *
10957 * Output:
10958 *
10959 * ping pong
10960 * ping pong
10961 * ping pong
10962 * (snipped)
10963 * ping
10964 *
10965 */
10966
10967static VALUE
10968rb_f_select(int argc, VALUE *argv, VALUE obj)
10969{
10970 VALUE scheduler = rb_fiber_scheduler_current();
10971 if (scheduler != Qnil) {
10972 // It's optionally supported.
10973 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
10974 if (!UNDEF_P(result)) return result;
10975 }
10976
10977 VALUE timeout;
10978 struct select_args args;
10979 struct timeval timerec;
10980 int i;
10981
10982 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
10983 if (NIL_P(timeout)) {
10984 args.timeout = 0;
10985 }
10986 else {
10987 timerec = rb_time_interval(timeout);
10988 args.timeout = &timerec;
10989 }
10990
10991 for (i = 0; i < numberof(args.fdsets); ++i)
10992 rb_fd_init(&args.fdsets[i]);
10993
10994 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
10995}
10996
10997#ifdef IOCTL_REQ_TYPE
10998 typedef IOCTL_REQ_TYPE ioctl_req_t;
10999#else
11000 typedef int ioctl_req_t;
11001# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11002#endif
11003
11004#ifdef HAVE_IOCTL
11005struct ioctl_arg {
11006 int fd;
11007 ioctl_req_t cmd;
11008 long narg;
11009};
11010
11011static VALUE
11012nogvl_ioctl(void *ptr)
11013{
11014 struct ioctl_arg *arg = ptr;
11015
11016 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11017}
11018
11019static int
11020do_ioctl(int fd, ioctl_req_t cmd, long narg)
11021{
11022 int retval;
11023 struct ioctl_arg arg;
11024
11025 arg.fd = fd;
11026 arg.cmd = cmd;
11027 arg.narg = narg;
11028
11029 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
11030
11031 return retval;
11032}
11033#endif
11034
11035#define DEFAULT_IOCTL_NARG_LEN (256)
11036
11037#if defined(__linux__) && defined(_IOC_SIZE)
11038static long
11039linux_iocparm_len(ioctl_req_t cmd)
11040{
11041 long len;
11042
11043 if ((cmd & 0xFFFF0000) == 0) {
11044 /* legacy and unstructured ioctl number. */
11045 return DEFAULT_IOCTL_NARG_LEN;
11046 }
11047
11048 len = _IOC_SIZE(cmd);
11049
11050 /* paranoia check for silly drivers which don't keep ioctl convention */
11051 if (len < DEFAULT_IOCTL_NARG_LEN)
11052 len = DEFAULT_IOCTL_NARG_LEN;
11053
11054 return len;
11055}
11056#endif
11057
11058#ifdef HAVE_IOCTL
11059static long
11060ioctl_narg_len(ioctl_req_t cmd)
11061{
11062 long len;
11063
11064#ifdef IOCPARM_MASK
11065#ifndef IOCPARM_LEN
11066#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11067#endif
11068#endif
11069#ifdef IOCPARM_LEN
11070 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11071#elif defined(__linux__) && defined(_IOC_SIZE)
11072 len = linux_iocparm_len(cmd);
11073#else
11074 /* otherwise guess at what's safe */
11075 len = DEFAULT_IOCTL_NARG_LEN;
11076#endif
11077
11078 return len;
11079}
11080#endif
11081
11082#ifdef HAVE_FCNTL
11083#ifdef __linux__
11084typedef long fcntl_arg_t;
11085#else
11086/* posix */
11087typedef int fcntl_arg_t;
11088#endif
11089
11090static long
11091fcntl_narg_len(ioctl_req_t cmd)
11092{
11093 long len;
11094
11095 switch (cmd) {
11096#ifdef F_DUPFD
11097 case F_DUPFD:
11098 len = sizeof(fcntl_arg_t);
11099 break;
11100#endif
11101#ifdef F_DUP2FD /* bsd specific */
11102 case F_DUP2FD:
11103 len = sizeof(int);
11104 break;
11105#endif
11106#ifdef F_DUPFD_CLOEXEC /* linux specific */
11107 case F_DUPFD_CLOEXEC:
11108 len = sizeof(fcntl_arg_t);
11109 break;
11110#endif
11111#ifdef F_GETFD
11112 case F_GETFD:
11113 len = 1;
11114 break;
11115#endif
11116#ifdef F_SETFD
11117 case F_SETFD:
11118 len = sizeof(fcntl_arg_t);
11119 break;
11120#endif
11121#ifdef F_GETFL
11122 case F_GETFL:
11123 len = 1;
11124 break;
11125#endif
11126#ifdef F_SETFL
11127 case F_SETFL:
11128 len = sizeof(fcntl_arg_t);
11129 break;
11130#endif
11131#ifdef F_GETOWN
11132 case F_GETOWN:
11133 len = 1;
11134 break;
11135#endif
11136#ifdef F_SETOWN
11137 case F_SETOWN:
11138 len = sizeof(fcntl_arg_t);
11139 break;
11140#endif
11141#ifdef F_GETOWN_EX /* linux specific */
11142 case F_GETOWN_EX:
11143 len = sizeof(struct f_owner_ex);
11144 break;
11145#endif
11146#ifdef F_SETOWN_EX /* linux specific */
11147 case F_SETOWN_EX:
11148 len = sizeof(struct f_owner_ex);
11149 break;
11150#endif
11151#ifdef F_GETLK
11152 case F_GETLK:
11153 len = sizeof(struct flock);
11154 break;
11155#endif
11156#ifdef F_SETLK
11157 case F_SETLK:
11158 len = sizeof(struct flock);
11159 break;
11160#endif
11161#ifdef F_SETLKW
11162 case F_SETLKW:
11163 len = sizeof(struct flock);
11164 break;
11165#endif
11166#ifdef F_READAHEAD /* bsd specific */
11167 case F_READAHEAD:
11168 len = sizeof(int);
11169 break;
11170#endif
11171#ifdef F_RDAHEAD /* Darwin specific */
11172 case F_RDAHEAD:
11173 len = sizeof(int);
11174 break;
11175#endif
11176#ifdef F_GETSIG /* linux specific */
11177 case F_GETSIG:
11178 len = 1;
11179 break;
11180#endif
11181#ifdef F_SETSIG /* linux specific */
11182 case F_SETSIG:
11183 len = sizeof(fcntl_arg_t);
11184 break;
11185#endif
11186#ifdef F_GETLEASE /* linux specific */
11187 case F_GETLEASE:
11188 len = 1;
11189 break;
11190#endif
11191#ifdef F_SETLEASE /* linux specific */
11192 case F_SETLEASE:
11193 len = sizeof(fcntl_arg_t);
11194 break;
11195#endif
11196#ifdef F_NOTIFY /* linux specific */
11197 case F_NOTIFY:
11198 len = sizeof(fcntl_arg_t);
11199 break;
11200#endif
11201
11202 default:
11203 len = 256;
11204 break;
11205 }
11206
11207 return len;
11208}
11209#else /* HAVE_FCNTL */
11210static long
11211fcntl_narg_len(ioctl_req_t cmd)
11212{
11213 return 0;
11214}
11215#endif /* HAVE_FCNTL */
11216
11217#define NARG_SENTINEL 17
11218
11219static long
11220setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11221{
11222 long narg = 0;
11223 VALUE arg = *argp;
11224
11225 if (!RTEST(arg)) {
11226 narg = 0;
11227 }
11228 else if (FIXNUM_P(arg)) {
11229 narg = FIX2LONG(arg);
11230 }
11231 else if (arg == Qtrue) {
11232 narg = 1;
11233 }
11234 else {
11235 VALUE tmp = rb_check_string_type(arg);
11236
11237 if (NIL_P(tmp)) {
11238 narg = NUM2LONG(arg);
11239 }
11240 else {
11241 char *ptr;
11242 long len, slen;
11243
11244 *argp = arg = tmp;
11245 len = narg_len(cmd);
11246 rb_str_modify(arg);
11247
11248 slen = RSTRING_LEN(arg);
11249 /* expand for data + sentinel. */
11250 if (slen < len+1) {
11251 rb_str_resize(arg, len+1);
11252 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11253 slen = len+1;
11254 }
11255 /* a little sanity check here */
11256 ptr = RSTRING_PTR(arg);
11257 ptr[slen - 1] = NARG_SENTINEL;
11258 narg = (long)(SIGNED_VALUE)ptr;
11259 }
11260 }
11261
11262 return narg;
11263}
11264
11265static VALUE
11266finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11267{
11268 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11269 if (RB_TYPE_P(arg, T_STRING)) {
11270 char *ptr;
11271 long slen;
11272 RSTRING_GETMEM(arg, ptr, slen);
11273 if (ptr[slen-1] != NARG_SENTINEL)
11274 rb_raise(rb_eArgError, "return value overflowed string");
11275 ptr[slen-1] = '\0';
11276 }
11277
11278 return INT2NUM(retval);
11279}
11280
11281#ifdef HAVE_IOCTL
11282static VALUE
11283rb_ioctl(VALUE io, VALUE req, VALUE arg)
11284{
11285 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11286 rb_io_t *fptr;
11287 long narg;
11288 int retval;
11289
11290 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11291 GetOpenFile(io, fptr);
11292 retval = do_ioctl(fptr->fd, cmd, narg);
11293 return finish_narg(retval, arg, fptr);
11294}
11295
11296/*
11297 * call-seq:
11298 * ioctl(integer_cmd, argument) -> integer
11299 *
11300 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11301 * which issues a low-level command to an I/O device.
11302 *
11303 * Issues a low-level command to an I/O device.
11304 * The arguments and returned value are platform-dependent.
11305 * The effect of the call is platform-dependent.
11306 *
11307 * If argument +argument+ is an integer, it is passed directly;
11308 * if it is a string, it is interpreted as a binary sequence of bytes.
11309 *
11310 * Not implemented on all platforms.
11311 *
11312 */
11313
11314static VALUE
11315rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11316{
11317 VALUE req, arg;
11318
11319 rb_scan_args(argc, argv, "11", &req, &arg);
11320 return rb_ioctl(io, req, arg);
11321}
11322#else
11323#define rb_io_ioctl rb_f_notimplement
11324#endif
11325
11326#ifdef HAVE_FCNTL
11327struct fcntl_arg {
11328 int fd;
11329 int cmd;
11330 long narg;
11331};
11332
11333static VALUE
11334nogvl_fcntl(void *ptr)
11335{
11336 struct fcntl_arg *arg = ptr;
11337
11338#if defined(F_DUPFD)
11339 if (arg->cmd == F_DUPFD)
11340 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11341#endif
11342 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11343}
11344
11345static int
11346do_fcntl(int fd, int cmd, long narg)
11347{
11348 int retval;
11349 struct fcntl_arg arg;
11350
11351 arg.fd = fd;
11352 arg.cmd = cmd;
11353 arg.narg = narg;
11354
11355 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
11356 if (retval != -1) {
11357 switch (cmd) {
11358#if defined(F_DUPFD)
11359 case F_DUPFD:
11360#endif
11361#if defined(F_DUPFD_CLOEXEC)
11362 case F_DUPFD_CLOEXEC:
11363#endif
11364 rb_update_max_fd(retval);
11365 }
11366 }
11367
11368 return retval;
11369}
11370
11371static VALUE
11372rb_fcntl(VALUE io, VALUE req, VALUE arg)
11373{
11374 int cmd = NUM2INT(req);
11375 rb_io_t *fptr;
11376 long narg;
11377 int retval;
11378
11379 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11380 GetOpenFile(io, fptr);
11381 retval = do_fcntl(fptr->fd, cmd, narg);
11382 return finish_narg(retval, arg, fptr);
11383}
11384
11385/*
11386 * call-seq:
11387 * fcntl(integer_cmd, argument) -> integer
11388 *
11389 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11390 * which provides a mechanism for issuing low-level commands to control or query
11391 * a file-oriented I/O stream. Arguments and results are platform
11392 * dependent.
11393 *
11394 * If +argument is a number, its value is passed directly;
11395 * if it is a string, it is interpreted as a binary sequence of bytes.
11396 * (Array#pack might be a useful way to build this string.)
11397 *
11398 * Not implemented on all platforms.
11399 *
11400 */
11401
11402static VALUE
11403rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11404{
11405 VALUE req, arg;
11406
11407 rb_scan_args(argc, argv, "11", &req, &arg);
11408 return rb_fcntl(io, req, arg);
11409}
11410#else
11411#define rb_io_fcntl rb_f_notimplement
11412#endif
11413
11414#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11415/*
11416 * call-seq:
11417 * syscall(integer_callno, *arguments) -> integer
11418 *
11419 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11420 * which calls a specified function.
11421 *
11422 * Calls the operating system function identified by +integer_callno+;
11423 * returns the result of the function or raises SystemCallError if it failed.
11424 * The effect of the call is platform-dependent.
11425 * The arguments and returned value are platform-dependent.
11426 *
11427 * For each of +arguments+: if it is an integer, it is passed directly;
11428 * if it is a string, it is interpreted as a binary sequence of bytes.
11429 * There may be as many as nine such arguments.
11430 *
11431 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11432 * are platform-dependent.
11433 *
11434 * Note: Method +syscall+ is essentially unsafe and unportable.
11435 * The DL (Fiddle) library is preferred for safer and a bit
11436 * more portable programming.
11437 *
11438 * Not implemented on all platforms.
11439 *
11440 */
11441
11442static VALUE
11443rb_f_syscall(int argc, VALUE *argv, VALUE _)
11444{
11445 VALUE arg[8];
11446#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11447# define SYSCALL __syscall
11448# define NUM2SYSCALLID(x) NUM2LONG(x)
11449# define RETVAL2NUM(x) LONG2NUM(x)
11450# if SIZEOF_LONG == 8
11451 long num, retval = -1;
11452# elif SIZEOF_LONG_LONG == 8
11453 long long num, retval = -1;
11454# else
11455# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11456# endif
11457#elif defined(__linux__)
11458# define SYSCALL syscall
11459# define NUM2SYSCALLID(x) NUM2LONG(x)
11460# define RETVAL2NUM(x) LONG2NUM(x)
11461 /*
11462 * Linux man page says, syscall(2) function prototype is below.
11463 *
11464 * int syscall(int number, ...);
11465 *
11466 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11467 */
11468 long num, retval = -1;
11469#else
11470# define SYSCALL syscall
11471# define NUM2SYSCALLID(x) NUM2INT(x)
11472# define RETVAL2NUM(x) INT2NUM(x)
11473 int num, retval = -1;
11474#endif
11475 int i;
11476
11477 if (RTEST(ruby_verbose)) {
11479 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11480 }
11481
11482 if (argc == 0)
11483 rb_raise(rb_eArgError, "too few arguments for syscall");
11484 if (argc > numberof(arg))
11485 rb_raise(rb_eArgError, "too many arguments for syscall");
11486 num = NUM2SYSCALLID(argv[0]); ++argv;
11487 for (i = argc - 1; i--; ) {
11488 VALUE v = rb_check_string_type(argv[i]);
11489
11490 if (!NIL_P(v)) {
11491 SafeStringValue(v);
11492 rb_str_modify(v);
11493 arg[i] = (VALUE)StringValueCStr(v);
11494 }
11495 else {
11496 arg[i] = (VALUE)NUM2LONG(argv[i]);
11497 }
11498 }
11499
11500 switch (argc) {
11501 case 1:
11502 retval = SYSCALL(num);
11503 break;
11504 case 2:
11505 retval = SYSCALL(num, arg[0]);
11506 break;
11507 case 3:
11508 retval = SYSCALL(num, arg[0],arg[1]);
11509 break;
11510 case 4:
11511 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11512 break;
11513 case 5:
11514 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11515 break;
11516 case 6:
11517 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11518 break;
11519 case 7:
11520 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11521 break;
11522 case 8:
11523 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11524 break;
11525 }
11526
11527 if (retval == -1)
11528 rb_sys_fail(0);
11529 return RETVAL2NUM(retval);
11530#undef SYSCALL
11531#undef NUM2SYSCALLID
11532#undef RETVAL2NUM
11533}
11534#else
11535#define rb_f_syscall rb_f_notimplement
11536#endif
11537
11538static VALUE
11539io_new_instance(VALUE args)
11540{
11541 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11542}
11543
11544static rb_encoding *
11545find_encoding(VALUE v)
11546{
11547 rb_encoding *enc = rb_find_encoding(v);
11548 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11549 return enc;
11550}
11551
11552static void
11553io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11554{
11555 rb_encoding *enc, *enc2;
11556 int ecflags = fptr->encs.ecflags;
11557 VALUE ecopts, tmp;
11558
11559 if (!NIL_P(v2)) {
11560 enc2 = find_encoding(v1);
11561 tmp = rb_check_string_type(v2);
11562 if (!NIL_P(tmp)) {
11563 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11564 /* Special case - "-" => no transcoding */
11565 enc = enc2;
11566 enc2 = NULL;
11567 }
11568 else
11569 enc = find_encoding(v2);
11570 if (enc == enc2) {
11571 /* Special case - "-" => no transcoding */
11572 enc2 = NULL;
11573 }
11574 }
11575 else {
11576 enc = find_encoding(v2);
11577 if (enc == enc2) {
11578 /* Special case - "-" => no transcoding */
11579 enc2 = NULL;
11580 }
11581 }
11582 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11583 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11584 }
11585 else {
11586 if (NIL_P(v1)) {
11587 /* Set to default encodings */
11588 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11589 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11590 ecopts = Qnil;
11591 }
11592 else {
11593 tmp = rb_check_string_type(v1);
11594 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11595 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11596 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11597 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11598 }
11599 else {
11600 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11601 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11602 ecopts = Qnil;
11603 }
11604 }
11605 }
11606 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11607 fptr->encs.enc = enc;
11608 fptr->encs.enc2 = enc2;
11609 fptr->encs.ecflags = ecflags;
11610 fptr->encs.ecopts = ecopts;
11611 clear_codeconv(fptr);
11612
11613}
11614
11616 rb_io_t *fptr;
11617 VALUE v1;
11618 VALUE v2;
11619 VALUE opt;
11620};
11621
11622static VALUE
11623io_encoding_set_v(VALUE v)
11624{
11625 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11626 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11627 return Qnil;
11628}
11629
11630static VALUE
11631pipe_pair_close(VALUE rw)
11632{
11633 VALUE *rwp = (VALUE *)rw;
11634 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11635}
11636
11637/*
11638 * call-seq:
11639 * IO.pipe(**opts) -> [read_io, write_io]
11640 * IO.pipe(enc, **opts) -> [read_io, write_io]
11641 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11642 * IO.pipe(**opts) {|read_io, write_io] ...} -> object
11643 * IO.pipe(enc, **opts) {|read_io, write_io] ...} -> object
11644 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io] ...} -> object
11645 *
11646 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11647 * connected to each other.
11648 *
11649 * If argument +enc_string+ is given, it must be a string containing one of:
11650 *
11651 * - The name of the encoding to be used as the external encoding.
11652 * - The colon-separated names of two encodings to be used as the external
11653 * and internal encodings.
11654 *
11655 * If argument +int_enc+ is given, it must be an Encoding object
11656 * or encoding name string that specifies the internal encoding to be used;
11657 * if argument +ext_enc+ is also given, it must be an Encoding object
11658 * or encoding name string that specifies the external encoding to be used.
11659 *
11660 * The string read from +read_io+ is tagged with the external encoding;
11661 * if an internal encoding is also specified, the string is converted
11662 * to, and tagged with, that encoding.
11663 *
11664 * If any encoding is specified,
11665 * optional hash arguments specify the conversion option.
11666 *
11667 * Optional keyword arguments +opts+ specify:
11668 *
11669 * - {Open Options}[rdoc-ref:IO@Open+Options].
11670 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11671 *
11672 * With no block given, returns the two endpoints in an array:
11673 *
11674 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11675 *
11676 * With a block given, calls the block with the two endpoints;
11677 * closes both endpoints and returns the value of the block:
11678 *
11679 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11680 *
11681 * Output:
11682 *
11683 * #<IO:fd 6>
11684 * #<IO:fd 7>
11685 *
11686 * Not available on all platforms.
11687 *
11688 * In the example below, the two processes close the ends of the pipe
11689 * that they are not using. This is not just a cosmetic nicety. The
11690 * read end of a pipe will not generate an end of file condition if
11691 * there are any writers with the pipe still open. In the case of the
11692 * parent process, the <tt>rd.read</tt> will never return if it
11693 * does not first issue a <tt>wr.close</tt>:
11694 *
11695 * rd, wr = IO.pipe
11696 *
11697 * if fork
11698 * wr.close
11699 * puts "Parent got: <#{rd.read}>"
11700 * rd.close
11701 * Process.wait
11702 * else
11703 * rd.close
11704 * puts 'Sending message to parent'
11705 * wr.write "Hi Dad"
11706 * wr.close
11707 * end
11708 *
11709 * <em>produces:</em>
11710 *
11711 * Sending message to parent
11712 * Parent got: <Hi Dad>
11713 *
11714 */
11715
11716static VALUE
11717rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11718{
11719 int pipes[2], state;
11720 VALUE r, w, args[3], v1, v2;
11721 VALUE opt;
11722 rb_io_t *fptr, *fptr2;
11723 struct io_encoding_set_args ies_args;
11724 int fmode = 0;
11725 VALUE ret;
11726
11727 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11728 if (rb_pipe(pipes) < 0)
11729 rb_sys_fail(0);
11730
11731 args[0] = klass;
11732 args[1] = INT2NUM(pipes[0]);
11733 args[2] = INT2FIX(O_RDONLY);
11734 r = rb_protect(io_new_instance, (VALUE)args, &state);
11735 if (state) {
11736 close(pipes[0]);
11737 close(pipes[1]);
11738 rb_jump_tag(state);
11739 }
11740 GetOpenFile(r, fptr);
11741
11742 ies_args.fptr = fptr;
11743 ies_args.v1 = v1;
11744 ies_args.v2 = v2;
11745 ies_args.opt = opt;
11746 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11747 if (state) {
11748 close(pipes[1]);
11749 io_close(r);
11750 rb_jump_tag(state);
11751 }
11752
11753 args[1] = INT2NUM(pipes[1]);
11754 args[2] = INT2FIX(O_WRONLY);
11755 w = rb_protect(io_new_instance, (VALUE)args, &state);
11756 if (state) {
11757 close(pipes[1]);
11758 if (!NIL_P(r)) rb_io_close(r);
11759 rb_jump_tag(state);
11760 }
11761 GetOpenFile(w, fptr2);
11762 rb_io_synchronized(fptr2);
11763
11764 extract_binmode(opt, &fmode);
11765
11766 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11769 }
11770
11771#if DEFAULT_TEXTMODE
11772 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11773 fptr->mode &= ~FMODE_TEXTMODE;
11774 setmode(fptr->fd, O_BINARY);
11775 }
11776#if RUBY_CRLF_ENVIRONMENT
11779 }
11780#endif
11781#endif
11782 fptr->mode |= fmode;
11783#if DEFAULT_TEXTMODE
11784 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11785 fptr2->mode &= ~FMODE_TEXTMODE;
11786 setmode(fptr2->fd, O_BINARY);
11787 }
11788#endif
11789 fptr2->mode |= fmode;
11790
11791 ret = rb_assoc_new(r, w);
11792 if (rb_block_given_p()) {
11793 VALUE rw[2];
11794 rw[0] = r;
11795 rw[1] = w;
11796 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11797 }
11798 return ret;
11799}
11800
11802 int argc;
11803 VALUE *argv;
11804 VALUE io;
11805};
11806
11807static void
11808open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11809{
11810 VALUE path, v;
11811 VALUE vmode = Qnil, vperm = Qnil;
11812
11813 path = *argv++;
11814 argc--;
11815 FilePathValue(path);
11816 arg->io = 0;
11817 arg->argc = argc;
11818 arg->argv = argv;
11819 if (NIL_P(opt)) {
11820 vmode = INT2NUM(O_RDONLY);
11821 vperm = INT2FIX(0666);
11822 }
11823 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11824 int n;
11825
11826 v = rb_to_array_type(v);
11827 n = RARRAY_LENINT(v);
11828 rb_check_arity(n, 0, 3); /* rb_io_open */
11829 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11830 }
11831 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11832}
11833
11834static VALUE
11835io_s_foreach(VALUE v)
11836{
11837 struct getline_arg *arg = (void *)v;
11838 VALUE str;
11839
11840 if (arg->limit == 0)
11841 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
11842 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11843 rb_lastline_set(str);
11844 rb_yield(str);
11845 }
11847 return Qnil;
11848}
11849
11850/*
11851 * call-seq:
11852 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
11853 * IO.foreach(path, limit, **opts) {|line| block } -> nil
11854 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
11855 * IO.foreach(command, sep = $/, **opts) {|line| block } -> nil
11856 * IO.foreach(command, limit, **opts) {|line| block } -> nil
11857 * IO.foreach(command, sep, limit, **opts) {|line| block } -> nil
11858 * IO.foreach(...) -> an_enumerator
11859 *
11860 * Calls the block with each successive line read from the stream.
11861 *
11862 * When called from class \IO (but not subclasses of \IO),
11863 * this method has potential security vulnerabilities if called with untrusted input;
11864 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11865 *
11866 * The first argument must be a string that is one of the following:
11867 *
11868 * - Path: if +self+ is a subclass of \IO (\File, for example),
11869 * or if the string _does_ _not_ start with the pipe character (<tt>'|'</tt>),
11870 * the string is the path to a file.
11871 * - Command: if +self+ is the class \IO,
11872 * and if the string starts with the pipe character,
11873 * the rest of the string is a command to be executed as a subprocess.
11874 * This usage has potential security vulnerabilities if called with untrusted input;
11875 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11876 *
11877 * With only argument +path+ given, parses lines from the file at the given +path+,
11878 * as determined by the default line separator,
11879 * and calls the block with each successive line:
11880 *
11881 * File.foreach('t.txt') {|line| p line }
11882 *
11883 * Output: the same as above.
11884 *
11885 * For both forms, command and path, the remaining arguments are the same.
11886 *
11887 * With argument +sep+ given, parses lines as determined by that line separator
11888 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
11889 *
11890 * File.foreach('t.txt', 'li') {|line| p line }
11891 *
11892 * Output:
11893 *
11894 * "First li"
11895 * "ne\nSecond li"
11896 * "ne\n\nThird li"
11897 * "ne\nFourth li"
11898 * "ne\n"
11899 *
11900 * Each paragraph:
11901 *
11902 * File.foreach('t.txt', '') {|paragraph| p paragraph }
11903 *
11904 * Output:
11905 *
11906 * "First line\nSecond line\n\n"
11907 * "Third line\nFourth line\n"
11908 *
11909 * With argument +limit+ given, parses lines as determined by the default
11910 * line separator and the given line-length limit
11911 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
11912 *
11913 * File.foreach('t.txt', 7) {|line| p line }
11914 *
11915 * Output:
11916 *
11917 * "First l"
11918 * "ine\n"
11919 * "Second "
11920 * "line\n"
11921 * "\n"
11922 * "Third l"
11923 * "ine\n"
11924 * "Fourth l"
11925 * "line\n"
11926 *
11927 * With arguments +sep+ and +limit+ given,
11928 * parses lines as determined by the given
11929 * line separator and the given line-length limit
11930 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
11931 *
11932 * Optional keyword arguments +opts+ specify:
11933 *
11934 * - {Open Options}[rdoc-ref:IO@Open+Options].
11935 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11936 * - {Line Options}[rdoc-ref:IO@Line+Options].
11937 *
11938 * Returns an Enumerator if no block is given.
11939 *
11940 */
11941
11942static VALUE
11943rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
11944{
11945 VALUE opt;
11946 int orig_argc = argc;
11947 struct foreach_arg arg;
11948 struct getline_arg garg;
11949
11950 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
11951 RETURN_ENUMERATOR(self, orig_argc, argv);
11952 extract_getline_args(argc-1, argv+1, &garg);
11953 open_key_args(self, argc, argv, opt, &arg);
11954 if (NIL_P(arg.io)) return Qnil;
11955 extract_getline_opts(opt, &garg);
11956 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
11957 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
11958}
11959
11960static VALUE
11961io_s_readlines(VALUE v)
11962{
11963 struct getline_arg *arg = (void *)v;
11964 return io_readlines(arg, arg->io);
11965}
11966
11967/*
11968 * call-seq:
11969 * IO.readlines(command, sep = $/, **opts) -> array
11970 * IO.readlines(command, limit, **opts) -> array
11971 * IO.readlines(command, sep, limit, **opts) -> array
11972 * IO.readlines(path, sep = $/, **opts) -> array
11973 * IO.readlines(path, limit, **opts) -> array
11974 * IO.readlines(path, sep, limit, **opts) -> array
11975 *
11976 * Returns an array of all lines read from the stream.
11977 *
11978 * When called from class \IO (but not subclasses of \IO),
11979 * this method has potential security vulnerabilities if called with untrusted input;
11980 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11981 *
11982 * The first argument must be a string;
11983 * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
11984 *
11985 * - If so (and if +self+ is \IO),
11986 * the rest of the string is a command to be executed as a subprocess.
11987 * - Otherwise, the string is the path to a file.
11988 *
11989 * With only argument +command+ given, executes the command in a shell,
11990 * parses its $stdout into lines, as determined by the default line separator,
11991 * and returns those lines in an array:
11992 *
11993 * IO.readlines('| cat t.txt')
11994 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
11995 *
11996 * With only argument +path+ given, parses lines from the file at the given +path+,
11997 * as determined by the default line separator,
11998 * and returns those lines in an array:
11999 *
12000 * IO.readlines('t.txt')
12001 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12002 *
12003 * For both forms, command and path, the remaining arguments are the same.
12004 *
12005 * With argument +sep+ given, parses lines as determined by that line separator
12006 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12007 *
12008 * # Ordinary separator.
12009 * IO.readlines('t.txt', 'li')
12010 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12011 * # Get-paragraphs separator.
12012 * IO.readlines('t.txt', '')
12013 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12014 * # Get-all separator.
12015 * IO.readlines('t.txt', nil)
12016 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12017 *
12018 * With argument +limit+ given, parses lines as determined by the default
12019 * line separator and the given line-length limit
12020 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
12021 *
12022 * IO.readlines('t.txt', 7)
12023 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12024 *
12025 * With arguments +sep+ and +limit+ given,
12026 * parses lines as determined by the given
12027 * line separator and the given line-length limit
12028 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
12029 *
12030 * Optional keyword arguments +opts+ specify:
12031 *
12032 * - {Open Options}[rdoc-ref:IO@Open+Options].
12033 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12034 * - {Line Options}[rdoc-ref:IO@Line+Options].
12035 *
12036 */
12037
12038static VALUE
12039rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12040{
12041 VALUE opt;
12042 struct foreach_arg arg;
12043 struct getline_arg garg;
12044
12045 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12046 extract_getline_args(argc-1, argv+1, &garg);
12047 open_key_args(io, argc, argv, opt, &arg);
12048 if (NIL_P(arg.io)) return Qnil;
12049 extract_getline_opts(opt, &garg);
12050 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12051 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12052}
12053
12054static VALUE
12055io_s_read(VALUE v)
12056{
12057 struct foreach_arg *arg = (void *)v;
12058 return io_read(arg->argc, arg->argv, arg->io);
12059}
12060
12061struct seek_arg {
12062 VALUE io;
12063 VALUE offset;
12064 int mode;
12065};
12066
12067static VALUE
12068seek_before_access(VALUE argp)
12069{
12070 struct seek_arg *arg = (struct seek_arg *)argp;
12071 rb_io_binmode(arg->io);
12072 return rb_io_seek(arg->io, arg->offset, arg->mode);
12073}
12074
12075/*
12076 * call-seq:
12077 * IO.read(command, length = nil, offset = 0, **opts) -> string or nil
12078 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12079 *
12080 * Opens the stream, reads and returns some or all of its content,
12081 * and closes the stream; returns +nil+ if no bytes were read.
12082 *
12083 * When called from class \IO (but not subclasses of \IO),
12084 * this method has potential security vulnerabilities if called with untrusted input;
12085 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12086 *
12087 * The first argument must be a string;
12088 * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
12089 *
12090 * - If so (and if +self+ is \IO),
12091 * the rest of the string is a command to be executed as a subprocess.
12092 * - Otherwise, the string is the path to a file.
12093 *
12094 * With only argument +command+ given, executes the command in a shell,
12095 * returns its entire $stdout:
12096 *
12097 * IO.read('| cat t.txt')
12098 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12099 *
12100 * With only argument +path+ given, reads in text mode and returns the entire content
12101 * of the file at the given path:
12102 *
12103 * IO.read('t.txt')
12104 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12105 *
12106 * On Windows, text mode can terminate reading and leave bytes in the file
12107 * unread when encountering certain special bytes. Consider using
12108 * IO.binread if all bytes in the file should be read.
12109 *
12110 * For both forms, command and path, the remaining arguments are the same.
12111 *
12112 * With argument +length+, returns +length+ bytes if available:
12113 *
12114 * IO.read('t.txt', 7) # => "First l"
12115 * IO.read('t.txt', 700)
12116 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12117 *
12118 * With arguments +length+ and +offset+, returns +length+ bytes
12119 * if available, beginning at the given +offset+:
12120 *
12121 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12122 * IO.read('t.txt', 10, 200) # => nil
12123 *
12124 * Optional keyword arguments +opts+ specify:
12125 *
12126 * - {Open Options}[rdoc-ref:IO@Open+Options].
12127 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12128 *
12129 */
12130
12131static VALUE
12132rb_io_s_read(int argc, VALUE *argv, VALUE io)
12133{
12134 VALUE opt, offset;
12135 struct foreach_arg arg;
12136
12137 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12138 open_key_args(io, argc, argv, opt, &arg);
12139 if (NIL_P(arg.io)) return Qnil;
12140 if (!NIL_P(offset)) {
12141 struct seek_arg sarg;
12142 int state = 0;
12143 sarg.io = arg.io;
12144 sarg.offset = offset;
12145 sarg.mode = SEEK_SET;
12146 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12147 if (state) {
12148 rb_io_close(arg.io);
12149 rb_jump_tag(state);
12150 }
12151 if (arg.argc == 2) arg.argc = 1;
12152 }
12153 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12154}
12155
12156/*
12157 * call-seq:
12158 * IO.binread(command, length = nil, offset = 0) -> string or nil
12159 * IO.binread(path, length = nil, offset = 0) -> string or nil
12160 *
12161 * Behaves like IO.read, except that the stream is opened in binary mode
12162 * with ASCII-8BIT encoding.
12163 *
12164 * When called from class \IO (but not subclasses of \IO),
12165 * this method has potential security vulnerabilities if called with untrusted input;
12166 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12167 *
12168 */
12169
12170static VALUE
12171rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12172{
12173 VALUE offset;
12174 struct foreach_arg arg;
12175 enum {
12177 oflags = O_RDONLY
12178#ifdef O_BINARY
12179 |O_BINARY
12180#endif
12181 };
12182 convconfig_t convconfig = {NULL, NULL, 0, Qnil};
12183
12184 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12185 FilePathValue(argv[0]);
12186 convconfig.enc = rb_ascii8bit_encoding();
12187 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12188 if (NIL_P(arg.io)) return Qnil;
12189 arg.argv = argv+1;
12190 arg.argc = (argc > 1) ? 1 : 0;
12191 if (!NIL_P(offset)) {
12192 struct seek_arg sarg;
12193 int state = 0;
12194 sarg.io = arg.io;
12195 sarg.offset = offset;
12196 sarg.mode = SEEK_SET;
12197 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12198 if (state) {
12199 rb_io_close(arg.io);
12200 rb_jump_tag(state);
12201 }
12202 }
12203 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12204}
12205
12206static VALUE
12207io_s_write0(VALUE v)
12208{
12209 struct write_arg *arg = (void *)v;
12210 return io_write(arg->io,arg->str,arg->nosync);
12211}
12212
12213static VALUE
12214io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12215{
12216 VALUE string, offset, opt;
12217 struct foreach_arg arg;
12218 struct write_arg warg;
12219
12220 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12221
12222 if (NIL_P(opt)) opt = rb_hash_new();
12223 else opt = rb_hash_dup(opt);
12224
12225
12226 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12227 int mode = O_WRONLY|O_CREAT;
12228#ifdef O_BINARY
12229 if (binary) mode |= O_BINARY;
12230#endif
12231 if (NIL_P(offset)) mode |= O_TRUNC;
12232 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12233 }
12234 open_key_args(klass, argc, argv, opt, &arg);
12235
12236#ifndef O_BINARY
12237 if (binary) rb_io_binmode_m(arg.io);
12238#endif
12239
12240 if (NIL_P(arg.io)) return Qnil;
12241 if (!NIL_P(offset)) {
12242 struct seek_arg sarg;
12243 int state = 0;
12244 sarg.io = arg.io;
12245 sarg.offset = offset;
12246 sarg.mode = SEEK_SET;
12247 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12248 if (state) {
12249 rb_io_close(arg.io);
12250 rb_jump_tag(state);
12251 }
12252 }
12253
12254 warg.io = arg.io;
12255 warg.str = string;
12256 warg.nosync = 0;
12257
12258 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12259}
12260
12261/*
12262 * call-seq:
12263 * IO.write(command, data, **opts) -> integer
12264 * IO.write(path, data, offset = 0, **opts) -> integer
12265 *
12266 * Opens the stream, writes the given +data+ to it,
12267 * and closes the stream; returns the number of bytes written.
12268 *
12269 * When called from class \IO (but not subclasses of \IO),
12270 * this method has potential security vulnerabilities if called with untrusted input;
12271 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12272 *
12273 * The first argument must be a string;
12274 * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
12275 *
12276 * - If so (and if +self+ is \IO),
12277 * the rest of the string is a command to be executed as a subprocess.
12278 * - Otherwise, the string is the path to a file.
12279 *
12280 * With argument +command+ given, executes the command in a shell,
12281 * passes +data+ through standard input, writes its output to $stdout,
12282 * and returns the length of the given +data+:
12283 *
12284 * IO.write('| cat', 'Hello World!') # => 12
12285 *
12286 * Output:
12287 *
12288 * Hello World!
12289 *
12290 * With argument +path+ given, writes the given +data+ to the file
12291 * at that path:
12292 *
12293 * IO.write('t.tmp', 'abc') # => 3
12294 * File.read('t.tmp') # => "abc"
12295 *
12296 * If +offset+ is zero (the default), the file is overwritten:
12297 *
12298 * IO.write('t.tmp', 'A') # => 1
12299 * File.read('t.tmp') # => "A"
12300 *
12301 * If +offset+ in within the file content, the file is partly overwritten:
12302 *
12303 * IO.write('t.tmp', 'abcdef') # => 3
12304 * File.read('t.tmp') # => "abcdef"
12305 * # Offset within content.
12306 * IO.write('t.tmp', '012', 2) # => 3
12307 * File.read('t.tmp') # => "ab012f"
12308 *
12309 * If +offset+ is outside the file content,
12310 * the file is padded with null characters <tt>"\u0000"</tt>:
12311 *
12312 * IO.write('t.tmp', 'xyz', 10) # => 3
12313 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12314 *
12315 * Optional keyword arguments +opts+ specify:
12316 *
12317 * - {Open Options}[rdoc-ref:IO@Open+Options].
12318 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12319 *
12320 */
12321
12322static VALUE
12323rb_io_s_write(int argc, VALUE *argv, VALUE io)
12324{
12325 return io_s_write(argc, argv, io, 0);
12326}
12327
12328/*
12329 * call-seq:
12330 * IO.binwrite(command, string, offset = 0) -> integer
12331 * IO.binwrite(path, string, offset = 0) -> integer
12332 *
12333 * Behaves like IO.write, except that the stream is opened in binary mode
12334 * with ASCII-8BIT encoding.
12335 *
12336 * When called from class \IO (but not subclasses of \IO),
12337 * this method has potential security vulnerabilities if called with untrusted input;
12338 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12339 *
12340 */
12341
12342static VALUE
12343rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12344{
12345 return io_s_write(argc, argv, io, 1);
12346}
12347
12349 VALUE src;
12350 VALUE dst;
12351 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12352 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12353
12354 rb_io_t *src_fptr;
12355 rb_io_t *dst_fptr;
12356 unsigned close_src : 1;
12357 unsigned close_dst : 1;
12358 int error_no;
12359 rb_off_t total;
12360 const char *syserr;
12361 const char *notimp;
12362 VALUE th;
12363 struct stat src_stat;
12364 struct stat dst_stat;
12365#ifdef HAVE_FCOPYFILE
12366 copyfile_state_t copyfile_state;
12367#endif
12368};
12369
12370static void *
12371exec_interrupts(void *arg)
12372{
12373 VALUE th = (VALUE)arg;
12374 rb_thread_execute_interrupts(th);
12375 return NULL;
12376}
12377
12378/*
12379 * returns TRUE if the preceding system call was interrupted
12380 * so we can continue. If the thread was interrupted, we
12381 * reacquire the GVL to execute interrupts before continuing.
12382 */
12383static int
12384maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12385{
12386 switch (errno) {
12387 case EINTR:
12388#if defined(ERESTART)
12389 case ERESTART:
12390#endif
12391 if (rb_thread_interrupted(stp->th)) {
12392 if (has_gvl)
12393 rb_thread_execute_interrupts(stp->th);
12394 else
12395 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12396 }
12397 return TRUE;
12398 }
12399 return FALSE;
12400}
12401
12403 VALUE scheduler;
12404
12405 rb_io_t *fptr;
12406 short events;
12407
12408 VALUE result;
12409};
12410
12411static void *
12412fiber_scheduler_wait_for(void * _arguments)
12413{
12414 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12415
12416 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12417
12418 return NULL;
12419}
12420
12421#if USE_POLL
12422# define IOWAIT_SYSCALL "poll"
12423STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12424STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12425static int
12426nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12427{
12429 if (scheduler != Qnil) {
12430 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12431 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12432 return RTEST(args.result);
12433 }
12434
12435 int fd = fptr->fd;
12436 if (fd == -1) return 0;
12437
12438 struct pollfd fds;
12439
12440 fds.fd = fd;
12441 fds.events = events;
12442
12443 int timeout_milliseconds = -1;
12444
12445 if (timeout) {
12446 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12447 }
12448
12449 return poll(&fds, 1, timeout_milliseconds);
12450}
12451#else /* !USE_POLL */
12452# define IOWAIT_SYSCALL "select"
12453static int
12454nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12455{
12457 if (scheduler != Qnil) {
12458 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12459 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12460 return RTEST(args.result);
12461 }
12462
12463 int fd = fptr->fd;
12464
12465 if (fd == -1) {
12466 errno = EBADF;
12467 return -1;
12468 }
12469
12470 rb_fdset_t fds;
12471 int ret;
12472
12473 rb_fd_init(&fds);
12474 rb_fd_set(fd, &fds);
12475
12476 switch (events) {
12477 case RB_WAITFD_IN:
12478 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12479 break;
12480 case RB_WAITFD_OUT:
12481 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12482 break;
12483 default:
12484 VM_UNREACHABLE(nogvl_wait_for);
12485 }
12486
12487 rb_fd_term(&fds);
12488
12489 // On timeout, this returns 0.
12490 return ret;
12491}
12492#endif /* !USE_POLL */
12493
12494static int
12495maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12496{
12497 int ret;
12498
12499 do {
12500 if (has_gvl) {
12502 }
12503 else {
12504 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12505 }
12506 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12507
12508 if (ret < 0) {
12509 stp->syserr = IOWAIT_SYSCALL;
12510 stp->error_no = errno;
12511 return ret;
12512 }
12513 return 0;
12514}
12515
12516static int
12517nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12518{
12519 int ret;
12520
12521 do {
12522 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12523 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12524
12525 if (ret < 0) {
12526 stp->syserr = IOWAIT_SYSCALL;
12527 stp->error_no = errno;
12528 return ret;
12529 }
12530 return 0;
12531}
12532
12533#ifdef USE_COPY_FILE_RANGE
12534
12535static ssize_t
12536simple_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)
12537{
12538#ifdef HAVE_COPY_FILE_RANGE
12539 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12540#else
12541 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12542#endif
12543}
12544
12545static int
12546nogvl_copy_file_range(struct copy_stream_struct *stp)
12547{
12548 ssize_t ss;
12549 rb_off_t src_size;
12550 rb_off_t copy_length, src_offset, *src_offset_ptr;
12551
12552 if (!S_ISREG(stp->src_stat.st_mode))
12553 return 0;
12554
12555 src_size = stp->src_stat.st_size;
12556 src_offset = stp->src_offset;
12557 if (src_offset >= (rb_off_t)0) {
12558 src_offset_ptr = &src_offset;
12559 }
12560 else {
12561 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12562 }
12563
12564 copy_length = stp->copy_length;
12565 if (copy_length < (rb_off_t)0) {
12566 if (src_offset < (rb_off_t)0) {
12567 rb_off_t current_offset;
12568 errno = 0;
12569 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12570 if (current_offset < (rb_off_t)0 && errno) {
12571 stp->syserr = "lseek";
12572 stp->error_no = errno;
12573 return (int)current_offset;
12574 }
12575 copy_length = src_size - current_offset;
12576 }
12577 else {
12578 copy_length = src_size - src_offset;
12579 }
12580 }
12581
12582 retry_copy_file_range:
12583# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12584 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12585 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12586# else
12587 ss = (ssize_t)copy_length;
12588# endif
12589 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12590 if (0 < ss) {
12591 stp->total += ss;
12592 copy_length -= ss;
12593 if (0 < copy_length) {
12594 goto retry_copy_file_range;
12595 }
12596 }
12597 if (ss < 0) {
12598 if (maygvl_copy_stream_continue_p(0, stp)) {
12599 goto retry_copy_file_range;
12600 }
12601 switch (errno) {
12602 case EINVAL:
12603 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12604 docker container) */
12605#ifdef ENOSYS
12606 case ENOSYS:
12607#endif
12608#ifdef EXDEV
12609 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12610#endif
12611 return 0;
12612 case EAGAIN:
12613#if EWOULDBLOCK != EAGAIN
12614 case EWOULDBLOCK:
12615#endif
12616 {
12617 int ret = nogvl_copy_stream_wait_write(stp);
12618 if (ret < 0) return ret;
12619 }
12620 goto retry_copy_file_range;
12621 case EBADF:
12622 {
12623 int e = errno;
12624 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12625
12626 if (flags != -1 && flags & O_APPEND) {
12627 return 0;
12628 }
12629 errno = e;
12630 }
12631 }
12632 stp->syserr = "copy_file_range";
12633 stp->error_no = errno;
12634 return (int)ss;
12635 }
12636 return 1;
12637}
12638#endif
12639
12640#ifdef HAVE_FCOPYFILE
12641static int
12642nogvl_fcopyfile(struct copy_stream_struct *stp)
12643{
12644 rb_off_t cur, ss = 0;
12645 const rb_off_t src_offset = stp->src_offset;
12646 int ret;
12647
12648 if (stp->copy_length >= (rb_off_t)0) {
12649 /* copy_length can't be specified in fcopyfile(3) */
12650 return 0;
12651 }
12652
12653 if (!S_ISREG(stp->src_stat.st_mode))
12654 return 0;
12655
12656 if (!S_ISREG(stp->dst_stat.st_mode))
12657 return 0;
12658 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12659 return 0;
12660 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12661 /* fcopyfile(3) appends src IO to dst IO and then truncates
12662 * dst IO to src IO's original size. */
12663 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12664 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12665 if (end > (rb_off_t)0) return 0;
12666 }
12667
12668 if (src_offset > (rb_off_t)0) {
12669 rb_off_t r;
12670
12671 /* get current offset */
12672 errno = 0;
12673 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12674 if (cur < (rb_off_t)0 && errno) {
12675 stp->error_no = errno;
12676 return 1;
12677 }
12678
12679 errno = 0;
12680 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12681 if (r < (rb_off_t)0 && errno) {
12682 stp->error_no = errno;
12683 return 1;
12684 }
12685 }
12686
12687 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12688 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12689 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12690
12691 if (ret == 0) { /* success */
12692 stp->total = ss;
12693 if (src_offset > (rb_off_t)0) {
12694 rb_off_t r;
12695 errno = 0;
12696 /* reset offset */
12697 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12698 if (r < (rb_off_t)0 && errno) {
12699 stp->error_no = errno;
12700 return 1;
12701 }
12702 }
12703 }
12704 else {
12705 switch (errno) {
12706 case ENOTSUP:
12707 case EPERM:
12708 case EINVAL:
12709 return 0;
12710 }
12711 stp->syserr = "fcopyfile";
12712 stp->error_no = errno;
12713 return (int)ret;
12714 }
12715 return 1;
12716}
12717#endif
12718
12719#ifdef HAVE_SENDFILE
12720
12721# ifdef __linux__
12722# define USE_SENDFILE
12723
12724# ifdef HAVE_SYS_SENDFILE_H
12725# include <sys/sendfile.h>
12726# endif
12727
12728static ssize_t
12729simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12730{
12731 return sendfile(out_fd, in_fd, offset, (size_t)count);
12732}
12733
12734# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12735/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12736 * without cpuset -l 0.
12737 */
12738# define USE_SENDFILE
12739
12740static ssize_t
12741simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12742{
12743 int r;
12744 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12745 rb_off_t sbytes;
12746# ifdef __APPLE__
12747 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12748 sbytes = count;
12749# else
12750 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12751# endif
12752 if (r != 0 && sbytes == 0) return r;
12753 if (offset) {
12754 *offset += sbytes;
12755 }
12756 else {
12757 lseek(in_fd, sbytes, SEEK_CUR);
12758 }
12759 return (ssize_t)sbytes;
12760}
12761
12762# endif
12763
12764#endif
12765
12766#ifdef USE_SENDFILE
12767static int
12768nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12769{
12770 ssize_t ss;
12771 rb_off_t src_size;
12772 rb_off_t copy_length;
12773 rb_off_t src_offset;
12774 int use_pread;
12775
12776 if (!S_ISREG(stp->src_stat.st_mode))
12777 return 0;
12778
12779 src_size = stp->src_stat.st_size;
12780#ifndef __linux__
12781 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12782 return 0;
12783#endif
12784
12785 src_offset = stp->src_offset;
12786 use_pread = src_offset >= (rb_off_t)0;
12787
12788 copy_length = stp->copy_length;
12789 if (copy_length < (rb_off_t)0) {
12790 if (use_pread)
12791 copy_length = src_size - src_offset;
12792 else {
12793 rb_off_t cur;
12794 errno = 0;
12795 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12796 if (cur < (rb_off_t)0 && errno) {
12797 stp->syserr = "lseek";
12798 stp->error_no = errno;
12799 return (int)cur;
12800 }
12801 copy_length = src_size - cur;
12802 }
12803 }
12804
12805 retry_sendfile:
12806# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12807 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12808 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12809# else
12810 ss = (ssize_t)copy_length;
12811# endif
12812 if (use_pread) {
12813 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12814 }
12815 else {
12816 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12817 }
12818 if (0 < ss) {
12819 stp->total += ss;
12820 copy_length -= ss;
12821 if (0 < copy_length) {
12822 goto retry_sendfile;
12823 }
12824 }
12825 if (ss < 0) {
12826 if (maygvl_copy_stream_continue_p(0, stp))
12827 goto retry_sendfile;
12828 switch (errno) {
12829 case EINVAL:
12830#ifdef ENOSYS
12831 case ENOSYS:
12832#endif
12833#ifdef EOPNOTSUP
12834 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12835 see also: [Feature #16965] */
12836 case EOPNOTSUP:
12837#endif
12838 return 0;
12839 case EAGAIN:
12840#if EWOULDBLOCK != EAGAIN
12841 case EWOULDBLOCK:
12842#endif
12843 {
12844 int ret;
12845#ifndef __linux__
12846 /*
12847 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12848 * select() reports regular files to always be "ready", so
12849 * there is no need to select() on it.
12850 * Other OSes may have the same limitation for sendfile() which
12851 * allow us to bypass maygvl_copy_stream_wait_read()...
12852 */
12853 ret = maygvl_copy_stream_wait_read(0, stp);
12854 if (ret < 0) return ret;
12855#endif
12856 ret = nogvl_copy_stream_wait_write(stp);
12857 if (ret < 0) return ret;
12858 }
12859 goto retry_sendfile;
12860 }
12861 stp->syserr = "sendfile";
12862 stp->error_no = errno;
12863 return (int)ss;
12864 }
12865 return 1;
12866}
12867#endif
12868
12869static ssize_t
12870maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12871{
12872 if (has_gvl)
12873 return rb_io_read_memory(fptr, buf, count);
12874 else
12875 return read(fptr->fd, buf, count);
12876}
12877
12878static ssize_t
12879maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12880{
12881 ssize_t ss;
12882 retry_read:
12883 if (offset < (rb_off_t)0) {
12884 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12885 }
12886 else {
12887#ifdef HAVE_PREAD
12888 ss = pread(stp->src_fptr->fd, buf, len, offset);
12889#else
12890 stp->notimp = "pread";
12891 return -1;
12892#endif
12893 }
12894 if (ss == 0) {
12895 return 0;
12896 }
12897 if (ss < 0) {
12898 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12899 goto retry_read;
12900 switch (errno) {
12901 case EAGAIN:
12902#if EWOULDBLOCK != EAGAIN
12903 case EWOULDBLOCK:
12904#endif
12905 {
12906 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12907 if (ret < 0) return ret;
12908 }
12909 goto retry_read;
12910#ifdef ENOSYS
12911 case ENOSYS:
12912 stp->notimp = "pread";
12913 return ss;
12914#endif
12915 }
12916 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
12917 stp->error_no = errno;
12918 }
12919 return ss;
12920}
12921
12922static int
12923nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
12924{
12925 ssize_t ss;
12926 int off = 0;
12927 while (len) {
12928 ss = write(stp->dst_fptr->fd, buf+off, len);
12929 if (ss < 0) {
12930 if (maygvl_copy_stream_continue_p(0, stp))
12931 continue;
12932 if (io_again_p(errno)) {
12933 int ret = nogvl_copy_stream_wait_write(stp);
12934 if (ret < 0) return ret;
12935 continue;
12936 }
12937 stp->syserr = "write";
12938 stp->error_no = errno;
12939 return (int)ss;
12940 }
12941 off += (int)ss;
12942 len -= (int)ss;
12943 stp->total += ss;
12944 }
12945 return 0;
12946}
12947
12948static void
12949nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
12950{
12951 char buf[1024*16];
12952 size_t len;
12953 ssize_t ss;
12954 int ret;
12955 rb_off_t copy_length;
12956 rb_off_t src_offset;
12957 int use_eof;
12958 int use_pread;
12959
12960 copy_length = stp->copy_length;
12961 use_eof = copy_length < (rb_off_t)0;
12962 src_offset = stp->src_offset;
12963 use_pread = src_offset >= (rb_off_t)0;
12964
12965 if (use_pread && stp->close_src) {
12966 rb_off_t r;
12967 errno = 0;
12968 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12969 if (r < (rb_off_t)0 && errno) {
12970 stp->syserr = "lseek";
12971 stp->error_no = errno;
12972 return;
12973 }
12974 src_offset = (rb_off_t)-1;
12975 use_pread = 0;
12976 }
12977
12978 while (use_eof || 0 < copy_length) {
12979 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
12980 len = (size_t)copy_length;
12981 }
12982 else {
12983 len = sizeof(buf);
12984 }
12985 if (use_pread) {
12986 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
12987 if (0 < ss)
12988 src_offset += ss;
12989 }
12990 else {
12991 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
12992 }
12993 if (ss <= 0) /* EOF or error */
12994 return;
12995
12996 ret = nogvl_copy_stream_write(stp, buf, ss);
12997 if (ret < 0)
12998 return;
12999
13000 if (!use_eof)
13001 copy_length -= ss;
13002 }
13003}
13004
13005static void *
13006nogvl_copy_stream_func(void *arg)
13007{
13008 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13009#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13010 int ret;
13011#endif
13012
13013#ifdef USE_COPY_FILE_RANGE
13014 ret = nogvl_copy_file_range(stp);
13015 if (ret != 0)
13016 goto finish; /* error or success */
13017#endif
13018
13019#ifdef HAVE_FCOPYFILE
13020 ret = nogvl_fcopyfile(stp);
13021 if (ret != 0)
13022 goto finish; /* error or success */
13023#endif
13024
13025#ifdef USE_SENDFILE
13026 ret = nogvl_copy_stream_sendfile(stp);
13027 if (ret != 0)
13028 goto finish; /* error or success */
13029#endif
13030
13031 nogvl_copy_stream_read_write(stp);
13032
13033#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13034 finish:
13035#endif
13036 return 0;
13037}
13038
13039static VALUE
13040copy_stream_fallback_body(VALUE arg)
13041{
13042 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13043 const int buflen = 16*1024;
13044 VALUE n;
13045 VALUE buf = rb_str_buf_new(buflen);
13046 rb_off_t rest = stp->copy_length;
13047 rb_off_t off = stp->src_offset;
13048 ID read_method = id_readpartial;
13049
13050 if (!stp->src_fptr) {
13051 if (!rb_respond_to(stp->src, read_method)) {
13052 read_method = id_read;
13053 }
13054 }
13055
13056 while (1) {
13057 long numwrote;
13058 long l;
13059 if (stp->copy_length < (rb_off_t)0) {
13060 l = buflen;
13061 }
13062 else {
13063 if (rest == 0) {
13064 rb_str_resize(buf, 0);
13065 break;
13066 }
13067 l = buflen < rest ? buflen : (long)rest;
13068 }
13069 if (!stp->src_fptr) {
13070 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13071
13072 if (read_method == id_read && NIL_P(rc))
13073 break;
13074 }
13075 else {
13076 ssize_t ss;
13077 rb_str_resize(buf, buflen);
13078 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13079 rb_str_resize(buf, ss > 0 ? ss : 0);
13080 if (ss < 0)
13081 return Qnil;
13082 if (ss == 0)
13083 rb_eof_error();
13084 if (off >= (rb_off_t)0)
13085 off += ss;
13086 }
13087 n = rb_io_write(stp->dst, buf);
13088 numwrote = NUM2LONG(n);
13089 stp->total += numwrote;
13090 rest -= numwrote;
13091 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13092 break;
13093 }
13094 }
13095
13096 return Qnil;
13097}
13098
13099static VALUE
13100copy_stream_fallback(struct copy_stream_struct *stp)
13101{
13102 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13103 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13104 }
13105 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13106 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13107 rb_eEOFError, (VALUE)0);
13108 return Qnil;
13109}
13110
13111static VALUE
13112copy_stream_body(VALUE arg)
13113{
13114 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13115 VALUE src_io = stp->src, dst_io = stp->dst;
13116 const int common_oflags = 0
13117#ifdef O_NOCTTY
13118 | O_NOCTTY
13119#endif
13120 ;
13121
13122 stp->th = rb_thread_current();
13123
13124 stp->total = 0;
13125
13126 if (src_io == argf ||
13127 !(RB_TYPE_P(src_io, T_FILE) ||
13128 RB_TYPE_P(src_io, T_STRING) ||
13129 rb_respond_to(src_io, rb_intern("to_path")))) {
13130 stp->src_fptr = NULL;
13131 }
13132 else {
13133 int stat_ret;
13134 VALUE tmp_io = rb_io_check_io(src_io);
13135 if (!NIL_P(tmp_io)) {
13136 src_io = tmp_io;
13137 }
13138 else if (!RB_TYPE_P(src_io, T_FILE)) {
13139 VALUE args[2];
13140 FilePathValue(src_io);
13141 args[0] = src_io;
13142 args[1] = INT2NUM(O_RDONLY|common_oflags);
13143 src_io = rb_class_new_instance(2, args, rb_cFile);
13144 stp->src = src_io;
13145 stp->close_src = 1;
13146 }
13147 RB_IO_POINTER(src_io, stp->src_fptr);
13148 rb_io_check_byte_readable(stp->src_fptr);
13149
13150 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13151 if (stat_ret < 0) {
13152 stp->syserr = "fstat";
13153 stp->error_no = errno;
13154 return Qnil;
13155 }
13156 }
13157
13158 if (dst_io == argf ||
13159 !(RB_TYPE_P(dst_io, T_FILE) ||
13160 RB_TYPE_P(dst_io, T_STRING) ||
13161 rb_respond_to(dst_io, rb_intern("to_path")))) {
13162 stp->dst_fptr = NULL;
13163 }
13164 else {
13165 int stat_ret;
13166 VALUE tmp_io = rb_io_check_io(dst_io);
13167 if (!NIL_P(tmp_io)) {
13168 dst_io = GetWriteIO(tmp_io);
13169 }
13170 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13171 VALUE args[3];
13172 FilePathValue(dst_io);
13173 args[0] = dst_io;
13174 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13175 args[2] = INT2FIX(0666);
13176 dst_io = rb_class_new_instance(3, args, rb_cFile);
13177 stp->dst = dst_io;
13178 stp->close_dst = 1;
13179 }
13180 else {
13181 dst_io = GetWriteIO(dst_io);
13182 stp->dst = dst_io;
13183 }
13184 RB_IO_POINTER(dst_io, stp->dst_fptr);
13185 rb_io_check_writable(stp->dst_fptr);
13186
13187 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13188 if (stat_ret < 0) {
13189 stp->syserr = "fstat";
13190 stp->error_no = errno;
13191 return Qnil;
13192 }
13193 }
13194
13195#ifdef O_BINARY
13196 if (stp->src_fptr)
13197 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13198#endif
13199 if (stp->dst_fptr)
13200 io_ascii8bit_binmode(stp->dst_fptr);
13201
13202 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13203 size_t len = stp->src_fptr->rbuf.len;
13204 VALUE str;
13205 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13206 len = (size_t)stp->copy_length;
13207 }
13208 str = rb_str_buf_new(len);
13209 rb_str_resize(str,len);
13210 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13211 if (stp->dst_fptr) { /* IO or filename */
13212 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13213 rb_sys_fail_on_write(stp->dst_fptr);
13214 }
13215 else /* others such as StringIO */
13216 rb_io_write(dst_io, str);
13217 rb_str_resize(str, 0);
13218 stp->total += len;
13219 if (stp->copy_length >= (rb_off_t)0)
13220 stp->copy_length -= len;
13221 }
13222
13223 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13224 rb_raise(rb_eIOError, "flush failed");
13225 }
13226
13227 if (stp->copy_length == 0)
13228 return Qnil;
13229
13230 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13231 return copy_stream_fallback(stp);
13232 }
13233
13234 rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
13235 return Qnil;
13236}
13237
13238static VALUE
13239copy_stream_finalize(VALUE arg)
13240{
13241 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13242
13243#ifdef HAVE_FCOPYFILE
13244 if (stp->copyfile_state) {
13245 copyfile_state_free(stp->copyfile_state);
13246 }
13247#endif
13248
13249 if (stp->close_src) {
13250 rb_io_close_m(stp->src);
13251 }
13252 if (stp->close_dst) {
13253 rb_io_close_m(stp->dst);
13254 }
13255 if (stp->syserr) {
13256 rb_syserr_fail(stp->error_no, stp->syserr);
13257 }
13258 if (stp->notimp) {
13259 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13260 }
13261 return Qnil;
13262}
13263
13264/*
13265 * call-seq:
13266 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13267 *
13268 * Copies from the given +src+ to the given +dst+,
13269 * returning the number of bytes copied.
13270 *
13271 * - The given +src+ must be one of the following:
13272 *
13273 * - The path to a readable file, from which source data is to be read.
13274 * - An \IO-like object, opened for reading and capable of responding
13275 * to method +:readpartial+ or method +:read+.
13276 *
13277 * - The given +dst+ must be one of the following:
13278 *
13279 * - The path to a writable file, to which data is to be written.
13280 * - An \IO-like object, opened for writing and capable of responding
13281 * to method +:write+.
13282 *
13283 * The examples here use file <tt>t.txt</tt> as source:
13284 *
13285 * File.read('t.txt')
13286 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13287 * File.read('t.txt').size # => 47
13288 *
13289 * If only arguments +src+ and +dst+ are given,
13290 * the entire source stream is copied:
13291 *
13292 * # Paths.
13293 * IO.copy_stream('t.txt', 't.tmp') # => 47
13294 *
13295 * # IOs (recall that a File is also an IO).
13296 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13297 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13298 * IO.copy_stream(src_io, dst_io) # => 47
13299 * src_io.close
13300 * dst_io.close
13301 *
13302 * With argument +src_length+ a non-negative integer,
13303 * no more than that many bytes are copied:
13304 *
13305 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13306 * File.read('t.tmp') # => "First line"
13307 *
13308 * With argument +src_offset+ also given,
13309 * the source stream is read beginning at that offset:
13310 *
13311 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13312 * IO.read('t.tmp') # => "Second line"
13313 *
13314 */
13315static VALUE
13316rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13317{
13318 VALUE src, dst, length, src_offset;
13319 struct copy_stream_struct st;
13320
13321 MEMZERO(&st, struct copy_stream_struct, 1);
13322
13323 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13324
13325 st.src = src;
13326 st.dst = dst;
13327
13328 st.src_fptr = NULL;
13329 st.dst_fptr = NULL;
13330
13331 if (NIL_P(length))
13332 st.copy_length = (rb_off_t)-1;
13333 else
13334 st.copy_length = NUM2OFFT(length);
13335
13336 if (NIL_P(src_offset))
13337 st.src_offset = (rb_off_t)-1;
13338 else
13339 st.src_offset = NUM2OFFT(src_offset);
13340
13341 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13342
13343 return OFFT2NUM(st.total);
13344}
13345
13346/*
13347 * call-seq:
13348 * external_encoding -> encoding or nil
13349 *
13350 * Returns the Encoding object that represents the encoding of the stream,
13351 * or +nil+ if the stream is in write mode and no encoding is specified.
13352 *
13353 * See {Encodings}[rdoc-ref:File@Encodings].
13354 *
13355 */
13356
13357static VALUE
13358rb_io_external_encoding(VALUE io)
13359{
13360 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13361
13362 if (fptr->encs.enc2) {
13363 return rb_enc_from_encoding(fptr->encs.enc2);
13364 }
13365 if (fptr->mode & FMODE_WRITABLE) {
13366 if (fptr->encs.enc)
13367 return rb_enc_from_encoding(fptr->encs.enc);
13368 return Qnil;
13369 }
13370 return rb_enc_from_encoding(io_read_encoding(fptr));
13371}
13372
13373/*
13374 * call-seq:
13375 * internal_encoding -> encoding or nil
13376 *
13377 * Returns the Encoding object that represents the encoding of the internal string,
13378 * if conversion is specified,
13379 * or +nil+ otherwise.
13380 *
13381 * See {Encodings}[rdoc-ref:File@Encodings].
13382 *
13383 */
13384
13385static VALUE
13386rb_io_internal_encoding(VALUE io)
13387{
13388 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13389
13390 if (!fptr->encs.enc2) return Qnil;
13391 return rb_enc_from_encoding(io_read_encoding(fptr));
13392}
13393
13394/*
13395 * call-seq:
13396 * set_encoding(ext_enc) -> self
13397 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13398 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13399 *
13400 * See {Encodings}[rdoc-ref:File@Encodings].
13401 *
13402 * Argument +ext_enc+, if given, must be an Encoding object;
13403 * it is assigned as the encoding for the stream.
13404 *
13405 * Argument +int_enc+, if given, must be an Encoding object;
13406 * it is assigned as the encoding for the internal string.
13407 *
13408 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13409 * containing two colon-separated encoding names;
13410 * corresponding Encoding objects are assigned as the external
13411 * and internal encodings for the stream.
13412 *
13413 * Optional keyword arguments +enc_opts+ specify
13414 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13415 *
13416 */
13417
13418static VALUE
13419rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13420{
13421 rb_io_t *fptr;
13422 VALUE v1, v2, opt;
13423
13424 if (!RB_TYPE_P(io, T_FILE)) {
13425 return forward(io, id_set_encoding, argc, argv);
13426 }
13427
13428 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13429 GetOpenFile(io, fptr);
13430 io_encoding_set(fptr, v1, v2, opt);
13431 return io;
13432}
13433
13434void
13435rb_stdio_set_default_encoding(void)
13436{
13437 VALUE val = Qnil;
13438
13439#ifdef _WIN32
13440 if (isatty(fileno(stdin))) {
13441 rb_encoding *external = rb_locale_encoding();
13442 rb_encoding *internal = rb_default_internal_encoding();
13443 if (!internal) internal = rb_default_external_encoding();
13444 io_encoding_set(RFILE(rb_stdin)->fptr,
13445 rb_enc_from_encoding(external),
13446 rb_enc_from_encoding(internal),
13447 Qnil);
13448 }
13449 else
13450#endif
13451 rb_io_set_encoding(1, &val, rb_stdin);
13452 rb_io_set_encoding(1, &val, rb_stdout);
13453 rb_io_set_encoding(1, &val, rb_stderr);
13454}
13455
13456static inline int
13457global_argf_p(VALUE arg)
13458{
13459 return arg == argf;
13460}
13461
13462typedef VALUE (*argf_encoding_func)(VALUE io);
13463
13464static VALUE
13465argf_encoding(VALUE argf, argf_encoding_func func)
13466{
13467 if (!RTEST(ARGF.current_file)) {
13468 return rb_enc_default_external();
13469 }
13470 return func(rb_io_check_io(ARGF.current_file));
13471}
13472
13473/*
13474 * call-seq:
13475 * ARGF.external_encoding -> encoding
13476 *
13477 * Returns the external encoding for files read from ARGF as an Encoding
13478 * object. The external encoding is the encoding of the text as stored in a
13479 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13480 * represent this text within Ruby.
13481 *
13482 * To set the external encoding use ARGF.set_encoding.
13483 *
13484 * For example:
13485 *
13486 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13487 *
13488 */
13489static VALUE
13490argf_external_encoding(VALUE argf)
13491{
13492 return argf_encoding(argf, rb_io_external_encoding);
13493}
13494
13495/*
13496 * call-seq:
13497 * ARGF.internal_encoding -> encoding
13498 *
13499 * Returns the internal encoding for strings read from ARGF as an
13500 * Encoding object.
13501 *
13502 * If ARGF.set_encoding has been called with two encoding names, the second
13503 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13504 * value is returned. Failing that, if a default external encoding was
13505 * specified on the command-line, that value is used. If the encoding is
13506 * unknown, +nil+ is returned.
13507 */
13508static VALUE
13509argf_internal_encoding(VALUE argf)
13510{
13511 return argf_encoding(argf, rb_io_internal_encoding);
13512}
13513
13514/*
13515 * call-seq:
13516 * ARGF.set_encoding(ext_enc) -> ARGF
13517 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13518 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13519 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13520 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13521 *
13522 * If single argument is specified, strings read from ARGF are tagged with
13523 * the encoding specified.
13524 *
13525 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13526 * the read string is converted from the first encoding (external encoding)
13527 * to the second encoding (internal encoding), then tagged with the second
13528 * encoding.
13529 *
13530 * If two arguments are specified, they must be encoding objects or encoding
13531 * names. Again, the first specifies the external encoding; the second
13532 * specifies the internal encoding.
13533 *
13534 * If the external encoding and the internal encoding are specified, the
13535 * optional Hash argument can be used to adjust the conversion process. The
13536 * structure of this hash is explained in the String#encode documentation.
13537 *
13538 * For example:
13539 *
13540 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13541 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13542 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13543 * # to UTF-8.
13544 */
13545static VALUE
13546argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13547{
13548 rb_io_t *fptr;
13549
13550 if (!next_argv()) {
13551 rb_raise(rb_eArgError, "no stream to set encoding");
13552 }
13553 rb_io_set_encoding(argc, argv, ARGF.current_file);
13554 GetOpenFile(ARGF.current_file, fptr);
13555 ARGF.encs = fptr->encs;
13556 return argf;
13557}
13558
13559/*
13560 * call-seq:
13561 * ARGF.tell -> Integer
13562 * ARGF.pos -> Integer
13563 *
13564 * Returns the current offset (in bytes) of the current file in ARGF.
13565 *
13566 * ARGF.pos #=> 0
13567 * ARGF.gets #=> "This is line one\n"
13568 * ARGF.pos #=> 17
13569 *
13570 */
13571static VALUE
13572argf_tell(VALUE argf)
13573{
13574 if (!next_argv()) {
13575 rb_raise(rb_eArgError, "no stream to tell");
13576 }
13577 ARGF_FORWARD(0, 0);
13578 return rb_io_tell(ARGF.current_file);
13579}
13580
13581/*
13582 * call-seq:
13583 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13584 *
13585 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13586 * the value of _whence_. See IO#seek for further details.
13587 */
13588static VALUE
13589argf_seek_m(int argc, VALUE *argv, VALUE argf)
13590{
13591 if (!next_argv()) {
13592 rb_raise(rb_eArgError, "no stream to seek");
13593 }
13594 ARGF_FORWARD(argc, argv);
13595 return rb_io_seek_m(argc, argv, ARGF.current_file);
13596}
13597
13598/*
13599 * call-seq:
13600 * ARGF.pos = position -> Integer
13601 *
13602 * Seeks to the position given by _position_ (in bytes) in ARGF.
13603 *
13604 * For example:
13605 *
13606 * ARGF.pos = 17
13607 * ARGF.gets #=> "This is line two\n"
13608 */
13609static VALUE
13610argf_set_pos(VALUE argf, VALUE offset)
13611{
13612 if (!next_argv()) {
13613 rb_raise(rb_eArgError, "no stream to set position");
13614 }
13615 ARGF_FORWARD(1, &offset);
13616 return rb_io_set_pos(ARGF.current_file, offset);
13617}
13618
13619/*
13620 * call-seq:
13621 * ARGF.rewind -> 0
13622 *
13623 * Positions the current file to the beginning of input, resetting
13624 * ARGF.lineno to zero.
13625 *
13626 * ARGF.readline #=> "This is line one\n"
13627 * ARGF.rewind #=> 0
13628 * ARGF.lineno #=> 0
13629 * ARGF.readline #=> "This is line one\n"
13630 */
13631static VALUE
13632argf_rewind(VALUE argf)
13633{
13634 VALUE ret;
13635 int old_lineno;
13636
13637 if (!next_argv()) {
13638 rb_raise(rb_eArgError, "no stream to rewind");
13639 }
13640 ARGF_FORWARD(0, 0);
13641 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13642 ret = rb_io_rewind(ARGF.current_file);
13643 if (!global_argf_p(argf)) {
13644 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13645 }
13646 return ret;
13647}
13648
13649/*
13650 * call-seq:
13651 * ARGF.fileno -> integer
13652 * ARGF.to_i -> integer
13653 *
13654 * Returns an integer representing the numeric file descriptor for
13655 * the current file. Raises an ArgumentError if there isn't a current file.
13656 *
13657 * ARGF.fileno #=> 3
13658 */
13659static VALUE
13660argf_fileno(VALUE argf)
13661{
13662 if (!next_argv()) {
13663 rb_raise(rb_eArgError, "no stream");
13664 }
13665 ARGF_FORWARD(0, 0);
13666 return rb_io_fileno(ARGF.current_file);
13667}
13668
13669/*
13670 * call-seq:
13671 * ARGF.to_io -> IO
13672 *
13673 * Returns an IO object representing the current file. This will be a
13674 * File object unless the current file is a stream such as STDIN.
13675 *
13676 * For example:
13677 *
13678 * ARGF.to_io #=> #<File:glark.txt>
13679 * ARGF.to_io #=> #<IO:<STDIN>>
13680 */
13681static VALUE
13682argf_to_io(VALUE argf)
13683{
13684 next_argv();
13685 ARGF_FORWARD(0, 0);
13686 return ARGF.current_file;
13687}
13688
13689/*
13690 * call-seq:
13691 * ARGF.eof? -> true or false
13692 * ARGF.eof -> true or false
13693 *
13694 * Returns true if the current file in ARGF is at end of file, i.e. it has
13695 * no data to read. The stream must be opened for reading or an IOError
13696 * will be raised.
13697 *
13698 * $ echo "eof" | ruby argf.rb
13699 *
13700 * ARGF.eof? #=> false
13701 * 3.times { ARGF.readchar }
13702 * ARGF.eof? #=> false
13703 * ARGF.readchar #=> "\n"
13704 * ARGF.eof? #=> true
13705 */
13706
13707static VALUE
13708argf_eof(VALUE argf)
13709{
13710 next_argv();
13711 if (RTEST(ARGF.current_file)) {
13712 if (ARGF.init_p == 0) return Qtrue;
13713 next_argv();
13714 ARGF_FORWARD(0, 0);
13715 if (rb_io_eof(ARGF.current_file)) {
13716 return Qtrue;
13717 }
13718 }
13719 return Qfalse;
13720}
13721
13722/*
13723 * call-seq:
13724 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13725 *
13726 * Reads _length_ bytes from ARGF. The files named on the command line
13727 * are concatenated and treated as a single file by this method, so when
13728 * called without arguments the contents of this pseudo file are returned in
13729 * their entirety.
13730 *
13731 * _length_ must be a non-negative integer or +nil+.
13732 *
13733 * If _length_ is a positive integer, +read+ tries to read
13734 * _length_ bytes without any conversion (binary mode).
13735 * It returns +nil+ if an EOF is encountered before anything can be read.
13736 * Fewer than _length_ bytes are returned if an EOF is encountered during
13737 * the read.
13738 * In the case of an integer _length_, the resulting string is always
13739 * in ASCII-8BIT encoding.
13740 *
13741 * If _length_ is omitted or is +nil+, it reads until EOF
13742 * and the encoding conversion is applied, if applicable.
13743 * A string is returned even if EOF is encountered before any data is read.
13744 *
13745 * If _length_ is zero, it returns an empty string (<code>""</code>).
13746 *
13747 * If the optional _outbuf_ argument is present,
13748 * it must reference a String, which will receive the data.
13749 * The _outbuf_ will contain only the received data after the method call
13750 * even if it is not empty at the beginning.
13751 *
13752 * For example:
13753 *
13754 * $ echo "small" > small.txt
13755 * $ echo "large" > large.txt
13756 * $ ./glark.rb small.txt large.txt
13757 *
13758 * ARGF.read #=> "small\nlarge"
13759 * ARGF.read(200) #=> "small\nlarge"
13760 * ARGF.read(2) #=> "sm"
13761 * ARGF.read(0) #=> ""
13762 *
13763 * Note that this method behaves like the fread() function in C.
13764 * This means it retries to invoke read(2) system calls to read data
13765 * with the specified length.
13766 * If you need the behavior like a single read(2) system call,
13767 * consider ARGF#readpartial or ARGF#read_nonblock.
13768 */
13769
13770static VALUE
13771argf_read(int argc, VALUE *argv, VALUE argf)
13772{
13773 VALUE tmp, str, length;
13774 long len = 0;
13775
13776 rb_scan_args(argc, argv, "02", &length, &str);
13777 if (!NIL_P(length)) {
13778 len = NUM2LONG(argv[0]);
13779 }
13780 if (!NIL_P(str)) {
13781 StringValue(str);
13782 rb_str_resize(str,0);
13783 argv[1] = Qnil;
13784 }
13785
13786 retry:
13787 if (!next_argv()) {
13788 return str;
13789 }
13790 if (ARGF_GENERIC_INPUT_P()) {
13791 tmp = argf_forward(argc, argv, argf);
13792 }
13793 else {
13794 tmp = io_read(argc, argv, ARGF.current_file);
13795 }
13796 if (NIL_P(str)) str = tmp;
13797 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13798 if (NIL_P(tmp) || NIL_P(length)) {
13799 if (ARGF.next_p != -1) {
13800 argf_close(argf);
13801 ARGF.next_p = 1;
13802 goto retry;
13803 }
13804 }
13805 else if (argc >= 1) {
13806 long slen = RSTRING_LEN(str);
13807 if (slen < len) {
13808 argv[0] = LONG2NUM(len - slen);
13809 goto retry;
13810 }
13811 }
13812 return str;
13813}
13814
13816 int argc;
13817 VALUE *argv;
13818 VALUE argf;
13819};
13820
13821static VALUE
13822argf_forward_call(VALUE arg)
13823{
13824 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13825 argf_forward(p->argc, p->argv, p->argf);
13826 return Qnil;
13827}
13828
13829static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13830 int nonblock);
13831
13832/*
13833 * call-seq:
13834 * ARGF.readpartial(maxlen) -> string
13835 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13836 *
13837 * Reads at most _maxlen_ bytes from the ARGF stream.
13838 *
13839 * If the optional _outbuf_ argument is present,
13840 * it must reference a String, which will receive the data.
13841 * The _outbuf_ will contain only the received data after the method call
13842 * even if it is not empty at the beginning.
13843 *
13844 * It raises EOFError on end of ARGF stream.
13845 * Since ARGF stream is a concatenation of multiple files,
13846 * internally EOF is occur for each file.
13847 * ARGF.readpartial returns empty strings for EOFs except the last one and
13848 * raises EOFError for the last one.
13849 *
13850 */
13851
13852static VALUE
13853argf_readpartial(int argc, VALUE *argv, VALUE argf)
13854{
13855 return argf_getpartial(argc, argv, argf, Qnil, 0);
13856}
13857
13858/*
13859 * call-seq:
13860 * ARGF.read_nonblock(maxlen[, options]) -> string
13861 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13862 *
13863 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13864 */
13865
13866static VALUE
13867argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13868{
13869 VALUE opts;
13870
13871 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13872
13873 if (!NIL_P(opts))
13874 argc--;
13875
13876 return argf_getpartial(argc, argv, argf, opts, 1);
13877}
13878
13879static VALUE
13880argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13881{
13882 VALUE tmp, str, length;
13883 int no_exception;
13884
13885 rb_scan_args(argc, argv, "11", &length, &str);
13886 if (!NIL_P(str)) {
13887 StringValue(str);
13888 argv[1] = str;
13889 }
13890 no_exception = no_exception_p(opts);
13891
13892 if (!next_argv()) {
13893 if (!NIL_P(str)) {
13894 rb_str_resize(str, 0);
13895 }
13896 rb_eof_error();
13897 }
13898 if (ARGF_GENERIC_INPUT_P()) {
13899 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13900 struct argf_call_arg arg;
13901 arg.argc = argc;
13902 arg.argv = argv;
13903 arg.argf = argf;
13904 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
13905 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
13906 }
13907 else {
13908 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13909 }
13910 if (NIL_P(tmp)) {
13911 if (ARGF.next_p == -1) {
13912 return io_nonblock_eof(no_exception);
13913 }
13914 argf_close(argf);
13915 ARGF.next_p = 1;
13916 if (RARRAY_LEN(ARGF.argv) == 0) {
13917 return io_nonblock_eof(no_exception);
13918 }
13919 if (NIL_P(str))
13920 str = rb_str_new(NULL, 0);
13921 return str;
13922 }
13923 return tmp;
13924}
13925
13926/*
13927 * call-seq:
13928 * ARGF.getc -> String or nil
13929 *
13930 * Reads the next character from ARGF and returns it as a String. Returns
13931 * +nil+ at the end of the stream.
13932 *
13933 * ARGF treats the files named on the command line as a single file created
13934 * by concatenating their contents. After returning the last character of the
13935 * first file, it returns the first character of the second file, and so on.
13936 *
13937 * For example:
13938 *
13939 * $ echo "foo" > file
13940 * $ ruby argf.rb file
13941 *
13942 * ARGF.getc #=> "f"
13943 * ARGF.getc #=> "o"
13944 * ARGF.getc #=> "o"
13945 * ARGF.getc #=> "\n"
13946 * ARGF.getc #=> nil
13947 * ARGF.getc #=> nil
13948 */
13949static VALUE
13950argf_getc(VALUE argf)
13951{
13952 VALUE ch;
13953
13954 retry:
13955 if (!next_argv()) return Qnil;
13956 if (ARGF_GENERIC_INPUT_P()) {
13957 ch = forward_current(rb_intern("getc"), 0, 0);
13958 }
13959 else {
13960 ch = rb_io_getc(ARGF.current_file);
13961 }
13962 if (NIL_P(ch) && ARGF.next_p != -1) {
13963 argf_close(argf);
13964 ARGF.next_p = 1;
13965 goto retry;
13966 }
13967
13968 return ch;
13969}
13970
13971/*
13972 * call-seq:
13973 * ARGF.getbyte -> Integer or nil
13974 *
13975 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
13976 * the end of the stream.
13977 *
13978 * For example:
13979 *
13980 * $ echo "foo" > file
13981 * $ ruby argf.rb file
13982 *
13983 * ARGF.getbyte #=> 102
13984 * ARGF.getbyte #=> 111
13985 * ARGF.getbyte #=> 111
13986 * ARGF.getbyte #=> 10
13987 * ARGF.getbyte #=> nil
13988 */
13989static VALUE
13990argf_getbyte(VALUE argf)
13991{
13992 VALUE ch;
13993
13994 retry:
13995 if (!next_argv()) return Qnil;
13996 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
13997 ch = forward_current(rb_intern("getbyte"), 0, 0);
13998 }
13999 else {
14000 ch = rb_io_getbyte(ARGF.current_file);
14001 }
14002 if (NIL_P(ch) && ARGF.next_p != -1) {
14003 argf_close(argf);
14004 ARGF.next_p = 1;
14005 goto retry;
14006 }
14007
14008 return ch;
14009}
14010
14011/*
14012 * call-seq:
14013 * ARGF.readchar -> String or nil
14014 *
14015 * Reads the next character from ARGF and returns it as a String. Raises
14016 * an EOFError after the last character of the last file has been read.
14017 *
14018 * For example:
14019 *
14020 * $ echo "foo" > file
14021 * $ ruby argf.rb file
14022 *
14023 * ARGF.readchar #=> "f"
14024 * ARGF.readchar #=> "o"
14025 * ARGF.readchar #=> "o"
14026 * ARGF.readchar #=> "\n"
14027 * ARGF.readchar #=> end of file reached (EOFError)
14028 */
14029static VALUE
14030argf_readchar(VALUE argf)
14031{
14032 VALUE ch;
14033
14034 retry:
14035 if (!next_argv()) rb_eof_error();
14036 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14037 ch = forward_current(rb_intern("getc"), 0, 0);
14038 }
14039 else {
14040 ch = rb_io_getc(ARGF.current_file);
14041 }
14042 if (NIL_P(ch) && ARGF.next_p != -1) {
14043 argf_close(argf);
14044 ARGF.next_p = 1;
14045 goto retry;
14046 }
14047
14048 return ch;
14049}
14050
14051/*
14052 * call-seq:
14053 * ARGF.readbyte -> Integer
14054 *
14055 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14056 * an EOFError after the last byte of the last file has been read.
14057 *
14058 * For example:
14059 *
14060 * $ echo "foo" > file
14061 * $ ruby argf.rb file
14062 *
14063 * ARGF.readbyte #=> 102
14064 * ARGF.readbyte #=> 111
14065 * ARGF.readbyte #=> 111
14066 * ARGF.readbyte #=> 10
14067 * ARGF.readbyte #=> end of file reached (EOFError)
14068 */
14069static VALUE
14070argf_readbyte(VALUE argf)
14071{
14072 VALUE c;
14073
14074 NEXT_ARGF_FORWARD(0, 0);
14075 c = argf_getbyte(argf);
14076 if (NIL_P(c)) {
14077 rb_eof_error();
14078 }
14079 return c;
14080}
14081
14082#define FOREACH_ARGF() while (next_argv())
14083
14084static VALUE
14085argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14086{
14087 const VALUE current = ARGF.current_file;
14088 rb_yield_values2(argc, argv);
14089 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14091 }
14092 return Qnil;
14093}
14094
14095#define ARGF_block_call(mid, argc, argv, func, argf) \
14096 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14097 func, argf, rb_keyword_given_p())
14098
14099static void
14100argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14101{
14102 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14103 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14104}
14105
14106static VALUE
14107argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14108{
14109 if (!global_argf_p(argf)) {
14110 ARGF.last_lineno = ++ARGF.lineno;
14111 }
14112 return argf_block_call_i(i, argf, argc, argv, blockarg);
14113}
14114
14115static void
14116argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14117{
14118 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14119 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14120}
14121
14122/*
14123 * call-seq:
14124 * ARGF.each(sep=$/) {|line| block } -> ARGF
14125 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14126 * ARGF.each(...) -> an_enumerator
14127 *
14128 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14129 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14130 * ARGF.each_line(...) -> an_enumerator
14131 *
14132 * Returns an enumerator which iterates over each line (separated by _sep_,
14133 * which defaults to your platform's newline character) of each file in
14134 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14135 * block, otherwise an enumerator is returned.
14136 * The optional _limit_ argument is an Integer specifying the maximum
14137 * length of each line; longer lines will be split according to this limit.
14138 *
14139 * This method allows you to treat the files supplied on the command line as
14140 * a single file consisting of the concatenation of each named file. After
14141 * the last line of the first file has been returned, the first line of the
14142 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14143 * used to determine the filename of the current line and line number of the
14144 * whole input, respectively.
14145 *
14146 * For example, the following code prints out each line of each named file
14147 * prefixed with its line number, displaying the filename once per file:
14148 *
14149 * ARGF.each_line do |line|
14150 * puts ARGF.filename if ARGF.file.lineno == 1
14151 * puts "#{ARGF.file.lineno}: #{line}"
14152 * end
14153 *
14154 * While the following code prints only the first file's name at first, and
14155 * the contents with line number counted through all named files.
14156 *
14157 * ARGF.each_line do |line|
14158 * puts ARGF.filename if ARGF.lineno == 1
14159 * puts "#{ARGF.lineno}: #{line}"
14160 * end
14161 */
14162static VALUE
14163argf_each_line(int argc, VALUE *argv, VALUE argf)
14164{
14165 RETURN_ENUMERATOR(argf, argc, argv);
14166 FOREACH_ARGF() {
14167 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14168 }
14169 return argf;
14170}
14171
14172/*
14173 * call-seq:
14174 * ARGF.each_byte {|byte| block } -> ARGF
14175 * ARGF.each_byte -> an_enumerator
14176 *
14177 * Iterates over each byte of each file in +ARGV+.
14178 * A byte is returned as an Integer in the range 0..255.
14179 *
14180 * This method allows you to treat the files supplied on the command line as
14181 * a single file consisting of the concatenation of each named file. After
14182 * the last byte of the first file has been returned, the first byte of the
14183 * second file is returned. The ARGF.filename method can be used to
14184 * determine the filename of the current byte.
14185 *
14186 * If no block is given, an enumerator is returned instead.
14187 *
14188 * For example:
14189 *
14190 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14191 *
14192 */
14193static VALUE
14194argf_each_byte(VALUE argf)
14195{
14196 RETURN_ENUMERATOR(argf, 0, 0);
14197 FOREACH_ARGF() {
14198 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14199 }
14200 return argf;
14201}
14202
14203/*
14204 * call-seq:
14205 * ARGF.each_char {|char| block } -> ARGF
14206 * ARGF.each_char -> an_enumerator
14207 *
14208 * Iterates over each character of each file in ARGF.
14209 *
14210 * This method allows you to treat the files supplied on the command line as
14211 * a single file consisting of the concatenation of each named file. After
14212 * the last character of the first file has been returned, the first
14213 * character of the second file is returned. The ARGF.filename method can
14214 * be used to determine the name of the file in which the current character
14215 * appears.
14216 *
14217 * If no block is given, an enumerator is returned instead.
14218 */
14219static VALUE
14220argf_each_char(VALUE argf)
14221{
14222 RETURN_ENUMERATOR(argf, 0, 0);
14223 FOREACH_ARGF() {
14224 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14225 }
14226 return argf;
14227}
14228
14229/*
14230 * call-seq:
14231 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14232 * ARGF.each_codepoint -> an_enumerator
14233 *
14234 * Iterates over each codepoint of each file in ARGF.
14235 *
14236 * This method allows you to treat the files supplied on the command line as
14237 * a single file consisting of the concatenation of each named file. After
14238 * the last codepoint of the first file has been returned, the first
14239 * codepoint of the second file is returned. The ARGF.filename method can
14240 * be used to determine the name of the file in which the current codepoint
14241 * appears.
14242 *
14243 * If no block is given, an enumerator is returned instead.
14244 */
14245static VALUE
14246argf_each_codepoint(VALUE argf)
14247{
14248 RETURN_ENUMERATOR(argf, 0, 0);
14249 FOREACH_ARGF() {
14250 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14251 }
14252 return argf;
14253}
14254
14255/*
14256 * call-seq:
14257 * ARGF.filename -> String
14258 * ARGF.path -> String
14259 *
14260 * Returns the current filename. "-" is returned when the current file is
14261 * STDIN.
14262 *
14263 * For example:
14264 *
14265 * $ echo "foo" > foo
14266 * $ echo "bar" > bar
14267 * $ echo "glark" > glark
14268 *
14269 * $ ruby argf.rb foo bar glark
14270 *
14271 * ARGF.filename #=> "foo"
14272 * ARGF.read(5) #=> "foo\nb"
14273 * ARGF.filename #=> "bar"
14274 * ARGF.skip
14275 * ARGF.filename #=> "glark"
14276 */
14277static VALUE
14278argf_filename(VALUE argf)
14279{
14280 next_argv();
14281 return ARGF.filename;
14282}
14283
14284static VALUE
14285argf_filename_getter(ID id, VALUE *var)
14286{
14287 return argf_filename(*var);
14288}
14289
14290/*
14291 * call-seq:
14292 * ARGF.file -> IO or File object
14293 *
14294 * Returns the current file as an IO or File object.
14295 * <code>$stdin</code> is returned when the current file is STDIN.
14296 *
14297 * For example:
14298 *
14299 * $ echo "foo" > foo
14300 * $ echo "bar" > bar
14301 *
14302 * $ ruby argf.rb foo bar
14303 *
14304 * ARGF.file #=> #<File:foo>
14305 * ARGF.read(5) #=> "foo\nb"
14306 * ARGF.file #=> #<File:bar>
14307 */
14308static VALUE
14309argf_file(VALUE argf)
14310{
14311 next_argv();
14312 return ARGF.current_file;
14313}
14314
14315/*
14316 * call-seq:
14317 * ARGF.binmode -> ARGF
14318 *
14319 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14320 * be reset to non-binary mode. This option has the following effects:
14321 *
14322 * * Newline conversion is disabled.
14323 * * Encoding conversion is disabled.
14324 * * Content is treated as ASCII-8BIT.
14325 */
14326static VALUE
14327argf_binmode_m(VALUE argf)
14328{
14329 ARGF.binmode = 1;
14330 next_argv();
14331 ARGF_FORWARD(0, 0);
14332 rb_io_ascii8bit_binmode(ARGF.current_file);
14333 return argf;
14334}
14335
14336/*
14337 * call-seq:
14338 * ARGF.binmode? -> true or false
14339 *
14340 * Returns true if ARGF is being read in binary mode; false otherwise.
14341 * To enable binary mode use ARGF.binmode.
14342 *
14343 * For example:
14344 *
14345 * ARGF.binmode? #=> false
14346 * ARGF.binmode
14347 * ARGF.binmode? #=> true
14348 */
14349static VALUE
14350argf_binmode_p(VALUE argf)
14351{
14352 return RBOOL(ARGF.binmode);
14353}
14354
14355/*
14356 * call-seq:
14357 * ARGF.skip -> ARGF
14358 *
14359 * Sets the current file to the next file in ARGV. If there aren't any more
14360 * files it has no effect.
14361 *
14362 * For example:
14363 *
14364 * $ ruby argf.rb foo bar
14365 * ARGF.filename #=> "foo"
14366 * ARGF.skip
14367 * ARGF.filename #=> "bar"
14368 */
14369static VALUE
14370argf_skip(VALUE argf)
14371{
14372 if (ARGF.init_p && ARGF.next_p == 0) {
14373 argf_close(argf);
14374 ARGF.next_p = 1;
14375 }
14376 return argf;
14377}
14378
14379/*
14380 * call-seq:
14381 * ARGF.close -> ARGF
14382 *
14383 * Closes the current file and skips to the next file in ARGV. If there are
14384 * no more files to open, just closes the current file. STDIN will not be
14385 * closed.
14386 *
14387 * For example:
14388 *
14389 * $ ruby argf.rb foo bar
14390 *
14391 * ARGF.filename #=> "foo"
14392 * ARGF.close
14393 * ARGF.filename #=> "bar"
14394 * ARGF.close
14395 */
14396static VALUE
14397argf_close_m(VALUE argf)
14398{
14399 next_argv();
14400 argf_close(argf);
14401 if (ARGF.next_p != -1) {
14402 ARGF.next_p = 1;
14403 }
14404 ARGF.lineno = 0;
14405 return argf;
14406}
14407
14408/*
14409 * call-seq:
14410 * ARGF.closed? -> true or false
14411 *
14412 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14413 * ARGF.close to actually close the current file.
14414 */
14415static VALUE
14416argf_closed(VALUE argf)
14417{
14418 next_argv();
14419 ARGF_FORWARD(0, 0);
14420 return rb_io_closed(ARGF.current_file);
14421}
14422
14423/*
14424 * call-seq:
14425 * ARGF.to_s -> String
14426 *
14427 * Returns "ARGF".
14428 */
14429static VALUE
14430argf_to_s(VALUE argf)
14431{
14432 return rb_str_new2("ARGF");
14433}
14434
14435/*
14436 * call-seq:
14437 * ARGF.inplace_mode -> String
14438 *
14439 * Returns the file extension appended to the names of backup copies of
14440 * modified files under in-place edit mode. This value can be set using
14441 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14442 */
14443static VALUE
14444argf_inplace_mode_get(VALUE argf)
14445{
14446 if (!ARGF.inplace) return Qnil;
14447 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14448 return rb_str_dup(ARGF.inplace);
14449}
14450
14451static VALUE
14452opt_i_get(ID id, VALUE *var)
14453{
14454 return argf_inplace_mode_get(*var);
14455}
14456
14457/*
14458 * call-seq:
14459 * ARGF.inplace_mode = ext -> ARGF
14460 *
14461 * Sets the filename extension for in-place editing mode to the given String.
14462 * The backup copy of each file being edited has this value appended to its
14463 * filename.
14464 *
14465 * For example:
14466 *
14467 * $ ruby argf.rb file.txt
14468 *
14469 * ARGF.inplace_mode = '.bak'
14470 * ARGF.each_line do |line|
14471 * print line.sub("foo","bar")
14472 * end
14473 *
14474 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14475 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14476 * "bar".
14477 */
14478static VALUE
14479argf_inplace_mode_set(VALUE argf, VALUE val)
14480{
14481 if (!RTEST(val)) {
14482 ARGF.inplace = Qfalse;
14483 }
14484 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14485 ARGF.inplace = Qnil;
14486 }
14487 else {
14488 ARGF.inplace = rb_str_new_frozen(val);
14489 }
14490 return argf;
14491}
14492
14493static void
14494opt_i_set(VALUE val, ID id, VALUE *var)
14495{
14496 argf_inplace_mode_set(*var, val);
14497}
14498
14499void
14500ruby_set_inplace_mode(const char *suffix)
14501{
14502 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14503}
14504
14505/*
14506 * call-seq:
14507 * ARGF.argv -> ARGV
14508 *
14509 * Returns the +ARGV+ array, which contains the arguments passed to your
14510 * script, one per element.
14511 *
14512 * For example:
14513 *
14514 * $ ruby argf.rb -v glark.txt
14515 *
14516 * ARGF.argv #=> ["-v", "glark.txt"]
14517 *
14518 */
14519static VALUE
14520argf_argv(VALUE argf)
14521{
14522 return ARGF.argv;
14523}
14524
14525static VALUE
14526argf_argv_getter(ID id, VALUE *var)
14527{
14528 return argf_argv(*var);
14529}
14530
14531VALUE
14533{
14534 return ARGF.argv;
14535}
14536
14537/*
14538 * call-seq:
14539 * ARGF.to_write_io -> io
14540 *
14541 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14542 * enabled.
14543 */
14544static VALUE
14545argf_write_io(VALUE argf)
14546{
14547 if (!RTEST(ARGF.current_file)) {
14548 rb_raise(rb_eIOError, "not opened for writing");
14549 }
14550 return GetWriteIO(ARGF.current_file);
14551}
14552
14553/*
14554 * call-seq:
14555 * ARGF.write(string) -> integer
14556 *
14557 * Writes _string_ if inplace mode.
14558 */
14559static VALUE
14560argf_write(VALUE argf, VALUE str)
14561{
14562 return rb_io_write(argf_write_io(argf), str);
14563}
14564
14565void
14566rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14567{
14568 rb_readwrite_syserr_fail(waiting, errno, mesg);
14569}
14570
14571void
14572rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14573{
14574 VALUE arg, c = Qnil;
14575 arg = mesg ? rb_str_new2(mesg) : Qnil;
14576 switch (waiting) {
14577 case RB_IO_WAIT_WRITABLE:
14578 switch (n) {
14579 case EAGAIN:
14580 c = rb_eEAGAINWaitWritable;
14581 break;
14582#if EAGAIN != EWOULDBLOCK
14583 case EWOULDBLOCK:
14584 c = rb_eEWOULDBLOCKWaitWritable;
14585 break;
14586#endif
14587 case EINPROGRESS:
14588 c = rb_eEINPROGRESSWaitWritable;
14589 break;
14590 default:
14592 }
14593 break;
14594 case RB_IO_WAIT_READABLE:
14595 switch (n) {
14596 case EAGAIN:
14597 c = rb_eEAGAINWaitReadable;
14598 break;
14599#if EAGAIN != EWOULDBLOCK
14600 case EWOULDBLOCK:
14601 c = rb_eEWOULDBLOCKWaitReadable;
14602 break;
14603#endif
14604 case EINPROGRESS:
14605 c = rb_eEINPROGRESSWaitReadable;
14606 break;
14607 default:
14609 }
14610 break;
14611 default:
14612 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14613 }
14615}
14616
14617static VALUE
14618get_LAST_READ_LINE(ID _x, VALUE *_y)
14619{
14620 return rb_lastline_get();
14621}
14622
14623static void
14624set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14625{
14626 rb_lastline_set(val);
14627}
14628
14629/*
14630 * Document-class: IOError
14631 *
14632 * Raised when an IO operation fails.
14633 *
14634 * File.open("/etc/hosts") {|f| f << "example"}
14635 * #=> IOError: not opened for writing
14636 *
14637 * File.open("/etc/hosts") {|f| f.close; f.read }
14638 * #=> IOError: closed stream
14639 *
14640 * Note that some IO failures raise <code>SystemCallError</code>s
14641 * and these are not subclasses of IOError:
14642 *
14643 * File.open("does/not/exist")
14644 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14645 */
14646
14647/*
14648 * Document-class: EOFError
14649 *
14650 * Raised by some IO operations when reaching the end of file. Many IO
14651 * methods exist in two forms,
14652 *
14653 * one that returns +nil+ when the end of file is reached, the other
14654 * raises EOFError.
14655 *
14656 * EOFError is a subclass of IOError.
14657 *
14658 * file = File.open("/etc/hosts")
14659 * file.read
14660 * file.gets #=> nil
14661 * file.readline #=> EOFError: end of file reached
14662 * file.close
14663 */
14664
14665/*
14666 * Document-class: ARGF
14667 *
14668 * ARGF is a stream designed for use in scripts that process files given as
14669 * command-line arguments or passed in via STDIN.
14670 *
14671 * The arguments passed to your script are stored in the +ARGV+ Array, one
14672 * argument per element. ARGF assumes that any arguments that aren't
14673 * filenames have been removed from +ARGV+. For example:
14674 *
14675 * $ ruby argf.rb --verbose file1 file2
14676 *
14677 * ARGV #=> ["--verbose", "file1", "file2"]
14678 * option = ARGV.shift #=> "--verbose"
14679 * ARGV #=> ["file1", "file2"]
14680 *
14681 * You can now use ARGF to work with a concatenation of each of these named
14682 * files. For instance, ARGF.read will return the contents of _file1_
14683 * followed by the contents of _file2_.
14684 *
14685 * After a file in +ARGV+ has been read ARGF removes it from the Array.
14686 * Thus, after all files have been read +ARGV+ will be empty.
14687 *
14688 * You can manipulate +ARGV+ yourself to control what ARGF operates on. If
14689 * you remove a file from +ARGV+, it is ignored by ARGF; if you add files to
14690 * +ARGV+, they are treated as if they were named on the command line. For
14691 * example:
14692 *
14693 * ARGV.replace ["file1"]
14694 * ARGF.readlines # Returns the contents of file1 as an Array
14695 * ARGV #=> []
14696 * ARGV.replace ["file2", "file3"]
14697 * ARGF.read # Returns the contents of file2 and file3
14698 *
14699 * If +ARGV+ is empty, ARGF acts as if it contained STDIN, i.e. the data
14700 * piped to your script. For example:
14701 *
14702 * $ echo "glark" | ruby -e 'p ARGF.read'
14703 * "glark\n"
14704 */
14705
14706/*
14707 * An instance of class \IO (commonly called a _stream_)
14708 * represents an input/output stream in the underlying operating system.
14709 * \Class \IO is the basis for input and output in Ruby.
14710 *
14711 * \Class File is the only class in the Ruby core that is a subclass of \IO.
14712 * Some classes in the Ruby standard library are also subclasses of \IO;
14713 * these include TCPSocket and UDPSocket.
14714 *
14715 * The global constant ARGF (also accessible as <tt>$<</tt>)
14716 * provides an IO-like stream that allows access to all file paths
14717 * found in ARGV (or found in STDIN if ARGV is empty).
14718 * ARGF is not itself a subclass of \IO.
14719 *
14720 * \Class StringIO provides an IO-like stream that handles a String.
14721 * \StringIO is not itself a subclass of \IO.
14722 *
14723 * Important objects based on \IO include:
14724 *
14725 * - $stdin.
14726 * - $stdout.
14727 * - $stderr.
14728 * - Instances of class File.
14729 *
14730 * An instance of \IO may be created using:
14731 *
14732 * - IO.new: returns a new \IO object for the given integer file descriptor.
14733 * - IO.open: passes a new \IO object to the given block.
14734 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
14735 * of a newly-launched subprocess.
14736 * - Kernel#open: Returns a new \IO object connected to a given source:
14737 * stream, file, or subprocess.
14738 *
14739 * Like a \File stream, an \IO stream has:
14740 *
14741 * - A read/write mode, which may be read-only, write-only, or read/write;
14742 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
14743 * - A data mode, which may be text-only or binary;
14744 * see {Data Mode}[rdoc-ref:File@Data+Mode].
14745 * - Internal and external encodings;
14746 * see {Encodings}[rdoc-ref:File@Encodings].
14747 *
14748 * And like other \IO streams, it has:
14749 *
14750 * - A position, which determines where in the stream the next
14751 * read or write is to occur;
14752 * see {Position}[rdoc-ref:IO@Position].
14753 * - A line number, which is a special, line-oriented, "position"
14754 * (different from the position mentioned above);
14755 * see {Line Number}[rdoc-ref:IO@Line+Number].
14756 *
14757 * == Extension <tt>io/console</tt>
14758 *
14759 * Extension <tt>io/console</tt> provides numerous methods
14760 * for interacting with the console;
14761 * requiring it adds numerous methods to class \IO.
14762 *
14763 * == Example Files
14764 *
14765 * Many examples here use these variables:
14766 *
14767 * :include: doc/examples/files.rdoc
14768 *
14769 * == Open Options
14770 *
14771 * A number of \IO methods accept optional keyword arguments
14772 * that determine how a new stream is to be opened:
14773 *
14774 * - +:mode+: Stream mode.
14775 * - +:flags+: \Integer file open flags;
14776 * If +mode+ is also given, the two are bitwise-ORed.
14777 * - +:external_encoding+: External encoding for the stream.
14778 * - +:internal_encoding+: Internal encoding for the stream.
14779 * <tt>'-'</tt> is a synonym for the default internal encoding.
14780 * If the value is +nil+ no conversion occurs.
14781 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
14782 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
14783 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
14784 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
14785 * when the stream closes; otherwise it remains open.
14786 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
14787 * #path method.
14788 *
14789 * Also available are the options offered in String#encode,
14790 * which may control conversion between external internal encoding.
14791 *
14792 * == Basic \IO
14793 *
14794 * You can perform basic stream \IO with these methods,
14795 * which typically operate on multi-byte strings:
14796 *
14797 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
14798 * - IO#write: Writes zero or more strings to the stream;
14799 * each given object that is not already a string is converted via +to_s+.
14800 *
14801 * === Position
14802 *
14803 * An \IO stream has a nonnegative integer _position_,
14804 * which is the byte offset at which the next read or write is to occur.
14805 * A new stream has position zero (and line number zero);
14806 * method +rewind+ resets the position (and line number) to zero.
14807 *
14808 * The relevant methods:
14809 *
14810 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
14811 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
14812 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
14813 * relative to a given position +whence+
14814 * (indicating the beginning, end, or current position).
14815 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
14816 *
14817 * === Open and Closed Streams
14818 *
14819 * A new \IO stream may be open for reading, open for writing, or both.
14820 *
14821 * A stream is automatically closed when claimed by the garbage collector.
14822 *
14823 * Attempted reading or writing on a closed stream raises an exception.
14824 *
14825 * The relevant methods:
14826 *
14827 * - IO#close: Closes the stream for both reading and writing.
14828 * - IO#close_read: Closes the stream for reading.
14829 * - IO#close_write: Closes the stream for writing.
14830 * - IO#closed?: Returns whether the stream is closed.
14831 *
14832 * === End-of-Stream
14833 *
14834 * You can query whether a stream is positioned at its end:
14835 *
14836 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
14837 *
14838 * You can reposition to end-of-stream by using method IO#seek:
14839 *
14840 * f = File.new('t.txt')
14841 * f.eof? # => false
14842 * f.seek(0, :END)
14843 * f.eof? # => true
14844 * f.close
14845 *
14846 * Or by reading all stream content (which is slower than using IO#seek):
14847 *
14848 * f.rewind
14849 * f.eof? # => false
14850 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14851 * f.eof? # => true
14852 *
14853 * == Line \IO
14854 *
14855 * You can read an \IO stream line-by-line using these methods:
14856 *
14857 * - IO#each_line: Reads each remaining line, passing it to the given block.
14858 * - IO#gets: Returns the next line.
14859 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
14860 * - IO#readlines: Returns all remaining lines in an array.
14861 *
14862 * Each of these reader methods accepts:
14863 *
14864 * - An optional line separator, +sep+;
14865 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
14866 * - An optional line-size limit, +limit+;
14867 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
14868 *
14869 * For each of these reader methods, reading may begin mid-line,
14870 * depending on the stream's position;
14871 * see {Position}[rdoc-ref:IO@Position]:
14872 *
14873 * f = File.new('t.txt')
14874 * f.pos = 27
14875 * f.each_line {|line| p line }
14876 * f.close
14877 *
14878 * Output:
14879 *
14880 * "rth line\n"
14881 * "Fifth line\n"
14882 *
14883 * You can write to an \IO stream line-by-line using this method:
14884 *
14885 * - IO#puts: Writes objects to the stream.
14886 *
14887 * === Line Separator
14888 *
14889 * Each of these methods uses a <i>line separator</i>,
14890 * which is the string that delimits lines:
14891 *
14892 * - IO.foreach.
14893 * - IO.readlines.
14894 * - IO#each_line.
14895 * - IO#gets.
14896 * - IO#readline.
14897 * - IO#readlines.
14898 *
14899 * The default line separator is the given by the global variable <tt>$/</tt>,
14900 * whose value is by default <tt>"\n"</tt>.
14901 * The line to be read next is all data from the current position
14902 * to the next line separator:
14903 *
14904 * f = File.new('t.txt')
14905 * f.gets # => "First line\n"
14906 * f.gets # => "Second line\n"
14907 * f.gets # => "\n"
14908 * f.gets # => "Fourth line\n"
14909 * f.gets # => "Fifth line\n"
14910 * f.close
14911 *
14912 * You can specify a different line separator:
14913 *
14914 * f = File.new('t.txt')
14915 * f.gets('l') # => "First l"
14916 * f.gets('li') # => "ine\nSecond li"
14917 * f.gets('lin') # => "ne\n\nFourth lin"
14918 * f.gets # => "e\n"
14919 * f.close
14920 *
14921 * There are two special line separators:
14922 *
14923 * - +nil+: The entire stream is read into a single string:
14924 *
14925 * f = File.new('t.txt')
14926 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14927 * f.close
14928 *
14929 * - <tt>''</tt> (the empty string): The next "paragraph" is read
14930 * (paragraphs being separated by two consecutive line separators):
14931 *
14932 * f = File.new('t.txt')
14933 * f.gets('') # => "First line\nSecond line\n\n"
14934 * f.gets('') # => "Fourth line\nFifth line\n"
14935 * f.close
14936 *
14937 * === Line Limit
14938 *
14939 * Each of these methods uses a <i>line limit</i>,
14940 * which specifies that the number of bytes returned may not be (much) longer
14941 * than the given +limit+;
14942 *
14943 * - IO.foreach.
14944 * - IO.readlines.
14945 * - IO#each_line.
14946 * - IO#gets.
14947 * - IO#readline.
14948 * - IO#readlines.
14949 *
14950 * A multi-byte character will not be split, and so a line may be slightly longer
14951 * than the given limit.
14952 *
14953 * If +limit+ is not given, the line is determined only by +sep+.
14954 *
14955 * # Text with 1-byte characters.
14956 * File.open('t.txt') {|f| f.gets(1) } # => "F"
14957 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
14958 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
14959 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
14960 * # No more than one line.
14961 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
14962 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
14963 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
14964 *
14965 * # Text with 2-byte characters, which will not be split.
14966 * File.open('t.rus') {|f| f.gets(1).size } # => 1
14967 * File.open('t.rus') {|f| f.gets(2).size } # => 1
14968 * File.open('t.rus') {|f| f.gets(3).size } # => 2
14969 * File.open('t.rus') {|f| f.gets(4).size } # => 2
14970 *
14971 * === Line Separator and Line Limit
14972 *
14973 * With arguments +sep+ and +limit+ given,
14974 * combines the two behaviors:
14975 *
14976 * - Returns the next line as determined by line separator +sep+.
14977 * - But returns no more bytes than are allowed by the limit.
14978 *
14979 * Example:
14980 *
14981 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
14982 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
14983 *
14984 * === Line Number
14985 *
14986 * A readable \IO stream has a non-negative integer <i>line number</i>.
14987 *
14988 * The relevant methods:
14989 *
14990 * - IO#lineno: Returns the line number.
14991 * - IO#lineno=: Resets and returns the line number.
14992 *
14993 * Unless modified by a call to method IO#lineno=,
14994 * the line number is the number of lines read
14995 * by certain line-oriented methods,
14996 * according to the given line separator +sep+:
14997 *
14998 * - IO.foreach: Increments the line number on each call to the block.
14999 * - IO#each_line: Increments the line number on each call to the block.
15000 * - IO#gets: Increments the line number.
15001 * - IO#readline: Increments the line number.
15002 * - IO#readlines: Increments the line number for each line read.
15003 *
15004 * A new stream is initially has line number zero (and position zero);
15005 * method +rewind+ resets the line number (and position) to zero:
15006 *
15007 * f = File.new('t.txt')
15008 * f.lineno # => 0
15009 * f.gets # => "First line\n"
15010 * f.lineno # => 1
15011 * f.rewind
15012 * f.lineno # => 0
15013 * f.close
15014 *
15015 * Reading lines from a stream usually changes its line number:
15016 *
15017 * f = File.new('t.txt', 'r')
15018 * f.lineno # => 0
15019 * f.readline # => "This is line one.\n"
15020 * f.lineno # => 1
15021 * f.readline # => "This is the second line.\n"
15022 * f.lineno # => 2
15023 * f.readline # => "Here's the third line.\n"
15024 * f.lineno # => 3
15025 * f.eof? # => true
15026 * f.close
15027 *
15028 * Iterating over lines in a stream usually changes its line number:
15029 *
15030 * File.open('t.txt') do |f|
15031 * f.each_line do |line|
15032 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15033 * end
15034 * end
15035 *
15036 * Output:
15037 *
15038 * "position=11 eof?=false lineno=1"
15039 * "position=23 eof?=false lineno=2"
15040 * "position=24 eof?=false lineno=3"
15041 * "position=36 eof?=false lineno=4"
15042 * "position=47 eof?=true lineno=5"
15043 *
15044 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15045 * the line number does not affect where the next read or write will occur:
15046 *
15047 * f = File.new('t.txt')
15048 * f.lineno = 1000
15049 * f.lineno # => 1000
15050 * f.gets # => "First line\n"
15051 * f.lineno # => 1001
15052 * f.close
15053 *
15054 * Associated with the line number is the global variable <tt>$.</tt>:
15055 *
15056 * - When a stream is opened, <tt>$.</tt> is not set;
15057 * its value is left over from previous activity in the process:
15058 *
15059 * $. = 41
15060 * f = File.new('t.txt')
15061 * $. = 41
15062 * # => 41
15063 * f.close
15064 *
15065 * - When a stream is read, <tt>#.</tt> is set to the line number for that stream:
15066 *
15067 * f0 = File.new('t.txt')
15068 * f1 = File.new('t.dat')
15069 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15070 * $. # => 5
15071 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15072 * $. # => 1
15073 * f0.close
15074 * f1.close
15075 *
15076 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15077 *
15078 * f = File.new('t.txt')
15079 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15080 * $. # => 5
15081 * f.rewind
15082 * f.seek(0, :SET)
15083 * $. # => 5
15084 * f.close
15085 *
15086 * == Character \IO
15087 *
15088 * You can process an \IO stream character-by-character using these methods:
15089 *
15090 * - IO#getc: Reads and returns the next character from the stream.
15091 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15092 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15093 * - IO#putc: Writes a character to the stream.
15094 * - IO#each_char: Reads each remaining character in the stream,
15095 * passing the character to the given block.
15096 * == Byte \IO
15097 *
15098 * You can process an \IO stream byte-by-byte using these methods:
15099 *
15100 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15101 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15102 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15103 * - IO#each_byte: Reads each remaining byte in the stream,
15104 * passing the byte to the given block.
15105 *
15106 * == Codepoint \IO
15107 *
15108 * You can process an \IO stream codepoint-by-codepoint:
15109 *
15110 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15111 *
15112 * == What's Here
15113 *
15114 * First, what's elsewhere. \Class \IO:
15115 *
15116 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15117 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15118 * which provides dozens of additional methods.
15119 *
15120 * Here, class \IO provides methods that are useful for:
15121 *
15122 * - {Creating}[rdoc-ref:IO@Creating]
15123 * - {Reading}[rdoc-ref:IO@Reading]
15124 * - {Writing}[rdoc-ref:IO@Writing]
15125 * - {Positioning}[rdoc-ref:IO@Positioning]
15126 * - {Iterating}[rdoc-ref:IO@Iterating]
15127 * - {Settings}[rdoc-ref:IO@Settings]
15128 * - {Querying}[rdoc-ref:IO@Querying]
15129 * - {Buffering}[rdoc-ref:IO@Buffering]
15130 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15131 * - {Other}[rdoc-ref:IO@Other]
15132 *
15133 * === Creating
15134 *
15135 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15136 * integer file descriptor.
15137 * - ::open: Creates a new \IO object.
15138 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15139 * - ::popen: Creates an \IO object to interact with a subprocess.
15140 * - ::select: Selects which given \IO instances are ready for reading,
15141 * writing, or have pending exceptions.
15142 *
15143 * === Reading
15144 *
15145 * - ::binread: Returns a binary string with all or a subset of bytes
15146 * from the given file.
15147 * - ::read: Returns a string with all or a subset of bytes from the given file.
15148 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15149 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15150 * - #getc: Returns the next character read from +self+ as a string.
15151 * - #gets: Returns the line read from +self+.
15152 * - #pread: Returns all or the next _n_ bytes read from +self+,
15153 * not updating the receiver's offset.
15154 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15155 * for a given _n_.
15156 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15157 * in non-block mode.
15158 * - #readbyte: Returns the next byte read from +self+;
15159 * same as #getbyte, but raises an exception on end-of-stream.
15160 * - #readchar: Returns the next character read from +self+;
15161 * same as #getc, but raises an exception on end-of-stream.
15162 * - #readline: Returns the next line read from +self+;
15163 * same as #getline, but raises an exception of end-of-stream.
15164 * - #readlines: Returns an array of all lines read read from +self+.
15165 * - #readpartial: Returns up to the given number of bytes from +self+.
15166 *
15167 * === Writing
15168 *
15169 * - ::binwrite: Writes the given string to the file at the given filepath,
15170 * in binary mode.
15171 * - ::write: Writes the given string to +self+.
15172 * - #<<: Appends the given string to +self+.
15173 * - #print: Prints last read line or given objects to +self+.
15174 * - #printf: Writes to +self+ based on the given format string and objects.
15175 * - #putc: Writes a character to +self+.
15176 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15177 * - #pwrite: Writes the given string at the given offset,
15178 * not updating the receiver's offset.
15179 * - #write: Writes one or more given strings to +self+.
15180 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15181 *
15182 * === Positioning
15183 *
15184 * - #lineno: Returns the current line number in +self+.
15185 * - #lineno=: Sets the line number is +self+.
15186 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15187 * - #pos=: Sets the byte offset in +self+.
15188 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15189 * - #rewind: Positions +self+ to the beginning of input.
15190 * - #seek: Sets the offset for +self+ relative to given position.
15191 *
15192 * === Iterating
15193 *
15194 * - ::foreach: Yields each line of given file to the block.
15195 * - #each (aliased as #each_line): Calls the given block
15196 * with each successive line in +self+.
15197 * - #each_byte: Calls the given block with each successive byte in +self+
15198 * as an integer.
15199 * - #each_char: Calls the given block with each successive character in +self+
15200 * as a string.
15201 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15202 * as an integer.
15203 *
15204 * === Settings
15205 *
15206 * - #autoclose=: Sets whether +self+ auto-closes.
15207 * - #binmode: Sets +self+ to binary mode.
15208 * - #close: Closes +self+.
15209 * - #close_on_exec=: Sets the close-on-exec flag.
15210 * - #close_read: Closes +self+ for reading.
15211 * - #close_write: Closes +self+ for writing.
15212 * - #set_encoding: Sets the encoding for +self+.
15213 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15214 * Unicode byte-order-mark.
15215 * - #sync=: Sets the sync-mode to the given value.
15216 *
15217 * === Querying
15218 *
15219 * - #autoclose?: Returns whether +self+ auto-closes.
15220 * - #binmode?: Returns whether +self+ is in binary mode.
15221 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15222 * - #closed?: Returns whether +self+ is closed.
15223 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15224 * - #external_encoding: Returns the external encoding object for +self+.
15225 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15226 * - #internal_encoding: Returns the internal encoding object for +self+.
15227 * - #pid: Returns the process ID of a child process associated with +self+,
15228 * if +self+ was created by ::popen.
15229 * - #stat: Returns the File::Stat object containing status information for +self+.
15230 * - #sync: Returns whether +self+ is in sync-mode.
15231 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15232 *
15233 * === Buffering
15234 *
15235 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15236 * - #flush: Flushes any buffered data within +self+ to the underlying
15237 * operating system.
15238 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15239 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15240 * - #ungetc: Prepends buffer for +self+ with given string.
15241 *
15242 * === Low-Level Access
15243 *
15244 * - ::sysopen: Opens the file given by its path,
15245 * returning the integer file descriptor.
15246 * - #advise: Announces the intention to access data from +self+ in a specific way.
15247 * - #fcntl: Passes a low-level command to the file specified
15248 * by the given file descriptor.
15249 * - #ioctl: Passes a low-level command to the device specified
15250 * by the given file descriptor.
15251 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15252 * - #sysseek: Sets the offset for +self+.
15253 * - #syswrite: Writes the given string to +self+ using a low-level write.
15254 *
15255 * === Other
15256 *
15257 * - ::copy_stream: Copies data from a source to a destination,
15258 * each of which is a filepath or an \IO-like object.
15259 * - ::try_convert: Returns a new \IO object resulting from converting
15260 * the given object.
15261 * - #inspect: Returns the string representation of +self+.
15262 *
15263 */
15264
15265void
15266Init_IO(void)
15267{
15268 VALUE rb_cARGF;
15269#ifdef __CYGWIN__
15270#include <sys/cygwin.h>
15271 static struct __cygwin_perfile pf[] =
15272 {
15273 {"", O_RDONLY | O_BINARY},
15274 {"", O_WRONLY | O_BINARY},
15275 {"", O_RDWR | O_BINARY},
15276 {"", O_APPEND | O_BINARY},
15277 {NULL, 0}
15278 };
15279 cygwin_internal(CW_PERFILE, pf);
15280#endif
15281
15284
15285 id_write = rb_intern_const("write");
15286 id_read = rb_intern_const("read");
15287 id_getc = rb_intern_const("getc");
15288 id_flush = rb_intern_const("flush");
15289 id_readpartial = rb_intern_const("readpartial");
15290 id_set_encoding = rb_intern_const("set_encoding");
15291 id_fileno = rb_intern_const("fileno");
15292
15293 rb_define_global_function("syscall", rb_f_syscall, -1);
15294
15295 rb_define_global_function("open", rb_f_open, -1);
15296 rb_define_global_function("printf", rb_f_printf, -1);
15297 rb_define_global_function("print", rb_f_print, -1);
15298 rb_define_global_function("putc", rb_f_putc, 1);
15299 rb_define_global_function("puts", rb_f_puts, -1);
15300 rb_define_global_function("gets", rb_f_gets, -1);
15301 rb_define_global_function("readline", rb_f_readline, -1);
15302 rb_define_global_function("select", rb_f_select, -1);
15303
15304 rb_define_global_function("readlines", rb_f_readlines, -1);
15305
15306 rb_define_global_function("`", rb_f_backquote, 1);
15307
15308 rb_define_global_function("p", rb_f_p, -1);
15309 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15310
15311 rb_cIO = rb_define_class("IO", rb_cObject);
15313
15315
15319
15320 /* exception to wait for reading. see IO.select. */
15322 /* exception to wait for writing. see IO.select. */
15324 /* exception to wait for reading by EAGAIN. see IO.select. */
15325 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15326 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15327 /* exception to wait for writing by EAGAIN. see IO.select. */
15328 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15329 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15330#if EAGAIN == EWOULDBLOCK
15331 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15332 /* same as IO::EAGAINWaitReadable */
15333 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15334 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15335 /* same as IO::EAGAINWaitWritable */
15336 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15337#else
15338 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15339 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15340 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15341 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15342 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15343 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15344#endif
15345 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15346 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15347 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15348 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15349 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15350 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15351
15352#if 0
15353 /* This is necessary only for forcing rdoc handle File::open */
15354 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15355#endif
15356
15357 rb_define_alloc_func(rb_cIO, io_alloc);
15358 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15359 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15360 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15361 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15362 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15363 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15364 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15365 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15366 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15367 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15368 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15369 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15370 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15371 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15372 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15373
15374 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15375
15376 rb_output_fs = Qnil;
15377 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15378
15379 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15380 rb_gc_register_mark_object(rb_default_rs);
15381 rb_rs = rb_default_rs;
15383 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15384 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15385 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15386
15387 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15388 rb_gvar_ractor_local("$_");
15389
15390 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15391 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15392
15393 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15394 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15395 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15396 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15397
15398 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15399 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15400 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15401 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15402 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15403
15404 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15405 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15406
15407 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15408 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15409
15410 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15411 rb_define_alias(rb_cIO, "to_i", "fileno");
15412 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15413
15414 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15415 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15416
15417 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15418 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15419 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15420 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15421
15422 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15423 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15424
15425 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15426
15427 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15428 rb_define_method(rb_cIO, "read", io_read, -1);
15429 rb_define_method(rb_cIO, "write", io_write_m, -1);
15430 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15431 rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
15432 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15433 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15434 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15435 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15436 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15437 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15439 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15440 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15441 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15442 /* Set I/O position from the beginning */
15443 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15444 /* Set I/O position from the current position */
15445 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15446 /* Set I/O position from the end */
15447 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15448#ifdef SEEK_DATA
15449 /* Set I/O position to the next location containing data */
15450 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15451#endif
15452#ifdef SEEK_HOLE
15453 /* Set I/O position to the next hole */
15454 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15455#endif
15456 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15457 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15458 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15459 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15460 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15461
15462 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15463 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15464
15465 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15466 rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
15467 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15468 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15469
15470 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15471 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15472 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15473 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15474 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15475 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15476
15477 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15478 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15479 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15480
15481 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15482 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15483
15484 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15485
15486 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15487 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15488 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15489 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15490
15491 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15492 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15493
15494 rb_define_method(rb_cIO, "wait", io_wait, -1);
15495
15496 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15497 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15498 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15499
15500 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15501 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15502 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15503 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15504
15505 rb_gvar_ractor_local("$stdin");
15506 rb_gvar_ractor_local("$stdout");
15507 rb_gvar_ractor_local("$>");
15508 rb_gvar_ractor_local("$stderr");
15509
15510 rb_stdin = rb_io_prep_stdin();
15511 rb_stdout = rb_io_prep_stdout();
15512 rb_stderr = rb_io_prep_stderr();
15513
15517
15518 orig_stdout = rb_stdout;
15519 orig_stderr = rb_stderr;
15520
15521 /* Holds the original stdin */
15523 /* Holds the original stdout */
15525 /* Holds the original stderr */
15527
15528#if 0
15529 /* Hack to get rdoc to regard ARGF as a class: */
15530 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15531#endif
15532
15533 rb_cARGF = rb_class_new(rb_cObject);
15534 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15535 rb_define_alloc_func(rb_cARGF, argf_alloc);
15536
15538
15539 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15540 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15541 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15542 rb_define_alias(rb_cARGF, "inspect", "to_s");
15543 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15544
15545 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15546 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15547 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15548 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15549 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15550 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15551 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15552 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15553 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15554
15555 rb_define_method(rb_cARGF, "read", argf_read, -1);
15556 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15557 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15558 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15559 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15560 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15561 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15562 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15563 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15564 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15565 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15566 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15567 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15568 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15569 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15570 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15571 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15572 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15573 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15574 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15575
15576 rb_define_method(rb_cARGF, "write", argf_write, 1);
15577 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15578 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15579 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15580 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15581
15582 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15583 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15584 rb_define_method(rb_cARGF, "file", argf_file, 0);
15585 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15586 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15587 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15588
15589 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15590 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15591
15592 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15593 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15594
15595 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15596 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15597 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15598
15599 argf = rb_class_new_instance(0, 0, rb_cARGF);
15600
15602 /*
15603 * ARGF is a stream designed for use in scripts that process files given
15604 * as command-line arguments or passed in via STDIN.
15605 *
15606 * See ARGF (the class) for more details.
15607 */
15609
15610 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15611 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15612 ARGF.filename = rb_str_new2("-");
15613
15614 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15615 rb_gvar_ractor_local("$-i");
15616
15617 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15618
15619#if defined (_WIN32) || defined(__CYGWIN__)
15620 atexit(pipe_atexit);
15621#endif
15622
15623 Init_File();
15624
15625 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15626
15627 sym_mode = ID2SYM(rb_intern_const("mode"));
15628 sym_perm = ID2SYM(rb_intern_const("perm"));
15629 sym_flags = ID2SYM(rb_intern_const("flags"));
15630 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15631 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15632 sym_encoding = ID2SYM(rb_id_encoding());
15633 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15634 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15635 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15636 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15637 sym_normal = ID2SYM(rb_intern_const("normal"));
15638 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15639 sym_random = ID2SYM(rb_intern_const("random"));
15640 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15641 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15642 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15643 sym_SET = ID2SYM(rb_intern_const("SET"));
15644 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15645 sym_END = ID2SYM(rb_intern_const("END"));
15646#ifdef SEEK_DATA
15647 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15648#endif
15649#ifdef SEEK_HOLE
15650 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15651#endif
15652 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15653 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15654}
15655
15656#include "io.rbinc"
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:133
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1125
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:923
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:325
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:955
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1057
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2284
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:2587
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:2574
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:868
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2363
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:107
#define NEWOBJ_OF
Old name of RB_NEWOBJ_OF.
Definition newobj.h:61
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
Definition fl_type.h:58
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:394
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:143
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:396
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:653
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:110
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:536
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:108
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:393
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:533
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:534
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:535
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:532
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:139
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:651
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1677
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:400
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3193
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports always regardless of runtime -W flag.
Definition error.c:421
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition error.c:3150
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:453
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1101
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:688
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3262
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition error.c:794
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
Definition error.c:3274
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:14572
VALUE rb_eIOError
IOError exception.
Definition io.c:182
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1088
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3350
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:3268
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:459
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1091
VALUE rb_eEOFError
EOFError exception.
Definition io.c:181
void rb_fatal(const char *fmt,...)
Raises the unsung "fatal" exception.
Definition error.c:3201
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14566
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:1907
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:57
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1089
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
Definition error.c:411
VALUE rb_eArgError
ArgumentError exception.
Definition error.c:1092
void rb_sys_fail_str(VALUE mesg)
Identical to rb_sys_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3280
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1111
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:51
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3032
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:589
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:1939
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:1980
VALUE rb_cIO
IO class.
Definition io.c:180
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
Definition object.c:1968
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:194
VALUE rb_stderr
STDERR constant.
Definition io.c:194
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:190
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:487
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:600
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:184
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:185
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1182
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
Definition object.c:3013
VALUE rb_cFile
File class.
Definition file.c:176
VALUE rb_stdout
STDOUT constant.
Definition io.c:194
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3026
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
Definition encoding.h:433
static char * rb_enc_left_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the left boundary of a character.
Definition encoding.h:699
static bool rb_enc_asciicompat(rb_encoding *enc)
Queries if the passed encoding is in some sense compatible with ASCII.
Definition encoding.h:784
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:587
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:448
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3747
VALUE rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it additionally takes an encoding.
Definition string.c:981
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:719
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2579
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2076
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1453
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1749
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1793
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1910
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2630
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:1975
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2884
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4245
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4251
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1709
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1760
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1102
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:1069
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:239
#define rb_check_frozen
Just another name of rb_check_frozen.
Definition error.h:264
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
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8540
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4215
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:409
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8666
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2311
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9091
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:5080
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:4986
VALUE rb_io_puts(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8898
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:356
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
Definition io.c:9199
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:230
VALUE rb_io_write(VALUE io, VALUE str)
Writes the given string to the given IO.
Definition io.c:2263
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:310
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:199
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2662
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:9071
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
Definition io.c:280
VALUE rb_io_flush(VALUE io)
Flushes any buffered data within the passed IO to the underlying operating system.
Definition io.c:2367
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6277
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6231
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5144
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7282
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10261
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:443
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
Definition io.c:7165
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:349
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7172
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5667
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:200
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:1680
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1674
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
Definition proc.c:2901
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1434
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:686
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3353
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1532
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:871
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1382
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1834
void rb_str_modify(VALUE str)
Declares that the string is about to be modified.
Definition string.c:2437
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3177
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3020
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
Definition string.c:3295
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2640
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:2921
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3003
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3064
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2445
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1532
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1682
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1441
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
Definition io.c:1566
#define RUBY_UBF_IO
A special UBF for blocking IO operations.
Definition thread.h:382
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
Definition thread.c:2515
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1424
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:2793
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1560
void rb_thread_schedule(void)
Tries to switch to another thread.
Definition thread.c:1472
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1447
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2847
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
Definition variable.c:1226
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:251
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1606
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:310
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:2805
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:664
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:276
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
Definition symbol.c:796
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
const char * rb_id2name(ID id)
Retrieves the name mapped to the given id.
Definition symbol.c:960
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:3452
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:604
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition variable.c:3440
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:251
int rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6363
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:797
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:843
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:767
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1051
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
Definition io.c:6496
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
Definition io.h:340
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:257
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:362
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:997
#define FMODE_TTY
The IO is a TTY.
Definition io.h:281
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:304
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1006
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:6645
struct rb_io_t rb_io_t
Ruby's IO, metadata and buffers.
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:1554
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:6966
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2865
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:254
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
Definition io.c:9245
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:296
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:385
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:289
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:268
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1613
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:356
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1572
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:183
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:275
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:774
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
Definition io.h:312
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:332
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
Definition io.c:803
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:869
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:1976
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:978
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:318
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:809
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3375
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:6772
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1511
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:820
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1030
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
Definition io.c:1626
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:782
rb_io_event_t
Type of events that an IO can wait.
Definition io.h:81
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:82
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:84
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:83
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1477
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7269
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1416
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
Definition ractor.c:2148
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:2124
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
Definition ractor.c:2184
VALUE rb_ractor_stdout(void)
Queries the standard output of the current Ractor that is calling this function.
Definition ractor.c:2136
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
Definition ractor.c:2172
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
Definition ractor.c:2160
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:1761
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:208
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition sprintf.c:1219
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
Definition sprintf.c:1242
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1391
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1357
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:354
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:378
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:68
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:343
#define RARRAY_AREF(a, i)
Definition rarray.h:583
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:69
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define SafeStringValue(v)
Definition rstring.h:104
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:72
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:528
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:574
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition rstring.h:484
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition rstring.h:498
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:95
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:79
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:489
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14532
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:8974
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:91
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:203
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:246
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:419
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:413
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:70
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:449
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:208
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:425
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *buffer, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:582
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *buffer, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:569
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
Definition thread.c:4186
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:218
Definition win32.h:216
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:190
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
IO buffers.
Definition io.h:104
int len
Length of the buffer.
Definition io.h:104
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:104
int off
Offset inside of ptr.
Definition io.h:104
int capa
Designed capacity of the buffer.
Definition io.h:104
Decomposed encoding flags (e.g.
Definition io.h:116
int ecflags
Flags.
Definition io.h:126
rb_encoding * enc2
External encoding.
Definition io.h:120
VALUE ecopts
Flags as Ruby hash.
Definition io.h:134
rb_encoding * enc
Internal encoding.
Definition io.h:118
Ruby's IO, metadata and buffers.
Definition io.h:138
int fd
file descriptor.
Definition io.h:147
int lineno
number of lines read
Definition io.h:156
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:192
rb_pid_t pid
child's pid (for pipes)
Definition io.h:153
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:165
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:183
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:200
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:144
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:203
VALUE pathv
pathname for file
Definition io.h:159
int mode
mode flags: FMODE_XXXs
Definition io.h:150
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:209
struct rb_io_enc_t encs
Decomposed encoding flags.
Definition io.h:180
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:224
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:189
VALUE self
The IO's Ruby level counterpart.
Definition io.h:141
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:215
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:178
void(* finalize)(struct rb_io_t *, int)
finalize proc
Definition io.h:162
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:229
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:171
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:306
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
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:375